...
 
Commits (1)
......@@ -25,7 +25,7 @@ before_script:
- "forever start app.js"
script:
# Run tests
- "ruby saucelabs.rb"
#- "ruby saucelabs.rb"
deploy:
provider: cloudcontrol
email:
......
......@@ -804,7 +804,7 @@ app.get('/set', forceSSL, ensureAuthenticated, function(req, res){
return set;
});
res.json(_.sortBy(sets, function(set){ return set.name }));
res.json(_.sortBy(sets, function(set){ return set.name }));
});
});
......@@ -2209,4 +2209,4 @@ if(process.env.NODE_ENV === 'production') {
http_server.listen(app.get("port"), function(){
console.log("http_server listening on port " + app.get("port"));
});
});
\ No newline at end of file
......@@ -167,6 +167,7 @@ Cards.on("initialize:after", function() {
console.log("THMcards has started!");
});
/* ROUTING EVENTS */
Cards.on("pool", function(){
Cards.navigate("pool");
......@@ -270,5 +271,4 @@ function FilteredCollection(collection, options){
});
return filtered;
}
}
\ No newline at end of file
......@@ -20,10 +20,28 @@ Cards.module('Entities', function(Entities, App, Backbone){
url: function() {
return "/set/" + this.setId + "/card";
},
constructor: function(models, options){
constructor: function(models, options){
this.setId = options.setId;
Backbone.Collection.apply(this, arguments);
}
},
sort_key: 'front',
direction: 'down',
comparator: function(set) {
if(this.direction == "up"){
var cardside = (this.sort_key == "front") ? set.attributes.front.text : set.attributes.back.text;
return String.fromCharCode.apply(String, _.map(cardside.toLowerCase().split(""), function (c) {
return 0xffff - c.charCodeAt();
}));
} else {
var cardside = (this.sort_key == "front") ? set.attributes.front.text : set.attributes.back.text;
return cardside.toLowerCase();
}
},
sortByField: function(side, direction){
this.sort_key = side;
this.direction = direction;
this.sort();
}
});
Entities.CardMemoCollection = Backbone.Collection.extend({
......
......@@ -5,7 +5,7 @@ Cards.module('Entities', function(Entities, App, Backbone){
Entities.CategoryCollection = Backbone.Collection.extend({
model: Entities.Category,
url: "/set/category",
comparator: function(set) {
comparator: function(set) {
return set.get("name");
}
});
......@@ -18,6 +18,22 @@ Cards.module('Entities', function(Entities, App, Backbone){
constructor: function(models, options){
this.category = options.category;
Backbone.Collection.apply(this, arguments);
}
},
sort_key: 'name',
direction: 'down',
comparator: function(set) {
if(this.direction == "up"){
return String.fromCharCode.apply(String, _.map(set.get(this.sort_key).toLowerCase().split(""), function (c) {
return 0xffff - c.charCodeAt();
}));
} else {
return set.get(this.sort_key).toLowerCase();
}
},
sortByField: function(fieldname, direction){
this.sort_key = fieldname;
this.direction = direction;
this.sort();
}
});
});
\ No newline at end of file
......@@ -2,14 +2,13 @@ Cards.module('Entities', function(Entities, App, Backbone){
Entities.Set = Backbone.Model.extend({
url: function() {
if(this.get("id")) {
if(this.get("id")) {
return "/set/" + this.get("id")
} else {
} else {
return "/set";
}
},
validate: function (attrs) {
console.log(attrs);
var errors = [];
if (!attrs.name) {
errors.push({name: 'name', message: 'Bitte Namen angeben.'});
......@@ -22,15 +21,30 @@ Cards.module('Entities', function(Entities, App, Backbone){
}
return errors.length > 0 ? errors : false;
},
idAttribute: "_id"
idAttribute: "_id"
});
Entities.SetCollection = Backbone.Collection.extend({
Entities.SetCollection = Backbone.Collection.extend({
model: Entities.Set,
url: "/set",
comparator: function(set) {
return set.get("name");
}
url: "/set",
initialize: function() {
},
sort_key: 'name',
direction: 'down',
comparator: function(set) {
if(this.direction == "up"){
return String.fromCharCode.apply(String, _.map(set.get(this.sort_key).toLowerCase().split(""), function (c) {
return 0xffff - c.charCodeAt();
}));
} else {
return set.get(this.sort_key).toLowerCase();
}
},
sortByField: function(fieldname, direction){
this.sort_key = fieldname;
this.direction = direction;
this.sort();
}
});
Entities.SetLearnedCollection = Backbone.Collection.extend({
......
......@@ -25,8 +25,9 @@ Cards.module('Pool', function(Pool, App) {
template: "#pool-category-set-list",
itemView: Pool.CategorySetItemView,
itemViewContainer: "tbody",
initialize: function() {
initialize: function() {
this.collection.fetch();
this.collection.on('sort', this.render, this);
},
onRender: function(){
i18ninit();
......
Cards.module('Pool', function(Pool, App){
Pool.Controller = {
showPoolLayout: function(){
showPoolLayout: function(){
var poolLayout = new Cards.Pool.Layout();
Cards.mainRegion.show(poolLayout);
......@@ -9,15 +9,27 @@ Cards.module('Pool', function(Pool, App){
poolLayout.categoryRegion.show(categoryView);
},
showPoolCategoryLayout: function(name){
showPoolCategoryLayout: function(name, fieldname, direction){
var poolLayout = new Cards.Pool.Layout();
Cards.mainRegion.show(poolLayout);
if(!fieldname){
fieldname = "name";
}
if(!direction){
direction = "down";
}
var categorySetCollection = new Cards.Entities.CategorySetCollection([], {category: name});
var categorySetCollection = new Cards.Entities.CategorySetCollection([], {category: name});
categorySetCollection.sortByField(fieldname, direction);
var categorySetView = new Cards.Pool.CategorySetView({ collection: categorySetCollection });
poolLayout.categoryRegion.show(categorySetView);
poolLayout.categoryRegion.show(categorySetView);
},
sortPoolCategoryLayout: function(fieldname, direction){
this.showPoolCategoryLayout(window.location.hash.split("/").pop(), fieldname, direction);
},
onRender: function(){
i18ninit();
}
......
Cards.module('Set', function(Set, App){
Set.Controller = {
showListLayout: function(){
showListLayout: function(fieldname, direction){
var setLayout = new Cards.Set.List.Layout();
Cards.mainRegion.show(setLayout);
var sets = new Cards.Entities.SetCollection();
var listView = new Cards.Set.List.ListView({ collection: sets });
setLayout.listRegion.show(listView);
if(!fieldname){
fieldname = "name";
}
if(!direction){
direction = "down";
}
var sets = new Cards.Entities.SetCollection();
sets.sortByField(fieldname, direction);
var listView = new Cards.Set.List.ListView({ collection: sets });
setLayout.listRegion.show(listView);
var sideBarView = new Cards.Set.List.SideBar.SideBarView({ collection: sets });
setLayout.sideBarRegion.show(sideBarView);
},
showDetailsLayout: function(id){
var set = new Cards.Entities.Set({id: id});
showDetailsLayout: function(id){
var set = new Cards.Entities.Set({id: id});
set.fetch({
success: function(){
var detailsLayout = new Cards.Set.Details.Layout();
......@@ -51,16 +60,23 @@ Cards.module('Set', function(Set, App){
}
});
},
showDetailsListLayout: function(id){
showDetailsListLayout: function(id, side, direction){
var set = new Cards.Entities.Set({id: id});
set.fetch({
success: function(){
var detailsLayout = new Cards.Set.Details.Layout();
Cards.mainRegion.show(detailsLayout);
var cardCollection = new Cards.Entities.CardCollection([], { setId: set.get("id") });
if(!side){
side = "front";
}
if(!direction){
direction = "down";
}
var cardCollection = new Cards.Entities.CardCollection([], { setId: set.get("id") });
cardCollection.sortByField(side, direction);
cardCollection.fetch({
success: function(){
var detailsListView = new Cards.Set.Details.DetailsListView({ collection: cardCollection, model: set });
......@@ -91,6 +107,9 @@ Cards.module('Set', function(Set, App){
}
});
},
sortSetDetailsLayout: function(side, direction){
this.showDetailsListLayout(window.location.hash.split("/").pop(), side, direction);
},
showLearnLayout: function(id){
var set = new Cards.Entities.Set({id: id});
set.fetch({
......@@ -226,7 +245,6 @@ Cards.module('Set', function(Set, App){
function FilteredCollection(collection, options){
var filtered = new collection.constructor(collection.models, options);
filtered.filter = function(criteria){
var items;
if (criteria){
......@@ -261,6 +279,5 @@ function FilteredCollection(collection, options){
collection.on("reset", function(){
filtered.reset(collection.models);
});
return filtered;
}
......@@ -2,6 +2,8 @@ Cards.module('Set.Details', function(Details, App) {
Details.ItemView = Backbone.Marionette.ItemView.extend({
template: "#set-details-item",
className: "item",
initialize: function() {
},
events: {
"click a": "linkClicked",
"click div.box": "cardClicked"
......@@ -47,6 +49,12 @@ Cards.module('Set.Details', function(Details, App) {
ui: {
modalView: "#pictureModal"
},
initialize: function() {
$(document).on('keyup', this.keyHandler);
},
remove: function(){
$(document).off('keyup', this.keyHandler);
},
events: {
"click a.carousel-control": "cycleCarousel",
"click button.learn": "learnClicked",
......@@ -55,8 +63,26 @@ Cards.module('Set.Details', function(Details, App) {
"click a.btn-editCard": "editClicked",
"click a.btn-showPictureModal": "showModal",
"click a.btn-deleteCard": "deleteClicked",
"click div.box": "checkForPicture"
"click div.box": "checkForPicture"
},
keyHandler: function(ev){
if(window.location.hash.indexOf("details") != -1){
switch (ev.keyCode) {
//Turn card with ctrl key
case 17 :
$('div.active>div.box').click();
break;
//Go to previous card with arrow left
case 37 :
$('#leftCarouselControl').click();
break;
//Go to next card with arrow right
case 39 :
$('#rightCarouselControl').click();
break;
}
}
},
playMeteor: function(ev) {
App.trigger("play:meteor", this.model.get("id"));
},
......@@ -90,16 +116,15 @@ Cards.module('Set.Details', function(Details, App) {
});
},
cycleCarousel: function(ev) {
ev.preventDefault();
ev.preventDefault();
this.turnCardtoFront(ev);
if($(ev.currentTarget).hasClass("left")) {
this.$el.find(":first-child").carousel("prev");
} else if($(ev.currentTarget).hasClass("right")) {
this.$el.find(":first-child").carousel("next");
}
},
turnCardtoFront: function(ev) {
ev.preventDefault();
......
......@@ -255,7 +255,7 @@ Cards.module("Set.Details.SideBar", function(SideBar, App) {
App.trigger('set:rating', this.model.get("id"));
},
onClose: function(){
console.log("asd");
//console.log("asd");
$(".btn-setDelete").off('clickout');
},
onRender: function(){
......@@ -263,4 +263,4 @@ Cards.module("Set.Details.SideBar", function(SideBar, App) {
this.$(".btn-setDelete").clickout(this.resetDeleteButton);
}
});
});
});
\ No newline at end of file
Cards.module('Set.Learn', function(Learn, App) {
Learn.ItemView = Backbone.Marionette.ItemView.extend({
template: "#set-learn-item",
className: "item",
className: "item",
events: {
"click a": "linkClicked",
"click div.box": "cardClicked"
},
"click div.box": "cardClicked",
},
cardClicked: function(ev) {
ev.preventDefault();
ev.preventDefault();
var front = $(ev.currentTarget).find('div.front');
var back = $(ev.currentTarget).find('div.back');
var answerButtons = $("button.answer");
......@@ -46,6 +45,19 @@ Cards.module('Set.Learn', function(Learn, App) {
ui: {
modalView: "#pictureModalLearn"
},
initialize: function() {
$(document).on('keyup', this.keyHandlerLearn);
var that = this;
App.on('filter:box', function(boxId) {
that.filterBox(boxId);
})
App.on('update:cardcount', function() {
that.updateCardcount();
})
},
remove: function(){
$(document).off('keyup', this.keyHandlerLearn);
},
events: {
"click a.carousel-control": "cycleCarousel",
"click button.card-success": "answeredCard",
......@@ -53,6 +65,28 @@ Cards.module('Set.Learn', function(Learn, App) {
"click a.btn-showPictureModal": "showModal",
"click div.box": "checkForPicture"
},
keyHandlerLearn: function(ev){
if(window.location.hash.indexOf("learn") != -1){
switch (ev.keyCode) {
//Turn card with ctrl key
case 17 :
$('div.active>div.box').click();
break;
//Mark card as known with arrow up
case 38 :
if($('#know').is(':visible')){
$('#know').click();
}
break;
//Mark card as unknown with arrow down
case 40 :
if($('#notknow').is(':visible')){
$('#notknow').click();
}
break;
}
}
},
cycleCarousel: function(ev) {
ev.preventDefault();
......@@ -68,7 +102,7 @@ Cards.module('Set.Learn', function(Learn, App) {
this.showPictureModal();
},
answeredCard: function(ev) {
if (ev.target.title === "success") {
if (ev.target.id === "know") {
var failed = false;
} else {
var failed = true;
......@@ -217,15 +251,7 @@ Cards.module('Set.Learn', function(Learn, App) {
}
});
},
initialize: function() {
var that = this;
App.on('filter:box', function(boxId) {
that.filterBox(boxId);
})
App.on('update:cardcount', function() {
that.updateCardcount();
})
},
filterBox: function(boxId) {
if(boxId != null) {
this.collection.filter(boxId);
......@@ -275,7 +301,7 @@ Cards.module('Set.Learn', function(Learn, App) {
this.ui.modalView.modal('show');
},
checkForPicture: function(ev) {
checkForPicture: function(ev) {
if(this.collection.length !== 0) {
var cardId = $("div.item.active").children(".box").attr("data-id");
var actualCard = this.collection.get(cardId);
......@@ -296,6 +322,8 @@ Cards.module('Set.Learn', function(Learn, App) {
}
},
onRender: function() {
i18ninit();
var that = this;
var cardIndicator = this.$el.find("small.card-indicator");
......@@ -358,4 +386,4 @@ Cards.module('Set.Learn', function(Learn, App) {
onShow: function() {
}
});
});
});
\ No newline at end of file
......@@ -42,14 +42,17 @@ Cards.module('Set.List', function(List, App) {
},
initialize: function() {
var that = this;
this.collection.bind("reset", function(col, opt) {
this.collection.bind("reset", function(col, opt) {
if(!_.isUndefined(opt) && _.has(opt, "learned")) {
that.emptyView = List.SetLearnedEmptyView;
} else {
that.emptyView = List.SetEmptyView;
}
});
this.collection.fetch();
this.collection.on('sort', this.render, this);
},
newSet: function() {
$("button.saveSet").click();
......
......@@ -17,6 +17,9 @@ Cards.module('Set.List', function(List, App) {
"click a": "linkClicked"
},
initialize: function() {
this.collection.on('reset', this.render, this);
this.collection.on('sort', this.render, this);
this.collection.fetch();
},
linkClicked: function(ev){
......
......@@ -31,11 +31,46 @@ Cards.module('Set.Memo', function(Memo, App) {
ui: {
modalView: "#pictureModalMemo"
},
initialize: function() {
$(document).on('keyup', this.keyHandlerMemo);
},
remove: function(){
$(document).off('keyup', this.keyHandlerMemo);
},
events: {
"click button.show-answer": "showAnswer",
"click button.rate-answer": "rateAnswer",
"click a.btn-showPictureModal": "showModal",
"click a.btn-showPictureModal": "showModal"
},
keyHandlerMemo: function(ev){
if(window.location.hash.indexOf("memo") != -1){
switch (ev.keyCode) {
//Turn card with ctrl key
case 17 :
$('button.show-answer').click();
break;
//Rating in Memo Mode (0-5)
case 48 :
$('button#memoRate0').click();
break;
case 49 :
$('button#memoRate1').click();
break;
case 50 :
$('button#memoRate2').click();
break;
case 51 :
$('button#memoRate3').click();
break;
case 52 :
$('button#memoRate4').click();
break;
case 53 :
$('button#memoRate5').click();
break;
}
}
},
cycleCarousel: function(ev) {
this.collection.fetch();
ev.preventDefault();
......@@ -198,9 +233,9 @@ Cards.module('Set.Memo', function(Memo, App) {
}
}
},
initialize: function() {
/*initialize: function() {
},
},*/
onRender: function() {
i18ninit();
......
......@@ -90,9 +90,9 @@
<script type="text/template" id="pool-category-set-list" class="pool">
<thead>
<tr>
<th data-i18n="pool.name"></th>
<th data-i18n="pool.description"></th>
<th data-i18n="pool.created"></th>
<th><span data-i18n="pool.name"></span> <a href="javascript:void(0)" onclick="Cards.Pool.Controller.sortPoolCategoryLayout('name', 'down');">&dArr;</a><a href="javascript:void(0)" onclick="Cards.Pool.Controller.sortPoolCategoryLayout('name', 'up');">&uArr;</a></th>
<th><span data-i18n="pool.description"></span> <a href="javascript:void(0)" onclick="Cards.Pool.Controller.sortPoolCategoryLayout('description', 'down');">&dArr;</a><a href="javascript:void(0)" onclick="Cards.Pool.Controller.sortPoolCategoryLayout('description', 'up');">&uArr;</a></th>
<th><span data-i18n="pool.created"></span> <a href="javascript:void(0)" onclick="Cards.Pool.Controller.sortPoolCategoryLayout('created', 'down');">&dArr;</a><a href="javascript:void(0)" onclick="Cards.Pool.Controller.sortPoolCategoryLayout('created', 'up');">&uArr;</a></th>
</tr>
</thead>
<tbody id="cardSetsPool"></tbody>
......@@ -173,8 +173,8 @@
<div class="listhead">
<thead>
<tr>
<th width="45%" data-i18n="foreside"></th>
<th width="45%" data-i18n="backside"></th>
<th width="45%"><span data-i18n="foreside"></span> <a href="javascript:void(0)" onclick="Cards.Set.Controller.sortSetDetailsLayout('front', 'down');">&dArr;</a><a href="javascript:void(0)" onclick="Cards.Set.Controller.sortSetDetailsLayout('front', 'up');">&uArr;</a></th>
<th width="45%"><span data-i18n="backside"></span> <a href="javascript:void(0)" onclick="Cards.Set.Controller.sortSetDetailsLayout('back', 'down');">&dArr;</a><a href="javascript:void(0)" onclick="Cards.Set.Controller.sortSetDetailsLayout('back', 'up');">&uArr;</a></th>
<th width="10%" data-i18n="options"></th>
</tr>
</thead>
......@@ -644,9 +644,9 @@
<script type="text/template" id="set-list">
<thead class="set-list">
<tr>
<th data-i18n="set-list.name"></th>
<th width="25%" data-i18n="set-list.category"></th>
<th width="40%" data-i18n="set-list.description"></th>
<th><span data-i18n="set-list.name"></span> <a href="javascript:void(0)" onclick="Cards.Set.Controller.showListLayout('name', 'down');">&dArr;</a><a href="javascript:void(0)" onclick="Cards.Set.Controller.showListLayout('name', 'up');">&uArr;</a></th>
<th width="25%"><span data-i18n="set-list.category"></span> <a href="javascript:void(0)" onclick="Cards.Set.Controller.showListLayout('category', 'down');">&dArr;</a><a href="javascript:void(0)" onclick="Cards.Set.Controller.showListLayout('category', 'up');">&uArr;</a></th>
<th width="40%"><span data-i18n="set-list.description"></span> <a href="javascript:void(0)" onclick="Cards.Set.Controller.showListLayout('description', 'down');">&dArr;</a><a href="javascript:void(0)" onclick="Cards.Set.Controller.showListLayout('description', 'up');">&uArr;</a></th>
</tr>
</thead>
<tbody id="cardSetView"></tbody>
......@@ -876,8 +876,8 @@
</div>
<div id="learn-navigation">
<button id="know" class="btn btn-primary answer card-success" title="success" style="width:100%; margin-top:10px; display:none" data-i18n="know"></button>
<button id="notknow" class="btn btn-default answer card-fail" title="failed" style="width:100%; margin-top:10px; display:none" data-i18n="notknow"></button>
<button id="know" class="btn btn-primary answer card-success" style="width:100%; margin-top:10px; display:none" data-i18n="know"></button>
<button id="notknow" class="btn btn-default answer card-fail" style="width:100%; margin-top:10px; display:none" data-i18n="notknow"></button>
</div>
<div class="box learn-endscreen" style="display:none">
......@@ -962,9 +962,9 @@
<div class="btn-group memo-rating">
<button id="memoRate0" class="btn btn-default rate-answer wrong" data-placement="bottom" data-id="0" data-i18n="[title]cardmemo.rate0" title="">0</button>
<button id="memoRate1" class="btn btn-default rate-answer wrong" data-placement="bottom" data-id="1" data-i18n="[title]cardmemo.rate1" title="">1</button>
<button id="memoRate2" class="btn btn-default rate-answer" data-placement="bottom" data-id="2" data-i18n="[title]cardmemo.rate3" title="">2</button>
<button id="memoRate3" class="btn btn-default rate-answer" data-placement="bottom" data-id="3" data-i18n="[title]cardmemo.rate4" title="">3</button>
<button id="memoRate4" class="btn btn-default rate-answer" data-placement="bottom" data-id="4" title="">4</button>
<button id="memoRate2" class="btn btn-default rate-answer" data-placement="bottom" data-id="2" data-i18n="[title]cardmemo.rate2" title="">2</button>
<button id="memoRate3" class="btn btn-default rate-answer" data-placement="bottom" data-id="3" data-i18n="[title]cardmemo.rate3" title="">3</button>
<button id="memoRate4" class="btn btn-default rate-answer" data-placement="bottom" data-id="4" data-i18n="[title]cardmemo.rate4" title="">4</button>
<button id="memoRate5" class="btn btn-default rate-answer" data-placement="bottom" data-id="5" data-i18n="[title]cardmemo.rate5" title="">5</button>
<a id="memetext" class="btn btn-default btn-info memo-helptext" data-placement="bottom" title="Memo" data-i18n="[data-content]cardmemo.memotext" data-content="">
<i class="glyphicon glyphicon-question-sign"></i>
......