Commit 5cd9fd4e92b477fd49d644bdfd0ee23fb5f5eef0

Authored by Andrew Buss
1 parent 062ba87a4c
Exists in master

try to prevent user from submitting blank edit

Showing 3 changed files with 8 additions and 7 deletions Inline Diff

scripts/CardGridController.js View file @ 5cd9fd4
angular.module('flashy.CardGridController', ['ui.router', 'ngAnimate', 'ngWebSocket', 'flashy.DeckFactory']).CardGridController = 1 1 angular.module('flashy.CardGridController', ['ui.router', 'ngAnimate', 'ngWebSocket', 'flashy.DeckFactory']).CardGridController =
function($scope, $rootScope, $state, $http, $window, $timeout, $stateParams, $websocket, $interval, UserService, Flashcard, Deck) { 2 2 function($scope, $rootScope, $state, $http, $window, $timeout, $stateParams, $websocket, $interval, UserService, Flashcard, Deck) {
sectionId = parseInt($stateParams.sectionId); 3 3 sectionId = parseInt($stateParams.sectionId);
4 if (!UserService.isInSection(sectionId)) $state.go('addclass');
$scope.cards = []; // all cards 4 5 $scope.cards = []; // all cards
$scope.cardCols = null; // organized data 5 6 $scope.cardCols = null; // organized data
$scope.affectedCards = []; // cards affected by a position change move 6 7 $scope.affectedCards = []; // cards affected by a position change move
$scope.numCols = 0; 7 8 $scope.numCols = 0;
$scope.height = 0; // height of a card 8 9 $scope.height = 0; // height of a card
$scope.section = $rootScope.SectionResource.get({sectionId: sectionId}); 9 10 $scope.section = $rootScope.SectionResource.get({sectionId: sectionId});
$scope.currentEditingCard = null; 10 11 $scope.currentEditingCard = null;
$scope.deck = new Deck(sectionId, { 11 12 $scope.deck = new Deck(sectionId, {
cardHideCallback: function(card) { 12 13 cardHideCallback: function(card) {
$scope.hideCardFromGrid(card); 13 14 $scope.hideCardFromGrid(card);
if (!card.isReported && !card.isEdited) 14 15 if (!card.isReported && !card.isEdited)
Materialize.toast('Card hidden! If the card was spammy or abusive, you may also ' + 15 16 Materialize.toast('Card hidden! If the card was spammy or abusive, you may also ' +
'<a class="btn-flat cyan-text" onclick="card.report()">report</a>', 4000); 16 17 '<a class="btn-flat cyan-text" onclick="card.report()">report</a>', 4000);
}, 17 18 },
cardPullCallback: $scope.cardPullCallback, 18 19 cardPullCallback: $scope.cardPullCallback,
}); 19 20 });
20 21
$('.edit-modal-trigger').leanModal({ 21 22 $('.edit-modal-trigger').leanModal({
dismissible: true, // Modal can be dismissed by clicking outside of the modal 22 23 dismissible: true, // Modal can be dismissed by clicking outside of the modal
opacity: .5, // Opacity of modal background 23 24 opacity: .5, // Opacity of modal background
in_duration: 300, // Transition in duration 24 25 in_duration: 300, // Transition in duration
out_duration: 200, // Transition out duration 25 26 out_duration: 200, // Transition out duration
ready: function() { 26 27 ready: function() {
console.log('hi'); 27 28 console.log('hi');
$('#edit-card-input').html($scope.currentEditingCard); 28 29 $('#edit-card-input').html($scope.currentEditingCard);
$('#edit-card-input').get(0).focus(); 29 30 $('#edit-card-input').get(0).focus();
}, // Callback for Modal open 30 31 }, // Callback for Modal open
complete: function() { 31 32 complete: function() {
$scope.currentEditingCard = null; 32 33 $scope.currentEditingCard = null;
console.log('EDIT MODAL CLOSED'); 33 34 console.log('EDIT MODAL CLOSED');
34 35
} // Callback for Modal close 35 36 } // Callback for Modal close
}); 36 37 });
37 38
Flashcard.linkDeck($scope.deck); 38 39 Flashcard.linkDeck($scope.deck);
39 40
$scope.moveQueue = []; 40 41 $scope.moveQueue = [];
41 42
$scope.procQueue; 42 43 $scope.procQueue;
$scope.addMove = function(m) { 43 44 $scope.addMove = function(m) {
if (!$scope.moveQueue) return m.go(); 44 45 if (!$scope.moveQueue) return m.go();
$scope.moveQueue.push(m); 45 46 $scope.moveQueue.push(m);
}; 46 47 };
47 48
$scope.showGrid = false; 48 49 $scope.showGrid = false;
//$scope.moveQueue = []; // queue of flashcard objects 49 50 //$scope.moveQueue = []; // queue of flashcard objects
$rootScope.currentSection = $scope.section; 50 51 $rootScope.currentSection = $scope.section;
51 52
$scope.refreshColumnWidth = function() { 52 53 $scope.refreshColumnWidth = function() {
avail = $window.innerWidth - 17; 53 54 avail = $window.innerWidth - 17;
width = Math.floor(avail / Math.floor(avail / 250)); 54 55 width = Math.floor(avail / Math.floor(avail / 250));
$('.cardColumn').css({ 55 56 $('.cardColumn').css({
width: width + 'px' 56 57 width: width + 'px'
}); 57 58 });
$('.cardColumn .card.flashy').css({ 58 59 $('.cardColumn .card.flashy').css({
width: width - 12 + 'px', 59 60 width: width - 12 + 'px',
'font-size': 100 * width / 250 + '%', 60 61 'font-size': 100 * width / 250 + '%',
height: (width * 3 / 5) + 'px' 61 62 height: (width * 3 / 5) + 'px'
}); 62 63 });
/* 63 64 /*
$('.cardColumn .card.flashy i.small').css({ 64 65 $('.cardColumn .card.flashy i.small').css({
'font-size': 200 * width / 250 + '%' 65 66 'font-size': 200 * width / 250 + '%'
}); 66 67 });
$('.cardColumn .card.flashy i.medium').css({ 67 68 $('.cardColumn .card.flashy i.medium').css({
'font-size': 400 * width / 250 + '%' 68 69 'font-size': 400 * width / 250 + '%'
});*/ 69 70 });*/
$scope.height = width * 3 / 5; 70 71 $scope.height = width * 3 / 5;
}; 71 72 };
72 73
$scope.refreshLayout = function() { 73 74 $scope.refreshLayout = function() {
numCols = Math.max(1, Math.floor(($window.innerWidth - 17) / 250)); 74 75 numCols = Math.max(1, Math.floor(($window.innerWidth - 17) / 250));
// check if we actually need to refresh the whole layout 75 76 // check if we actually need to refresh the whole layout
if (numCols == $scope.numCols) return $scope.refreshColumnWidth(); 76 77 if (numCols == $scope.numCols) return $scope.refreshColumnWidth();
$scope.numCols = numCols; 77 78 $scope.numCols = numCols;
console.log('refreshing layout for ' + numCols + ' columns'); 78 79 console.log('refreshing layout for ' + numCols + ' columns');
$scope.cardCols = []; 79 80 $scope.cardCols = [];
var cols = []; 80 81 var cols = [];
for (var i = 0; i < numCols; i++) cols.push([]); 81 82 for (var i = 0; i < numCols; i++) cols.push([]);
var n = 0; 82 83 var n = 0;
$scope.cards.forEach(function(card, j) { 83 84 $scope.cards.forEach(function(card, j) {
card.colNum = n++ % numCols; 84 85 card.colNum = n++ % numCols;
cols[card.colNum].push(card); 85 86 cols[card.colNum].push(card);
}); 86 87 });
for (i in cols) $scope.updateColRanks(cols[i]); 87 88 for (i in cols) $scope.updateColRanks(cols[i]);
$scope.cardCols = cols; 88 89 $scope.cardCols = cols;
return $timeout($scope.refreshColumnWidth); 89 90 return $timeout($scope.refreshColumnWidth);
}; 90 91 };
91 92
angular.element($window).bind('resize', $scope.refreshLayout); 92 93 angular.element($window).bind('resize', $scope.refreshLayout);
93 94
$scope.addCardToGrid = function(card) { 94 95 $scope.addCardToGrid = function(card) {
console.log('adding card to grid', card); 95 96 console.log('adding card to grid', card);
var colNum = 0; 96 97 var colNum = 0;
var lowestCol = $scope.cardCols[0]; 97 98 var lowestCol = $scope.cardCols[0];
var lowestColNum = 0; 98 99 var lowestColNum = 0;
while (colNum < $scope.numCols) { 99 100 while (colNum < $scope.numCols) {
if ($scope.cardCols[colNum].length == 0) { 100 101 if ($scope.cardCols[colNum].length == 0) {
lowestCol = $scope.cardCols[colNum]; 101 102 lowestCol = $scope.cardCols[colNum];
lowestColNum = colNum; 102 103 lowestColNum = colNum;
break; 103 104 break;
} else if ($scope.cardCols[colNum].length < lowestCol.length) { 104 105 } else if ($scope.cardCols[colNum].length < lowestCol.length) {
lowestCol = $scope.cardCols[colNum]; 105 106 lowestCol = $scope.cardCols[colNum];
lowestColNum = colNum; 106 107 lowestColNum = colNum;
lowestColLen = $scope.cardCols[colNum].length; 107 108 lowestColLen = $scope.cardCols[colNum].length;
} 108 109 }
colNum++; 109 110 colNum++;
} 110 111 }
card.colNum = lowestColNum; 111 112 card.colNum = lowestColNum;
$scope.cards.push(card); 112 113 $scope.cards.push(card);
$scope.cardCols[lowestColNum].unshift(card); 113 114 $scope.cardCols[lowestColNum].unshift(card);
114 115
$scope.updateColRanks(lowestCol); 115 116 $scope.updateColRanks(lowestCol);
console.log($scope.cardCols); 116 117 console.log($scope.cardCols);
$timeout($scope.refreshColumnWidth); 117 118 $timeout($scope.refreshColumnWidth);
}; 118 119 };
119 120
$scope.updateColRanks = function(col) { 120 121 $scope.updateColRanks = function(col) {
for (i in col) 121 122 for (i in col)
col[i].colRank = parseInt(i); 122 123 col[i].colRank = parseInt(i);
}; 123 124 };
124 125
$scope.hideCardFromGrid = function(card) { 125 126 $scope.hideCardFromGrid = function(card) {
console.log('hiding', card); 126 127 console.log('hiding', card);
if (typeof card.colNum === 'undefined') return; 127 128 if (typeof card.colNum === 'undefined') return;
$scope.cardCols[card.colNum].splice(card.colRank, 1); 128 129 $scope.cardCols[card.colNum].splice(card.colRank, 1);
card.colNum = undefined; 129 130 card.colNum = undefined;
card.colRank = undefined; 130 131 card.colRank = undefined;
$scope.updateColRanks($scope.cardCols[card.colNum]); 131 132 $scope.updateColRanks($scope.cardCols[card.colNum]);
console.log($scope.cardCols); 132 133 console.log($scope.cardCols);
}; 133 134 };
134 135
$scope.$on('$destroy', function() { 135 136 $scope.$on('$destroy', function() {
$scope.deck.cleanup(); 136 137 $scope.deck.cleanup();
Flashcard.cleanup(); 137 138 Flashcard.cleanup();
$rootScope.currentSection = {}; 138 139 $rootScope.currentSection = {};
$(document).off('keydown'); 139 140 $(document).off('keydown');
}); 140 141 });
141 142
$scope.editCard = function(card) { 142 143 $scope.editCard = function(card) {
$scope.currentEditingCard = card; 143 144 $scope.currentEditingCard = card;
$scope.editCardFormattedText = card.formatted_text; 144 145 $scope.editCardFormattedText = card.formatted_text;
console.log(card); 145 146 console.log(card);
$('#editModal').openModal(card.editModalOptions); 146 147 $('#editModal').openModal(card.editModalOptions);
147
}; 148 148 };
149 149
$scope.saveEditChanges = function() { 150 150 $scope.saveEditChanges = function() {
if (!$scope.currentEditingCard) return; 151 151 if (!$scope.currentEditingCard) return;
152 if ($('#edit-card-input').text().length == 0) return;
var myCard = { 152 153 var myCard = {
'text': $('#edit-card-input').text(), 153 154 'text': $('#edit-card-input').text(),
'mask': $scope.editCardBlanks, 154 155 'mask': $scope.editCardBlanks,
}; 155 156 };
$scope.currentEditingCard.isEdited = true; 156 157 $scope.currentEditingCard.isEdited = true;
if (myCard.text != '') 157 158 if (myCard.text != '')
$http.patch('/api/flashcards/' + $scope.currentEditingCard.id + '/', myCard). 158 159 $http.patch('/api/flashcards/' + $scope.currentEditingCard.id + '/', myCard).
success(function(data) { 159 160 success(function(data) {
console.log('flashcard edited: ' + myCard.text); 160 161 console.log('flashcard edited: ' + myCard.text);
}); 161 162 });
$scope.currentEditingCard = null; 162 163 $scope.currentEditingCard = null;
$('#editModal').closeModal(); 163 164 $('#editModal').closeModal();
}; 164 165 };
165 166
$scope.discardEditChanges = function() { 166 167 $scope.discardEditChanges = function() {
$scope.currentEditingCard = null; 167 168 $scope.currentEditingCard = null;
$('#editModal').closeModal(); 168 169 $('#editModal').closeModal();
}; 169 170 };
170 171
$scope.refreshEditCardInput = function() { 171 172 $scope.refreshEditCardInput = function() {
$scope.editCardText = $('#edit-card-input').text(); 172 173 $scope.editCardText = $('#edit-card-input').text();
173 174
$scope.submit_enabled = $scope.editCardText.length >= 5 && $scope.editCardText.length <= 160; 174 175 $scope.submit_enabled = $scope.editCardText.length >= 5 && $scope.editCardText.length <= 160;
175 176
var i = 0; 176 177 var i = 0;
$scope.editCardBlanks = []; 177 178 $scope.editCardBlanks = [];
$('#edit-card-input')[0].childNodes.forEach(function(node) { 178 179 $('#edit-card-input')[0].childNodes.forEach(function(node) {
node = $(node)[0]; 179 180 node = $(node)[0];
if (node.tagName == 'B') { 180 181 if (node.tagName == 'B') {
var text = $(node).text(); 181 182 var text = $(node).text();
var leftspaces = 0, rightspaces = 0; 182 183 var leftspaces = 0, rightspaces = 0;
// awful way to find the first non-space character from the left or the right. thanks.js 183 184 // awful way to find the first non-space character from the left or the right. thanks.js
while (text[leftspaces] == ' ' || text[leftspaces] == '\xa0') leftspaces++; 184 185 while (text[leftspaces] == ' ' || text[leftspaces] == '\xa0') leftspaces++;
while (text[text.length - 1 - rightspaces] == ' ' || text[text.length - 1 - rightspaces] == '\xa0') rightspaces++; 185 186 while (text[text.length - 1 - rightspaces] == ' ' || text[text.length - 1 - rightspaces] == '\xa0') rightspaces++;
console.log(leftspaces, text.length); 186 187 console.log(leftspaces, text.length);
if (leftspaces != text.length) $scope.editCardBlanks.push([i + leftspaces, i + text.length - rightspaces]); 187 188 if (leftspaces != text.length) $scope.editCardBlanks.push([i + leftspaces, i + text.length - rightspaces]);
i += text.length; 188 189 i += text.length;
} else if (!node.data) { 189 190 } else if (!node.data) {
i += $(node).text().length; 190 191 i += $(node).text().length;
} else { 191 192 } else {
i += node.data.length; 192 193 i += node.data.length;
scripts/CardListController.js View file @ 5cd9fd4
angular.module('flashy.CardListController', ['ui.router', 'angular.filter', 'ngSanitize', 'flashy.DeckFactory']). 1 1 angular.module('flashy.CardListController', ['ui.router', 'angular.filter', 'ngSanitize', 'flashy.DeckFactory']).
controller('CardListController', function($scope, $rootScope, $state, $http, $stateParams, Flashcard, Deck) { 2 2 controller('CardListController', function($scope, $rootScope, $state, $http, $stateParams, Flashcard, UserService, Deck) {
// cards array 3 3 // cards array
sectionId = parseInt($stateParams.sectionId); 4 4 sectionId = parseInt($stateParams.sectionId);
5 if (!UserService.isInSection(sectionId)) $state.go('addclass');
$scope.deck = new Deck(sectionId, { 5 6 $scope.deck = new Deck(sectionId, {
cardPullCallback: function(card) { 6 7 cardPullCallback: function(card) {
Materialize.toast('Pulled!', 3000); 7 8 Materialize.toast('Pulled!', 3000);
}, 8 9 },
cardUnpullCallback: function(card) { 9 10 cardUnpullCallback: function(card) {
Materialize.toast('Unpulled!', 3000); 10 11 Materialize.toast('Unpulled!', 3000);
}, 11 12 },
cardHideCallback: function(card) { 12 13 cardHideCallback: function(card) {
card.is_hidden = true; 13 14 card.is_hidden = true;
Materialize.toast('Hidden!', 3000); 14 15 Materialize.toast('Hidden!', 3000);
}, 15 16 },
cardUnhideCallback: function(card) { 16 17 cardUnhideCallback: function(card) {
card.is_hidden = false; 17 18 card.is_hidden = false;
Materialize.toast('Unhidden!', 3000); 18 19 Materialize.toast('Unhidden!', 3000);
} 19 20 }
}); 20 21 });
Flashcard.linkDeck($scope.deck); 21 22 Flashcard.linkDeck($scope.deck);
$rootScope.currentSection = $rootScope.SectionResource.get({sectionId: sectionId}); 22 23 $rootScope.currentSection = $rootScope.SectionResource.get({sectionId: sectionId});
$scope.cards = null; 23 24 $scope.cards = null;
24 25
25 26
$http.get('/api/sections/' + sectionId + '/flashcards/?hidden=yes'). 26 27 $http.get('/api/sections/' + sectionId + '/flashcards/?hidden=yes').
success(function(data) { 27 28 success(function(data) {
$scope.cards = []; 28 29 $scope.cards = [];
for (i in data) $scope.cards[data[i].id] = new Flashcard(data[i], $scope.deck); 29 30 for (i in data) $scope.cards[data[i].id] = new Flashcard(data[i], $scope.deck);
console.log('got list', data); 30 31 console.log('got list', data);
}). 31 32 }).
error(function(err) { 32 33 error(function(err) {
console.log('pulling feed failed'); 33 34 console.log('pulling feed failed');
}); 34 35 });
35 36
// flag/report card 36 37 // flag/report card
$scope.flag = function(card) { 37 38 $scope.flag = function(card) {
$http.post('/api/flashcards/' + card.id + '/report/'). 38 39 $http.post('/api/flashcards/' + card.id + '/report/').
success(function(data) { 39 40 success(function(data) {
console.log(card.text + ' reported'); 40 41 console.log(card.text + ' reported');
}). 41 42 }).
error(function(err) { 42 43 error(function(err) {
console.log('no flag for you'); 43 44 console.log('no flag for you');
}); 44 45 });
}; 45 46 };
46 47
// toggle button text from show to hide 47 48 // toggle button text from show to hide
$(function() { 48 49 $(function() {
$('#showHidden').click(function() { 49 50 $('#showHidden').click(function() {
$(this).text(function(i, text) { 50 51 $(this).text(function(i, text) {
return text === 'Show Hidden' ? 'Hide Hidden' : 'Show Hidden'; 51 52 return text === 'Show Hidden' ? 'Hide Hidden' : 'Show Hidden';
}); 52 53 });
}); 53 54 });
}); 54 55 });
55 56
$scope.$on('$destroy', function() { 56 57 $scope.$on('$destroy', function() {
$rootScope.currentSection = {}; 57 58 $rootScope.currentSection = {};
$(document).off('keydown'); 58 59 $(document).off('keydown');
}); 59 60 });
60 61
$(document).ready(function() { 61 62 $(document).ready(function() {
62 63
//back to top 63 64 //back to top
var offset = 300; 64 65 var offset = 300;
var duration = 300; 65 66 var duration = 300;
$(window).scroll(function() { 66 67 $(window).scroll(function() {
if ($(this).scrollTop() > offset) { 67 68 if ($(this).scrollTop() > offset) {
$('.back-to-top').fadeIn(duration); 68 69 $('.back-to-top').fadeIn(duration);
} else { 69 70 } else {
$('.back-to-top').fadeOut(duration); 70 71 $('.back-to-top').fadeOut(duration);
} 71 72 }
}); 72 73 });
73 74
$('.back-to-top').click(function(event) { 74 75 $('.back-to-top').click(function(event) {
event.preventDefault(); 75 76 event.preventDefault();
$('html, body').animate({scrollTop: 0}, duration); 76 77 $('html, body').animate({scrollTop: 0}, duration);
return false; 77 78 return false;
}); 78 79 });
}); 79 80 });
80 81
// to display day of the week badges 81 82 // to display day of the week badges
$scope.dayofweek = function(item) { 82 83 $scope.dayofweek = function(item) {
var date = new Date(item.material_date); 83 84 var date = new Date(item.material_date);
return ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'][date.getDay()]; 84 85 return ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'][date.getDay()];
}; 85 86 };
86 87
// checkbox filter 87 88 // checkbox filter
$scope.filter = { 88 89 $scope.filter = {
'week1': true, 89 90 'week1': true,
'week2': true, 90 91 'week2': true,
'week3': true, 91 92 'week3': true,
'week4': true, 92 93 'week4': true,
'week5': true, 93 94 'week5': true,
'week6': true, 94 95 'week6': true,
'week7': true, 95 96 'week7': true,
'week8': true, 96 97 'week8': true,
'week9': true, 97 98 'week9': true,
'week10': true, 98 99 'week10': true,
}; 99 100 };
100 101
$scope.filterByDate = function(item) { 101 102 $scope.filterByDate = function(item) {
var week = item.material_week_num; 102 103 var week = item.material_week_num;
return (week == 1 && $scope.filter['week1']) || 103 104 return (week == 1 && $scope.filter['week1']) ||
(week == 2 && $scope.filter['week2']) || 104 105 (week == 2 && $scope.filter['week2']) ||
(week == 3 && $scope.filter['week3']) || 105 106 (week == 3 && $scope.filter['week3']) ||
(week == 4 && $scope.filter['week4']) || 106 107 (week == 4 && $scope.filter['week4']) ||
(week == 5 && $scope.filter['week5']) || 107 108 (week == 5 && $scope.filter['week5']) ||
(week == 6 && $scope.filter['week6']) || 108 109 (week == 6 && $scope.filter['week6']) ||
(week == 7 && $scope.filter['week7']) || 109 110 (week == 7 && $scope.filter['week7']) ||
(week == 8 && $scope.filter['week8']) || 110 111 (week == 8 && $scope.filter['week8']) ||
(week == 9 && $scope.filter['week9']) || 111 112 (week == 9 && $scope.filter['week9']) ||
(week == 10 && $scope.filter['week10']); 112 113 (week == 10 && $scope.filter['week10']);
}; 113 114 };
$scope.$on('$destroy', function() { 114 115 $scope.$on('$destroy', function() {
$scope.deck.cleanup(); 115 116 $scope.deck.cleanup();
Flashcard.cleanup(); 116 117 Flashcard.cleanup();
}); 117 118 });
118 119
} 119 120 }
). 120 121 ).
filter('displayCard', function($sce) { 121 122 filter('displayCard', function($sce) {
return function(card) { 122 123 return function(card) {
// text to display as html 123 124 // text to display as html
var cardText = ''; 124 125 var cardText = '';
125 126
var start = 0; // where to start next string break 126 127 var start = 0; // where to start next string break
127 128
// get all display pieces and blank pieces 128 129 // get all display pieces and blank pieces
scripts/FeedController.js View file @ 5cd9fd4
angular.module('flashy.FeedController', 1 1 angular.module('flashy.FeedController',
['ui.router', 2 2 ['ui.router',
'ngAnimate', 3 3 'ngAnimate',
'ngWebSocket', 4 4 'ngWebSocket',
'contenteditable', 5 5 'contenteditable',
'flashy.DeckFactory']).controller('FeedController', 6 6 'flashy.DeckFactory']).controller('FeedController',
function($scope, $rootScope, $state, $http, $window, $timeout, $stateParams, $websocket, $interval, UserService, Flashcard, Deck) { 7 7 function($scope, $rootScope, $state, $http, $window, $timeout, $stateParams, $websocket, $interval, UserService, Flashcard, Deck) {
angular.module('flashy.CardGridController').CardGridController.apply(this, arguments); 8 8 angular.module('flashy.CardGridController').CardGridController.apply(this, arguments);
var promise; 9 9 var promise;
sectionId = parseInt($stateParams.sectionId); 10 10 sectionId = parseInt($stateParams.sectionId);
$scope.updateCardScore = function(card, scoreChange) { 11 11 $scope.updateCardScore = function(card, scoreChange) {
console.log('update card score'); 12 12 console.log('update card score');
// if no colNum is attached, then this doesn't exist on the feed yet 13 13 // if no colNum is attached, then this doesn't exist on the feed yet
if (typeof card.colNum === 'undefined' || typeof card.colRank === 'undefined') { 14 14 if (typeof card.colNum === 'undefined' || typeof card.colRank === 'undefined') {
console.log('no col num'); 15 15 console.log('no col num');
return; 16 16 return;
} 17 17 }
/*$scope.cardCols[card.colNum].sort(function(a, b) { 18 18 /*$scope.cardCols[card.colNum].sort(function(a, b) {
return b.score - a.score; 19 19 return b.score - a.score;
}); 20 20 });
console.log($scope.cardCols); 21 21 console.log($scope.cardCols);
$scope.updateColRanks($scope.cardCols[card.colNum]); 22 22 $scope.updateColRanks($scope.cardCols[card.colNum]);
return;*/ 23 23 return;*/
console.log(card.score); 24 24 console.log(card.score);
card.score += scoreChange; 25 25 card.score += scoreChange;
console.log(card.score); 26 26 console.log(card.score);
var col = card.colNum; 27 27 var col = card.colNum;
var rank = card.colRank; 28 28 var rank = card.colRank;
var s = Math.sign(scoreChange); 29 29 var s = Math.sign(scoreChange);
30 30
//rank -= s; 31 31 //rank -= s;
if (rank < 0) return; 32 32 if (rank < 0) return;
if (rank == $scope.cardCols[col].length) return; 33 33 if (rank == $scope.cardCols[col].length) return;
34 34
$scope.affectedCards = []; 35 35 $scope.affectedCards = [];
//console.log('before whiel, rank:' + rank); 36 36 //console.log('before whiel, rank:' + rank);
if (s > 0) { 37 37 if (s > 0) {
rank -= 1; 38 38 rank -= 1;
//console.log('+'); 39 39 //console.log('+');
while ($scope.cardCols[col][rank].score < card.score) { 40 40 while ($scope.cardCols[col][rank].score < card.score) {
//console.log('while'); 41 41 //console.log('while');
$scope.cardCols[col][rank].colRank += 1; 42 42 $scope.cardCols[col][rank].colRank += 1;
$scope.affectedCards.push($scope.cardCols[col][rank]); 43 43 $scope.affectedCards.push($scope.cardCols[col][rank]);
rank -= 1; 44 44 rank -= 1;
if (rank < 0) break; 45 45 if (rank < 0) break;
if (rank == $scope.cardCols[col].length) break; 46 46 if (rank == $scope.cardCols[col].length) break;
} 47 47 }
} else { 48 48 } else {
rank += 1; 49 49 rank += 1;
console.log('-'); 50 50 console.log('-');
while ($scope.cardCols[col][rank].score > card.score) { 51 51 while ($scope.cardCols[col][rank].score > card.score) {
//console.log('while'); 52 52 //console.log('while');
$scope.cardCols[col][rank].colRank -= 1; 53 53 $scope.cardCols[col][rank].colRank -= 1;
$scope.affectedCards.push($scope.cardCols[col][rank]); 54 54 $scope.affectedCards.push($scope.cardCols[col][rank]);
rank += 1; 55 55 rank += 1;
if (rank < 0) break; 56 56 if (rank < 0) break;
if (rank == $scope.cardCols[col].length) break; 57 57 if (rank == $scope.cardCols[col].length) break;
} 58 58 }
} 59 59 }
rank += s; 60 60 rank += s;
//console.log('after a whiel, rank:' + rank); 61 61 //console.log('after a whiel, rank:' + rank);
62 62
console.log($scope.affectedCards); 63 63 console.log($scope.affectedCards);
64 64
var upMove = $scope.height; 65 65 var upMove = $scope.height;
var downMove = $scope.height; 66 66 var downMove = $scope.height;
$scope.$apply(function() { 67 67 $scope.$apply(function() {
$('.card.flashy.card-moveUp').css({ 68 68 $('.card.flashy.card-moveUp').css({
'margin-top': 300 + 'px !important', // how much moveUp moves 69 69 'margin-top': 300 + 'px !important', // how much moveUp moves
}); 70 70 });
71 71
$('.card.flashy.card-moveDown').css({ 72 72 $('.card.flashy.card-moveDown').css({
'margin-top': 300 + 'px !important', // how much moveDown moves 73 73 'margin-top': 300 + 'px !important', // how much moveDown moves
}); 74 74 });
}); 75 75 });
76 76
if (s > 0) { 77 77 if (s > 0) {
card.moveUp = true; 78 78 card.moveUp = true;
upMove *= $scope.affectedCards.length; 79 79 upMove *= $scope.affectedCards.length;
/*for (i=0; i<$scope.affectedCards.length; i++) { 80 80 /*for (i=0; i<$scope.affectedCards.length; i++) {
$scope.affectedCards[i].moveDown = true; 81 81 $scope.affectedCards[i].moveDown = true;
}*/ 82 82 }*/
} else { 83 83 } else {
card.moveDown = true; 84 84 card.moveDown = true;
downMove *= $scope.affectedCards; 85 85 downMove *= $scope.affectedCards;
/*for (i=0; i<$scope.affectedCards.length; i++) { 86 86 /*for (i=0; i<$scope.affectedCards.length; i++) {
$scope.affectedCards[i].moveUp = true; 87 87 $scope.affectedCards[i].moveUp = true;
}*/ 88 88 }*/
} 89 89 }
90 90
$timeout(function() { 91 91 $timeout(function() {
$('.card.flashy.card-moveUp').css({ 92 92 $('.card.flashy.card-moveUp').css({
'margin-top': '6px', 93 93 'margin-top': '6px',
}); 94 94 });
95 95
$('.card.flashy.card-moveDown').css({ 96 96 $('.card.flashy.card-moveDown').css({
'margin-top': '6px', 97 97 'margin-top': '6px',
}); 98 98 });
if (s > 0) { 99 99 if (s > 0) {
card.moveUp = false; 100 100 card.moveUp = false;
for (i = 0; i < $scope.affectedCards.length; i++) { 101 101 for (i = 0; i < $scope.affectedCards.length; i++) {
$scope.affectedCards[i].moveDown = false; 102 102 $scope.affectedCards[i].moveDown = false;
} 103 103 }
} else { 104 104 } else {
card.moveDown = false; 105 105 card.moveDown = false;
for (i = 0; i < $scope.affectedCards.length; i++) { 106 106 for (i = 0; i < $scope.affectedCards.length; i++) {
$scope.affectedCards[i].moveUp = false; 107 107 $scope.affectedCards[i].moveUp = false;
} 108 108 }
} 109 109 }
}, 1000); 110 110 }, 1000);
$scope.cardCols[col].splice(rank, 0, $scope.cardCols[col].splice(card.colRank, 1)[0]); 111 111 $scope.cardCols[col].splice(rank, 0, $scope.cardCols[col].splice(card.colRank, 1)[0]);
card.colRank = rank; 112 112 card.colRank = rank;
//$scope.updateColRanks($scope.cardCols[card.colNum]); // can be optimized out 113 113 //$scope.updateColRanks($scope.cardCols[card.colNum]); // can be optimized out
}; 114 114 };
115 115
$scope.feed_ws = $websocket($scope.ws_host + '/ws/feed/' + sectionId + '?subscribe-broadcast'); 116 116 $scope.feed_ws = $websocket($scope.ws_host + '/ws/feed/' + sectionId + '?subscribe-broadcast');
$scope.feed_ws.onMessage(function(e) { 117 117 $scope.feed_ws.onMessage(function(e) {
data = JSON.parse(e.data); 118 118 data = JSON.parse(e.data);
console.log(data.event_type, 'message', data.flashcard); 119 119 console.log(data.event_type, 'message', data.flashcard);
if (data.event_type == 'new_card') { 120 120 if (data.event_type == 'new_card') {
// don't trust the backend for feed's authored_by_user 121 121 // don't trust the backend for feed's authored_by_user
card = data.flashcard; 122 122 card = data.flashcard;
delete card['is_authored_by_user']; 123 123 delete card['is_authored_by_user'];
card = new Flashcard(card); 124 124 card = new Flashcard(card);
$scope.addCardToGrid(card, $scope.deck); 125 125 $scope.addCardToGrid(card, $scope.deck);
} else if (data.event_type == 'score_change') { 126 126 } else if (data.event_type == 'score_change') {
card = new Flashcard(data.flashcard); // doesnt create a card if it exists 127 127 card = new Flashcard(data.flashcard); // doesnt create a card if it exists
//card.score = data.flashcard.score; 128 128 //card.score = data.flashcard.score;
console.log('score change'); 129 129 console.log('score change');
$scope.updateCardScore(card, data.flashcard.score - card.score); 130 130 $scope.updateCardScore(card, data.flashcard.score - card.score);
} 131 131 }
}); 132 132 });
133 133
$scope.pushCard = function() { 134 134 $scope.pushCard = function() {
var myCard = { 135 135 var myCard = {
// we can't trim this string because it'd mess up the blanks. Something to fix. 136 136 // we can't trim this string because it'd mess up the blanks. Something to fix.
'text': $('#new-card-input').text(), 137 137 'text': $('#new-card-input').text(),
'mask': $scope.newCardBlanks, 138 138 'mask': $scope.newCardBlanks,
section: $scope.section.id 139 139 section: $scope.section.id
}; 140 140 };
if (!$scope.submit_enabled) { 141 141 if (!$scope.submit_enabled) {
return; 142 142 return;
} 143 143 }
if (myCard.text == '') { 144 144 if (myCard.text == '') {
console.log('blank flashcard not pushed:' + myCard.text); 145 145 console.log('blank flashcard not pushed:' + myCard.text);
return closeNewCard(); 146 146 return closeNewCard();
} 147 147 }
$http.post('/api/flashcards/', myCard). 148 148 $http.post('/api/flashcards/', myCard).
success(function(data) { 149 149 success(function(data) {
console.log('flashcard pushed: ' + myCard.text); 150 150 console.log('flashcard pushed: ' + myCard.text);
if (!UserService.hasVerifiedEmail()) { 151 151 if (!UserService.hasVerifiedEmail()) {
Materialize.toast("<p>Thanks for contributing! However, others won't see your card until you verify your email address<p>", 4000); 152 152 Materialize.toast("<p>Thanks for contributing! However, others won't see your card until you verify your email address<p>", 4000);
} 153 153 }
}); 154 154 });
return $scope.closeNewCardModal(); 155 155 return $scope.closeNewCardModal();
}; 156 156 };
157 157
/* Key bindings for the whole feed window. Hotkey it up! */ 158 158 /* Key bindings for the whole feed window. Hotkey it up! */
var listenForC = true; 159 159 var listenForC = true;
160 160
// Need to pass these options into openmodal and leanmodal, 161 161 // Need to pass these options into openmodal and leanmodal,
// otherwise the ready handler doesn't get called 162 162 // otherwise the ready handler doesn't get called
163 163
modal_options = { 164 164 modal_options = {
dismissible: true, // Modal can be dismissed by clicking outside of the modal 165 165 dismissible: true, // Modal can be dismissed by clicking outside of the modal
opacity: 0, // Opacity of modal background 166 166 opacity: 0, // Opacity of modal background
in_duration: 300, // Transition in duration 167 167 in_duration: 300, // Transition in duration
out_duration: 200, // Transition out duration 168 168 out_duration: 200, // Transition out duration
ready: function() { 169 169 ready: function() {
$('#new-card-input').focus(); 170 170 $('#new-card-input').focus();
document.execCommand('selectAll', false, null); 171 171 document.execCommand('selectAll', false, null);
} 172 172 }
}; 173 173 };
174 174
$(document).keydown(function(e) { 175 175 $(document).keydown(function(e) {
var keyed = e.which; 176 176 var keyed = e.which;
if (keyed == 67 && listenForC) { // "c" for compose 177 177 if (keyed == 67 && listenForC) { // "c" for compose
if ($scope.currentEditingCard) return; 178 178 if ($scope.currentEditingCard) return;
$scope.openNewCardModal(); 179 179 $scope.openNewCardModal();
e.preventDefault(); 180 180 e.preventDefault();
return false; 181 181 return false;
} else if (keyed == 27) { // clear on ESC 182 182 } else if (keyed == 27) { // clear on ESC
$scope.closeNewCardModal(); 183 183 $scope.closeNewCardModal();
$scope.discardEditChanges(); 184 184 $scope.discardEditChanges();
} 185 185 }
}); 186 186 });
187 187
$scope.openNewCardModal = function() { 188 188 $scope.openNewCardModal = function() {
$('#newCard').openModal(modal_options); 189 189 $('#newCard').openModal(modal_options);
listenForC = false; 190 190 listenForC = false;
$('#new-card-input').html('Write a flashcard!'); 191 191 $('#new-card-input').html('Write a flashcard!');
}; 192 192 };
193 193
$scope.closeNewCardModal = function() { 194 194 $scope.closeNewCardModal = function() {
listenForC = true; 195 195 listenForC = true;
$('#new-card-input').html('').blur(); 196 196 $('#new-card-input').html('').blur();
$('#newCard').closeModal(modal_options); 197 197 $('#newCard').closeModal(modal_options);
}; 198 198 };
199 199
$('.tooltipped').tooltip({delay: 50}); 200 200 $('.tooltipped').tooltip({delay: 50});
// the "href" attribute of .modal-trigger must specify the modal ID that wants to be triggered 201 201 // the "href" attribute of .modal-trigger must specify the modal ID that wants to be triggered
$('.modal-trigger').leanModal(modal_options); 202 202 $('.modal-trigger').leanModal(modal_options);
203 203
$('#new-card-input').on('keydown', function(e) { 204 204 $('#new-card-input').on('keydown', function(e) {
if (e.which == 13) { 205 205 if (e.which == 13) {
e.preventDefault(); 206 206 e.preventDefault();
if ($scope.submit_enabled) { 207 207 if ($scope.submit_enabled) {
$scope.pushCard(); 208 208 $scope.pushCard();
} 209 209 }
return false; 210 210 return false;
} 211 211 }
}); 212 212 });
213 213
214 214
$scope.newCardBlanks = []; 215 215 $scope.newCardBlanks = [];
$scope.refreshNewCardInput = function() { 216 216 $scope.refreshNewCardInput = function() {
$scope.newCardText = $('#new-card-input').text(); 217 217 $scope.newCardText = $('#new-card-input').text();
$scope.submit_enabled = $scope.newCardText.length >= 5 && $scope.newCardText.length <= 160; 218 218 $scope.submit_enabled = $scope.newCardText.length >= 5 && $scope.newCardText.length <= 160;
var i = 0; 219 219 var i = 0;
$scope.newCardBlanks = []; 220 220 $scope.newCardBlanks = [];
$('#new-card-input')[0].childNodes.forEach(function(node) { 221 221 $('#new-card-input')[0].childNodes.forEach(function(node) {
node = $(node)[0]; 222 222 node = $(node)[0];
if (node.tagName == 'B') { 223 223 if (node.tagName == 'B') {
var text = $(node).text(); 224 224 var text = $(node).text();
var leftspaces = 0, rightspaces = 0; 225 225 var leftspaces = 0, rightspaces = 0;
// awful way to find the first non-space character from the left or the right. thanks.js 226 226 // awful way to find the first non-space character from the left or the right. thanks.js
while (text[leftspaces] == ' ' || text[leftspaces] == '\xa0') leftspaces++; 227 227 while (text[leftspaces] == ' ' || text[leftspaces] == '\xa0') leftspaces++;
while (text[text.length - 1 - rightspaces] == ' ' || text[text.length - 1 - rightspaces] == '\xa0') rightspaces++; 228 228 while (text[text.length - 1 - rightspaces] == ' ' || text[text.length - 1 - rightspaces] == '\xa0') rightspaces++;
console.log(leftspaces, text.length); 229 229 console.log(leftspaces, text.length);
if (leftspaces != text.length) $scope.newCardBlanks.push([i + leftspaces, i + text.length - rightspaces]); 230 230 if (leftspaces != text.length) $scope.newCardBlanks.push([i + leftspaces, i + text.length - rightspaces]);
i += text.length; 231 231 i += text.length;
} else if (!node.data) { 232 232 } else if (!node.data) {
i += $(node).text().length; 233 233 i += $(node).text().length;
} else { 234 234 } else {
i += node.data.length; 235 235 i += node.data.length;
} 236 236 }
}); 237 237 });
$scope.newCardBlanks.sort(function(a, b) { 238 238 $scope.newCardBlanks.sort(function(a, b) {
return a[0] - b[0]; 239 239 return a[0] - b[0];
}); 240 240 });
i = 0; 241 241 i = 0;
newtext = ''; 242 242 newtext = '';
$scope.newCardBlanks.forEach(function(blank) { 243 243 $scope.newCardBlanks.forEach(function(blank) {
newtext += $scope.newCardText.slice(i, blank[0]); 244 244 newtext += $scope.newCardText.slice(i, blank[0]);
newtext += '<b>' + $scope.newCardText.slice(blank[0], blank[1]) + '</b>'; 245 245 newtext += '<b>' + $scope.newCardText.slice(blank[0], blank[1]) + '</b>';
i = blank[1]; 246 246 i = blank[1];
}); 247 247 });
newtext += $scope.newCardText.slice(i); 248 248 newtext += $scope.newCardText.slice(i);
//$scope.newCardFormattedText = newtext; 249 249 //$scope.newCardFormattedText = newtext;
}; 250 250 };
$scope.shuffleCards = function() { 251 251 $scope.shuffleCards = function() {
$timeout(function() { 252 252 $timeout(function() {
(function(o) { 253 253 (function(o) {
for (var j, x, i = o.length; i; j = Math.floor(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x); 254 254 for (var j, x, i = o.length; i; j = Math.floor(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x);
return o; 255 255 return o;
})($scope.cardCols[0]); 256 256 })($scope.cardCols[0]);
}); 257 257 });
}; 258 258 };
$scope.$on('$destroy', function() { 259 259 $scope.$on('$destroy', function() {
$scope.feed_ws.close(); 260 260 $scope.feed_ws.close();