Compare View
Commits (3)
Diff
Showing 4 changed files Inline Diff
scripts/FeedController.js
View file @
0c0dbdc
File was created | 1 | angular.module('flashy.FeedController', | ||
2 | ['ui.router', | |||
3 | 'ngAnimate', | |||
4 | 'ngWebSocket', | |||
5 | 'contenteditable', | |||
6 | 'flashy.DeckFactory']).controller('FeedController', | |||
7 | function($scope, $rootScope, $state, $http, $window, $timeout, $stateParams, $websocket, $interval, UserService, Flashcard, Deck) { | |||
8 | angular.module('flashy.CardGridController').CardGridController.apply(this, arguments); | |||
9 | var promise; | |||
10 | $rootScope.debugFlashcard = false; | |||
11 | ||||
12 | $scope.updateCardScore = function(card, scoreChange) { | |||
13 | console.log('update card score'); | |||
14 | // if no colNum is attached, then this doesn't exist on the feed yet | |||
15 | if (!card.colNum) return; | |||
16 | /*$scope.cardCols[card.colNum].sort(function(a, b) { | |||
17 | return b.score - a.score; | |||
18 | });*/ | |||
19 | ||||
20 | card.score += scoreChange; | |||
21 | var col = card.colNum; | |||
22 | var rank = card.colRank; | |||
23 | var s = Math.sign(scoreChange); | |||
24 | ||||
25 | rank -= s; | |||
26 | if (rank < 0) return; | |||
27 | if (rank == $scope.cardCols[col].length) return; | |||
28 | ||||
29 | $scope.affectedCards = []; | |||
30 | while (s * $scope.cardCols[col][rank].score < s * card.score) { | |||
31 | $scope.affectedCards.push($scope.cardCols[col][rank]); | |||
32 | rank -= s; | |||
33 | if (rank < 0) break; | |||
34 | if (rank == $scope.cardCols[col].length) break; | |||
35 | } | |||
36 | ||||
37 | /*var direction = s ? 'margin- | |||
38 | var computedStyle = $boxTwo.css('margin-left'); | |||
39 | $boxTwo.removeClass('horizTranslate'); | |||
40 | $boxTwo.css('margin-left', computedStyle);*/ | |||
41 | ||||
42 | $scope.cardCols[col].splice(rank + s, 0, $scope.cardCols[col].splice(card.colRank, 1)[0]); | |||
43 | $scope.updateColRanks($scope.cardCols[card.colNum]); // can be optimized out | |||
44 | }; | |||
45 | ||||
46 | ||||
47 | ||||
48 | $scope.feed_ws = $websocket($scope.ws_host + '/ws/feed/' + $scope.sectionId + '?subscribe-broadcast'); | |||
49 | $scope.feed_ws.onMessage(function (e) { | |||
50 | ||||
51 | ||||
52 | console.log("oh yeaaaaaaaaaaaaaaaaaaa"); | |||
53 | ||||
54 | data = JSON.parse(e.data); | |||
55 | console.log('message', data); | |||
56 | if (data.event_type == 'new_card') { | |||
57 | $scope.addCardToGrid(new Flashcard(data.flashcard, $scope.deck)); | |||
58 | } else if (data.event_type == 'score_change') { | |||
59 | card = new Flashcard(data.flashcard); // doesnt create a card if it exists | |||
60 | console.log('score change'); | |||
61 | $scope.updateCardScore(card, data.flashcard.score - card.score); | |||
62 | } | |||
63 | }); | |||
64 | ||||
65 | $scope.pushCard = function() { | |||
66 | var myCard = { | |||
67 | // we can't trim this string because it'd mess up the blanks. Something to fix. | |||
68 | 'text': $('#new-card-input').text(), | |||
69 | 'mask': $scope.newCardBlanks, | |||
70 | section: $scope.section.id | |||
71 | }; | |||
72 | if (myCard.text == '') { | |||
73 | console.log('blank flashcard not pushed:' + myCard.text); | |||
74 | return closeNewCard(); | |||
75 | } | |||
76 | $http.post('/api/flashcards/', myCard). | |||
77 | success(function(data) { | |||
78 | console.log('flashcard pushed: ' + myCard.text); | |||
79 | if (!UserService.hasVerifiedEmail()) { | |||
80 | Materialize.toast("<p>Thanks for contributing! However, others won't see your card until you verify your email address<p>", 4000); | |||
81 | } | |||
82 | }); | |||
83 | return $scope.closeNewCardModal(); | |||
84 | }; | |||
85 | ||||
86 | /* Key bindings for the whole feed window. Hotkey it up! */ | |||
87 | var listenForC = true; | |||
88 | ||||
89 | // Need to pass these options into openmodal and leanmodal, | |||
90 | // otherwise the ready handler doesn't get called | |||
91 | ||||
92 | modal_options = { | |||
93 | dismissible: true, // Modal can be dismissed by clicking outside of the modal | |||
94 | opacity: 0, // Opacity of modal background | |||
95 | in_duration: 300, // Transition in duration | |||
96 | out_duration: 200, // Transition out duration | |||
97 | ready: function() { | |||
98 | $('#new-card-input').focus(); | |||
99 | document.execCommand('selectAll', false, null); | |||
100 | } | |||
101 | }; | |||
102 | ||||
103 | $(document).keydown(function(e) { | |||
104 | var keyed = e.which; | |||
105 | if (keyed == 67 && listenForC) { // "c" for compose | |||
106 | $scope.openNewCardModal(); | |||
107 | e.preventDefault(); | |||
108 | return false; | |||
109 | } else if (keyed == 27) { // clear on ESC | |||
110 | $scope.closeNewCardModal(); | |||
111 | } | |||
112 | }); | |||
113 | ||||
114 | $scope.openNewCardModal = function() { | |||
115 | $('#newCard').openModal(modal_options); | |||
116 | listenForC = false; | |||
117 | $('#new-card-input').html('Write a flashcard!'); | |||
118 | }; | |||
119 | ||||
120 | $scope.closeNewCardModal = function() { | |||
121 | listenForC = true; | |||
122 | $('#new-card-input').html('').blur(); | |||
123 | $('#newCard').closeModal(modal_options); | |||
124 | }; | |||
125 | ||||
126 | $('.tooltipped').tooltip({delay: 50}); | |||
127 | // the "href" attribute of .modal-trigger must specify the modal ID that wants to be triggered | |||
128 | $('.modal-trigger').leanModal(modal_options); | |||
129 | $('#new-card-input').on('keydown', function(e) { | |||
130 | if (e.which == 13) { | |||
131 | e.preventDefault(); | |||
132 | if ($scope.submit_enabled) { | |||
133 | $scope.pushCard(); | |||
134 | listenForC = true; | |||
135 | } | |||
136 | return false; | |||
137 | } else { | |||
138 | ||||
139 | } | |||
140 | }); | |||
141 | $('button#blank-selected').click(function() { | |||
142 | console.log(window.getSelection()); | |||
143 | document.execCommand('bold'); | |||
144 | }); | |||
145 | $scope.newCardBlanks = []; | |||
146 | $scope.refreshNewCardInput = function() { | |||
147 | $scope.newCardText = $('#new-card-input').text(); | |||
148 | $scope.submit_enabled = $scope.newCardText.length >= 5 && $scope.newCardText.length <= 160; | |||
149 | var i = 0; | |||
150 | $scope.newCardBlanks = []; | |||
151 | $('#new-card-input')[0].childNodes.forEach(function(node) { | |||
152 | node = $(node)[0]; | |||
153 | if (node.tagName == 'B') { | |||
154 | var text = $(node).text(); | |||
155 | var leftspaces = 0, rightspaces = 0; | |||
156 | // awful way to find the first non-space character from the left or the right. thanks.js | |||
157 | while (text[leftspaces] == ' ' || text[leftspaces] == '\xa0') leftspaces++; | |||
158 | while (text[text.length - 1 - rightspaces] == ' ' || text[text.length - 1 - rightspaces] == '\xa0') rightspaces++; | |||
159 | console.log(leftspaces, text.length); | |||
160 | if (leftspaces != text.length) $scope.newCardBlanks.push([i + leftspaces, i + text.length - rightspaces]); | |||
161 | i += text.length; | |||
162 | } else if (!node.data) { | |||
163 | i += $(node).text().length; | |||
164 | } else { | |||
165 | i += node.data.length; | |||
166 | } | |||
167 | }); | |||
168 | $scope.newCardBlanks.sort(function(a, b) { | |||
169 | return a[0] - b[0]; | |||
170 | }); | |||
171 | i = 0; | |||
172 | newtext = ''; | |||
173 | $scope.newCardBlanks.forEach(function(blank) { | |||
174 | newtext += $scope.newCardText.slice(i, blank[0]); | |||
175 | newtext += '<b>' + $scope.newCardText.slice(blank[0], blank[1]) + '</b>'; | |||
176 | i = blank[1]; | |||
177 | }); | |||
178 | newtext += $scope.newCardText.slice(i); | |||
179 | //$scope.newCardFormattedText = newtext; | |||
180 | }; | |||
181 | $scope.shuffleCards = function() { | |||
182 | $timeout(function() { | |||
183 | (function(o) { | |||
184 | for (var j, x, i = o.length; i; j = Math.floor(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x); | |||
185 | return o; | |||
186 | })($scope.cardCols[0]); | |||
187 | }); | |||
188 | }; | |||
189 | $scope.$on('$destroy', function() { | |||
190 | $scope.feed_ws.close(); | |||
191 | $interval.cancel(promise); | |||
192 | }); | |||
193 | return $http.get('/api/sections/' + sectionId + '/feed/'). | |||
194 | success(function(data) { | |||
195 | console.log(data); | |||
196 | $scope.cards = data.map(function(card) { | |||
197 | return new Flashcard(card, $scope.deck); | |||
198 | }); | |||
199 | $scope.refreshLayout().then(function() { | |||
200 | $timeout($scope.refreshColumnWidth).then(function() { | |||
201 | $scope.showGrid = true; | |||
202 | }); | |||
203 | console.log('layout done'); | |||
204 | }); | |||
205 | }); | |||
206 | ||||
207 | ||||
208 | }); | |||
angular.module('flashy.FeedController', | 1 | |||
['ui.router', | 2 | |||
'ngAnimate', | 3 | |||
'ngWebSocket', | 4 | |||
'contenteditable', | 5 | |||
'flashy.DeckFactory']).controller('FeedController', | 6 | |||
function($scope, $rootScope, $state, $http, $window, $timeout, $stateParams, $websocket, $interval, UserService, Flashcard, Deck) { | 7 | |||
angular.module('flashy.CardGridController').CardGridController.apply(this, arguments); | 8 | |||
var promise; | 9 | |||
$rootScope.debugFlashcard = false; | 10 | |||
11 | ||||
$scope.updateCardScore = function(card, scoreChange) { | 12 | |||
console.log('update card score'); | 13 | |||
// if no colNum is attached, then this doesn't exist on the feed yet | 14 | |||
if (!card.colNum) return; | 15 | |||
/*$scope.cardCols[card.colNum].sort(function(a, b) { | 16 | |||
return b.score - a.score; | 17 | |||
});*/ | 18 | |||
19 | ||||
card.score += scoreChange; | 20 | |||
var col = card.colNum; | 21 | |||
var rank = card.colRank; | 22 | |||
var s = Math.sign(scoreChange); | 23 | |||
24 | ||||
rank -= s; | 25 | |||
if (rank < 0) return; | 26 | |||
if (rank == $scope.cardCols[col].length) return; | 27 | |||
28 | ||||
$scope.affectedCards = []; | 29 | |||
while (s * $scope.cardCols[col][rank].score < s * card.score) { | 30 | |||
$scope.affectedCards.push($scope.cardCols[col][rank]); | 31 | |||
rank -= s; | 32 | |||
if (rank < 0) break; | 33 | |||
if (rank == $scope.cardCols[col].length) break; | 34 | |||
} | 35 | |||
36 | ||||
/*var direction = s ? 'margin- | 37 | |||
var computedStyle = $boxTwo.css('margin-left'); | 38 | |||
$boxTwo.removeClass('horizTranslate'); | 39 | |||
$boxTwo.css('margin-left', computedStyle);*/ | 40 | |||
41 | ||||
$scope.cardCols[col].splice(rank + s, 0, $scope.cardCols[col].splice(card.colRank, 1)[0]); | 42 | |||
$scope.updateColRanks($scope.cardCols[card.colNum]); // can be optimized out | 43 | |||
}; | 44 | |||
45 | ||||
46 | ||||
47 | ||||
$scope.feed_ws = $websocket($scope.ws_host + '/ws/feed/' + $scope.sectionId + '?subscribe-broadcast'); | 48 | |||
$scope.feed_ws.onMessage(function (e) { | 49 | |||
50 | ||||
51 | ||||
console.log("oh yeaaaaaaaaaaaaaaaaaaa"); | 52 | |||
53 | ||||
data = JSON.parse(e.data); | 54 | |||
console.log('message', data); | 55 | |||
if (data.event_type == 'new_card') { | 56 | |||
$scope.addCardToGrid(new Flashcard(data.flashcard, $scope.deck)); | 57 | |||
} else if (data.event_type == 'score_change') { | 58 | |||
card = new Flashcard(data.flashcard); // doesnt create a card if it exists | 59 | |||
console.log('score change'); | 60 | |||
$scope.updateCardScore(card, data.flashcard.score - card.score); | 61 | |||
} | 62 | |||
}); | 63 | |||
64 | ||||
$scope.pushCard = function() { | 65 | |||
var myCard = { | 66 | |||
// we can't trim this string because it'd mess up the blanks. Something to fix. | 67 | |||
'text': $('#new-card-input').text(), | 68 | |||
'mask': $scope.newCardBlanks, | 69 | |||
section: $scope.section.id | 70 | |||
}; | 71 | |||
if (myCard.text == '') { | 72 | |||
console.log('blank flashcard not pushed:' + myCard.text); | 73 | |||
return closeNewCard(); | 74 | |||
} | 75 | |||
$http.post('/api/flashcards/', myCard). | 76 | |||
success(function(data) { | 77 | |||
console.log('flashcard pushed: ' + myCard.text); | 78 | |||
if (!UserService.hasVerifiedEmail()) { | 79 | |||
Materialize.toast("<p>Thanks for contributing! However, others won't see your card until you verify your email address<p>", 4000); | 80 | |||
} | 81 | |||
}); | 82 | |||
return $scope.closeNewCardModal(); | 83 | |||
}; | 84 | |||
85 | ||||
/* Key bindings for the whole feed window. Hotkey it up! */ | 86 | |||
var listenForC = true; | 87 | |||
88 | ||||
// Need to pass these options into openmodal and leanmodal, | 89 | |||
// otherwise the ready handler doesn't get called | 90 | |||
91 | ||||
modal_options = { | 92 | |||
dismissible: true, // Modal can be dismissed by clicking outside of the modal | 93 | |||
opacity: 0, // Opacity of modal background | 94 | |||
in_duration: 300, // Transition in duration | 95 | |||
out_duration: 200, // Transition out duration | 96 | |||
ready: function() { | 97 | |||
$('#new-card-input').focus(); | 98 | |||
document.execCommand('selectAll', false, null); | 99 | |||
} | 100 | |||
}; | 101 | |||
102 | ||||
$(document).keydown(function(e) { | 103 | |||
var keyed = e.which; | 104 | |||
if (keyed == 67 && listenForC) { // "c" for compose | 105 | |||
$scope.openNewCardModal(); | 106 | |||
e.preventDefault(); | 107 | |||
return false; | 108 | |||
} else if (keyed == 27) { // clear on ESC | 109 | |||
$scope.closeNewCardModal(); | 110 | |||
} | 111 | |||
}); | 112 | |||
113 | ||||
$scope.openNewCardModal = function() { | 114 | |||
$('#newCard').openModal(modal_options); | 115 | |||
listenForC = false; | 116 | |||
$('#new-card-input').html('Write a flashcard!'); | 117 | |||
}; | 118 | |||
119 | ||||
$scope.closeNewCardModal = function() { | 120 | |||
listenForC = true; | 121 | |||
$('#new-card-input').html('').blur(); | 122 | |||
$('#newCard').closeModal(modal_options); | 123 | |||
}; | 124 | |||
125 | ||||
$('.tooltipped').tooltip({delay: 50}); | 126 | |||
// the "href" attribute of .modal-trigger must specify the modal ID that wants to be triggered | 127 | |||
$('.modal-trigger').leanModal(modal_options); | 128 | |||
$('#new-card-input').on('keydown', function(e) { | 129 | |||
if (e.which == 13) { | 130 | |||
e.preventDefault(); | 131 | |||
if ($scope.submit_enabled) { | 132 | |||
$scope.pushCard(); | 133 | |||
listenForC = true; | 134 | |||
} | 135 | |||
return false; | 136 | |||
} else { | 137 | |||
138 | ||||
} | 139 | |||
}); | 140 | |||
$('button#blank-selected').click(function() { | 141 | |||
console.log(window.getSelection()); | 142 | |||
document.execCommand('bold'); | 143 | |||
}); | 144 | |||
$scope.newCardBlanks = []; | 145 | |||
$scope.refreshNewCardInput = function() { | 146 | |||
$scope.newCardText = $('#new-card-input').text(); | 147 | |||
$scope.submit_enabled = $scope.newCardText.length >= 5 && $scope.newCardText.length <= 160; | 148 | |||
var i = 0; | 149 | |||
$scope.newCardBlanks = []; | 150 | |||
$('#new-card-input')[0].childNodes.forEach(function(node) { | 151 | |||
node = $(node)[0]; | 152 | |||
if (node.tagName == 'B') { | 153 | |||
var text = $(node).text(); | 154 | |||
var leftspaces = 0, rightspaces = 0; | 155 | |||
// awful way to find the first non-space character from the left or the right. thanks.js | 156 | |||
while (text[leftspaces] == ' ' || text[leftspaces] == '\xa0') leftspaces++; | 157 | |||
while (text[text.length - 1 - rightspaces] == ' ' || text[text.length - 1 - rightspaces] == '\xa0') rightspaces++; | 158 | |||
console.log(leftspaces, text.length); | 159 | |||
if (leftspaces != text.length) $scope.newCardBlanks.push([i + leftspaces, i + text.length - rightspaces]); | 160 | |||
i += text.length; | 161 | |||
} else if (!node.data) { | 162 | |||
i += $(node).text().length; | 163 | |||
} else { | 164 | |||
i += node.data.length; | 165 | |||
} | 166 | |||
}); | 167 | |||
$scope.newCardBlanks.sort(function(a, b) { | 168 | |||
return a[0] - b[0]; | 169 | |||
}); | 170 | |||
i = 0; | 171 | |||
newtext = ''; | 172 | |||
$scope.newCardBlanks.forEach(function(blank) { | 173 | |||
newtext += $scope.newCardText.slice(i, blank[0]); | 174 | |||
newtext += '<b>' + $scope.newCardText.slice(blank[0], blank[1]) + '</b>'; | 175 | |||
i = blank[1]; | 176 | |||
}); | 177 | |||
newtext += $scope.newCardText.slice(i); | 178 | |||
//$scope.newCardFormattedText = newtext; | 179 | |||
}; | 180 | |||
$scope.shuffleCards = function() { | 181 | |||
$timeout(function() { | 182 | |||
(function(o) { | 183 | |||
for (var j, x, i = o.length; i; j = Math.floor(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x); | 184 | |||
return o; | 185 |
scripts/FlashcardDirective.js
View file @
0c0dbdc
angular.module('flashy.FlashcardDirective', []). | 1 | 1 | angular.module('flashy.FlashcardDirective', []). | |
2 | 2 | |||
directive('flashcard', | 3 | 3 | directive('flashcard', | |
4 | 4 | |||
5 | ||||
6 | function($http, $state, $window) { | |||
5 | 7 | return { | ||
function($http, $state, $window) { | 6 | 8 | templateUrl: '/app/templates/flashcard.html', | |
return { | 7 | 9 | restrict: 'E', | |
templateUrl: '/app/templates/flashcard.html', | 8 | 10 | scope: { | |
restrict: 'E', | 9 | 11 | flashcard: '=flashcardObj', // flashcard-obj in parent html | |
scope: { | 10 | 12 | refresh: '&' // eval refresh in parent html | |
flashcard: '=flashcardObj', // flashcard-obj in parent html | 11 | 13 | }, | |
refresh: '&' // eval refresh in parent html | 12 | 14 | colNum: 0, | |
}, | 13 | 15 | colRank: 0, | |
colNum: 0, | 14 | 16 | link: function(scope, element) { | |
colRank: 0, | 15 | 17 | $('.tooltipped').tooltip(); | |
link: function(scope, element) { | 16 | 18 | // /* Handles width of the card */ | |
$('.tooltipped').tooltip(); | 17 | 19 | } | |
// /* Handles width of the card */ | 18 | 20 | }; | |
} | 19 | 21 | } | |
22 | ||||
}; | 20 | 23 | ); | |
} | 21 | |||
22 | 24 | |||
25 | ||||
); | 23 | |||
24 | ||||
25 | ||||
scripts/FlashcardFactory.js
View file @
0c0dbdc
angular.module('flashy.FlashcardFactory', ['ui.router']). | 1 | 1 | angular.module('flashy.FlashcardFactory', ['ui.router']). | |
factory('Flashcard', function ($http, UserService) { | 2 | 2 | factory('Flashcard', function ($http, UserService) { | |
var FlashcardCache = []; | 3 | 3 | var FlashcardCache = []; | |
var Deck = null; | 4 | 4 | var Deck = null; | |
var Flashcard = function (data) { | 5 | 5 | var Flashcard = function (data) { | |
if (typeof data == 'number') return FlashcardCache[data]; | 6 | 6 | if (typeof data == 'number') return FlashcardCache[data]; | |
if (FlashcardCache[data.id]) return FlashcardCache[data.id]; | 7 | 7 | if (FlashcardCache[data.id]) return FlashcardCache[data.id]; | |
for (var k in data) this[k] = data[k]; | 8 | 8 | for (var k in data) this[k] = data[k]; | |
this.textPieces = []; | 9 | 9 | this.textPieces = []; | |
this.mask.sort(function (a, b) { | 10 | 10 | this.mask.sort(function (a, b) { | |
return a[0] - b[0]; | 11 | 11 | return a[0] - b[0]; | |
}); | 12 | 12 | }); | |
var i = 0; | 13 | 13 | var i = 0; | |
this.mask.forEach(function (blank) { | 14 | 14 | this.mask.forEach(function (blank) { | |
this.textPieces.push({text: this.text.slice(i, blank[0])}); | 15 | 15 | this.textPieces.push({text: this.text.slice(i, blank[0])}); | |
this.textPieces.push({text: this.text.slice(blank[0], blank[1]), blank: true}); | 16 | 16 | this.textPieces.push({text: this.text.slice(blank[0], blank[1]), blank: true}); | |
i = blank[1]; | 17 | 17 | i = blank[1]; | |
}, this); | 18 | 18 | }, this); | |
this.textPieces.push({text: this.text.slice(i)}); | 19 | 19 | this.textPieces.push({text: this.text.slice(i)}); | |
this.formatted_text = ''; | 20 | 20 | this.formatted_text = ''; | |
for (i in this.textPieces) { | 21 | 21 | for (i in this.textPieces) { | |
p = this.textPieces[i]; | 22 | 22 | p = this.textPieces[i]; | |
this.formatted_text += p.blank ? '<b>' + p.text + '</b>' : p.text; | 23 | 23 | this.formatted_text += p.blank ? '<b>' + p.text + '</b>' : p.text; | |
} | 24 | 24 | } | |
FlashcardCache[this.id] = this; | 25 | 25 | FlashcardCache[this.id] = this; | |
}; | 26 | 26 | }; | |
27 | 27 | |||
Flashcard.prototype.isInDeck = function () { | 28 | 28 | Flashcard.prototype.isInDeck = function () { | |
return !(typeof Deck.contains(this.id) === 'undefined'); | 29 | 29 | return !(typeof Deck.contains(this.id) === 'undefined'); | |
}; | 30 | 30 | }; | |
Flashcard.prototype.pullUnpull = function () { | 31 | 31 | Flashcard.prototype.pullUnpull = function () { | |
if (this.isInDeck()) this.unpull(); | 32 | 32 | if (this.isInDeck()) this.unpull(); | |
else this.pull(); | 33 | 33 | else this.pull(); | |
}; | 34 | 34 | }; | |
Flashcard.prototype.pull = function () { | 35 | 35 | Flashcard.prototype.pull = function () { | |
if (this.isInDeck()) return console.log('Not pulling', this.id, "because it's already in deck"); | 36 | 36 | if (this.isInDeck()) return console.log('Not pulling', this.id, "because it's already in deck"); | |
return $http.post('/api/flashcards/' + this.id + '/pull/'); | 37 | 37 | return $http.post('/api/flashcards/' + this.id + '/pull/'); | |
}; | 38 | 38 | }; | |
Flashcard.prototype.unpull = function () { | 39 | 39 | Flashcard.prototype.unpull = function () { | |
if (!this.isInDeck()) return console.log('Not unpulling', this.id, "because it's not in deck"); | 40 | 40 | if (!this.isInDeck()) return console.log('Not unpulling', this.id, "because it's not in deck"); | |
return $http.post('/api/flashcards/' + this.id + '/unpull/'); | 41 | 41 | return $http.post('/api/flashcards/' + this.id + '/unpull/'); | |
}; | 42 | 42 | }; | |
Flashcard.prototype.hide = function () { | 43 | 43 | Flashcard.prototype.hide = function () { | |
return $http.post('/api/flashcards/' + this.id + '/hide/'); | 44 | 44 | return $http.post('/api/flashcards/' + this.id + '/hide/'); | |
}; | 45 | 45 | }; | |
Flashcard.prototype.unhide = function () { | 46 | 46 | Flashcard.prototype.unhide = function () { | |
return $http.post('/api/flashcards/' + this.id + '/unhide/'); | 47 | 47 | return $http.post('/api/flashcards/' + this.id + '/unhide/'); | |
}; | 48 | 48 | }; | |
Flashcard.cleanup = function () { | 49 | 49 | Flashcard.cleanup = function () { | |
Deck = null; | 50 | 50 | Deck = null; | |
FlashcardCache = []; | 51 | 51 | FlashcardCache = []; | |
}; | 52 | 52 | }; | |
Flashcard.linkDeck = function(deck){ | 53 | 53 | Flashcard.linkDeck = function(deck){ | |
Deck = deck; | 54 | 54 | Deck = deck; | |
} | 55 | 55 | } | |
56 | 56 | |||
57 | Flashcard.prototype.edit = function () { | |||
58 | ||||
59 | ||||
60 | var editableText = this.formatted_text; | |||
61 | ||||
62 | //$('#flashcardEditText').html(this.formatted_text); | |||
63 | ||||
64 | $('.modal-trigger').leanModal({ | |||
65 | dismissible: true, // Modal can be dismissed by clicking outside of the modal | |||
66 | opacity: .5, // Opacity of modal background | |||
67 | in_duration: 300, // Transition in duration | |||
68 | out_duration: 200, // Transition out duration | |||
69 | ready: function () { | |||
70 | ||||
71 | $('#edit-card-input').html(editableText); | |||
72 | ||||
73 | ||||
74 | ||||
75 | }, // Callback for Modal open | |||
76 | complete: function () { | |||
77 | ||||
78 | console.log("EDIT MODAL CLOSED"); | |||
79 | ||||
80 | } // Callback for Modal close | |||
81 | }); | |||
82 | ||||
83 | }; | |||
84 | ||||
85 | ||||
86 | ||||
87 | Flashcard.prototype.refreshEditCardInput = function () { | |||
88 | ||||
89 | console.log("ASDFASDFASDFASFD"); | |||
90 | ||||
91 | ||||
92 | this.editCardText = $('#edit-card-input').text(); | |||
93 | ||||
94 | ||||
95 | this.submit_enabled = this.editCardText.length >= 5 && this.editCardText.length <= 160; | |||
96 | ||||
97 | ||||
98 | ||||
99 | var i = 0; | |||
100 | this.editCardBlanks = []; | |||
101 | $('#edit-card-input')[0].childNodes.forEach(function (node) { | |||
102 | node = $(node)[0]; | |||
103 | if (node.tagName == 'B') { | |||
104 | var text = $(node).text(); | |||
105 | var leftspaces = 0, rightspaces = 0; | |||
106 | // awful way to find the first non-space character from the left or the right. thanks.js | |||
107 | while (text[leftspaces] == ' ' || text[leftspaces] == '\xa0') leftspaces++; | |||
108 | while (text[text.length - 1 - rightspaces] == ' ' || text[text.length - 1 - rightspaces] == '\xa0') rightspaces++; | |||
109 | console.log(leftspaces, text.length); | |||
110 | if (leftspaces != text.length) $scope.editCardBlanks.push([i + leftspaces, i + text.length - rightspaces]); | |||
111 | i += text.length; | |||
112 | } else if (!node.data) { | |||
113 | i += $(node).text().length; | |||
114 | } else { | |||
115 | i += node.data.length; | |||
116 | } | |||
117 | }); | |||
118 | this.editCardBlanks.sort(function (a, b) { | |||
119 | return a[0] - b[0]; | |||
120 | }); | |||
121 | i = 0; | |||
122 | newtext = ''; | |||
123 | this.editCardBlanks.forEach(function (blank) { | |||
124 | newtext += this.editCardText.slice(i, blank[0]); | |||
125 | newtext += '<b>' + this.editCardText.slice(blank[0], blank[1]) + '</b>'; | |||
126 | i = blank[1]; | |||
127 | }); | |||
128 | newtext += this.editCardText.slice(i); | |||
129 | //$scope.newCardFormattedText = newtext;*/ | |||
130 | ||||
131 | ||||
132 | }; | |||
133 | ||||
134 | ||||
135 | ||||
136 | ||||
137 | Flashcard.prototype.pushCard = function () { | |||
138 | ||||
139 | //console.log() | |||
140 | ||||
141 | var myCard = { | |||
142 | 'text': $('#edit-card-input').text(), | |||
143 | 'mask': this.editCardBlanks, | |||
144 | //section: this.section.id | |||
145 | }; | |||
146 | if (myCard.text == '') { | |||
147 | console.log('blank flashcard not pushed:' + myCard.text); | |||
148 | return closeNewCard(); | |||
149 | } | |||
150 | $http.patch('/api/flashcards/' + this.id, myCard). | |||
151 | success(function (data) { | |||
152 | console.log('flashcard pushed: ' + myCard.text); | |||
153 | if (!UserService.hasVerifiedEmail()) { | |||
154 | Materialize.toast("<p>Thanks for contributing! However, others won't see your card until you verify your email address<p>", 4000); | |||
155 | } | |||
156 | }); | |||
157 | //return .closeNewCardModal(); | |||
158 | ||||
159 | } | |||
160 | ||||
161 | ||||
162 | ||||
Flashcard.prototype.edit = function () { | 57 | 163 | return Flashcard; | |
58 | 164 | }); | ||
59 | 165 | |||
var editableText = this.formatted_text; | 60 | |||
61 | ||||
//$('#flashcardEditText').html(this.formatted_text); | 62 | |||
63 | ||||
$('.modal-trigger').leanModal({ | 64 | |||
dismissible: true, // Modal can be dismissed by clicking outside of the modal | 65 | |||
opacity: .5, // Opacity of modal background | 66 | |||
in_duration: 300, // Transition in duration | 67 | |||
out_duration: 200, // Transition out duration | 68 | |||
ready: function () { | 69 | |||
70 | ||||
$('#edit-card-input').html(editableText); | 71 | |||
72 | ||||
73 | ||||
74 | ||||
}, // Callback for Modal open | 75 | |||
complete: function () { | 76 | |||
77 | ||||
console.log("EDIT MODAL CLOSED"); | 78 | |||
79 | ||||
} // Callback for Modal close | 80 | |||
}); | 81 | |||
82 | ||||
}; | 83 | |||
84 | ||||
85 | ||||
86 | ||||
Flashcard.prototype.refreshEditCardInput = function () { | 87 | |||
88 | ||||
console.log("ASDFASDFASDFASFD"); | 89 | |||
90 | ||||
91 | ||||
this.editCardText = $('#edit-card-input').text(); | 92 | |||
93 | ||||
94 | ||||
this.submit_enabled = this.editCardText.length >= 5 && this.editCardText.length <= 160; | 95 | |||
96 | ||||
97 | ||||
98 | ||||
var i = 0; | 99 | |||
this.editCardBlanks = []; | 100 | |||
$('#edit-card-input')[0].childNodes.forEach(function (node) { | 101 | |||
node = $(node)[0]; | 102 | |||
if (node.tagName == 'B') { | 103 | |||
var text = $(node).text(); | 104 | |||
var leftspaces = 0, rightspaces = 0; | 105 | |||
// awful way to find the first non-space character from the left or the right. thanks.js | 106 | |||
while (text[leftspaces] == ' ' || text[leftspaces] == '\xa0') leftspaces++; | 107 | |||
while (text[text.length - 1 - rightspaces] == ' ' || text[text.length - 1 - rightspaces] == '\xa0') rightspaces++; | 108 | |||
console.log(leftspaces, text.length); | 109 | |||
if (leftspaces != text.length) $scope.editCardBlanks.push([i + leftspaces, i + text.length - rightspaces]); | 110 | |||
i += text.length; | 111 | |||
} else if (!node.data) { | 112 | |||
i += $(node).text().length; | 113 | |||
} else { | 114 | |||
i += node.data.length; | 115 | |||
} | 116 | |||
}); | 117 | |||
this.editCardBlanks.sort(function (a, b) { | 118 | |||
return a[0] - b[0]; | 119 | |||
}); | 120 | |||
i = 0; | 121 | |||
newtext = ''; | 122 | |||
this.editCardBlanks.forEach(function (blank) { | 123 | |||
newtext += this.editCardText.slice(i, blank[0]); | 124 | |||
newtext += '<b>' + this.editCardText.slice(blank[0], blank[1]) + '</b>'; | 125 | |||
i = blank[1]; | 126 | |||
}); | 127 | |||
newtext += this.editCardText.slice(i); | 128 | |||
//$scope.newCardFormattedText = newtext;*/ | 129 |
templates/flashcard.html
View file @
0c0dbdc
1 | <div class="card flashy smallify black-text text-darken-2" ng-class="{'in-deck':flashcard.isInDeck()}"> | |||
2 | ||||
<div class="card flashy smallify black-text text-darken-2" ng-class="{'in-deck':flashcard.isInDeck()}"> | 1 | 3 | <div class="card flashy black-text" | |
2 | 4 | ng-class="{'in-deck':flashcard.isInDeck()}"> | ||
<div class="card flashy black-text" | 3 | 5 | <div class="valign-wrapper"> | |
ng-class="{'in-deck':flashcard.isInDeck()}"> | 4 | 6 | <div class="card-content valign center-align" ng-bind-html="flashcard.formatted_text"></div> | |
<div class="valign-wrapper"> | 5 | 7 | </div> | |
8 | ||||
9 | ||||
10 | ||||
11 | ||||
12 | ||||
<div class="card-content valign center-align" ng-bind-html="flashcard.formatted_text"></div> | 6 | 13 | <div class="card-overlay"> | |
</div> | 7 | 14 | <div class="top-box no-user-select" | |
8 | 15 | ng-click="flashcard.pullUnpull()"> | ||
9 | 16 | <div class="center-me"> | ||
10 | 17 | <i ng-if="flashcard.isInDeck()" class="fadey mdi-content-remove-circle-outline medium"></i> | ||
11 | 18 | <i ng-if="!flashcard.isInDeck()" class="fadey mdi-content-add-circle-outline medium"></i> | ||
12 | 19 | </div> | ||
<div class="card-overlay"> | 13 | 20 | </div> | |
<div class="top-box no-user-select" | 14 | 21 | <div class="bottom-box no-user-select"> | |
ng-click="flashcard.pullUnpull()"> | 15 | 22 | ||
<div class="center-me"> | 16 | 23 | ||
24 | <div class="left-box tooltipped" data-position=" bottom" data-tooltip="Info"> | |||
25 | <div class="center-me modal-trigger" href="#editModal" ng-click="flashcard.edit()"><i class="mdi-editor-border-color small"></i></div> | |||
<i ng-if="flashcard.isInDeck()" class="fadey mdi-content-remove-circle-outline medium"></i> | 17 | 26 | </div> | |
27 | ||||
28 | ||||
29 | ||||
30 | ||||
<i ng-if="!flashcard.isInDeck()" class="fadey mdi-content-add-circle-outline medium"></i> | 18 | 31 | <div class="right-box tooltipped" ng-click="flashcard.hide()" data-position="bottom" data-tooltip="Hide"> | |
</div> | 19 | 32 | <div class="center-me"><i class="mdi-action-delete small"></i></div> | |
</div> | 20 | 33 | </div> | |
<div class="bottom-box no-user-select"> | 21 | 34 | ||
22 | 35 | </div> | ||
23 | 36 | </div> | ||
37 | ||||
38 | ||||
39 | <!--<div id="editModal" class="modal"> | |||
40 | <div class="modal-content"> | |||
41 | <h4 id="flashcardEditText"></h4> | |||
42 | </div> | |||
43 | <div class="modal-footer"> | |||
44 | ||||
45 | </div> | |||
46 | </div>--> | |||
47 | ||||
48 | ||||
49 | ||||
50 | <div id="editModal" class="modal row" style="max-height:none;"> | |||
51 | <form id="edit-card-form"> | |||
52 | <div class="modal-content col"> | |||
53 | <div class="row" style="margin-bottom:0"> | |||
54 | <div class="card cyan-text text-darken-2" | |||
55 | style="width:300px; height:180px; margin-bottom:0; font-size:120%;"> | |||
56 | <div class="valign-wrapper"> | |||
57 | <div id="edit-card-input" ng-model="newCardFormattedText" style="outline:0px solid transparent;" | |||
58 | class="card-content valign center-align" | |||
59 | contenteditable select-non-editable="true" ng-change="flashcard.refreshEditCardInput()"> | |||
60 | </div> | |||
61 | </div> | |||
62 | </div> | |||
63 | </div> | |||
64 | </div> | |||
65 | <div class="col"> | |||
66 | <div class="row"> | |||
67 | </div> | |||
68 | <div class="row"> | |||
69 | <button class="btn modal-close tooltipped" type="submit" ng-click="flashcard.pushCard()" | |||
70 | data-position="left" | |||
71 | data-delay="50" ng-class="flashcard.submit_enabled?{}:'disabled'" | |||
72 | data-tooltip="Enter"> | |||
73 | Edit | |||
74 | <i class="mdi-hardware-keyboard-return right"></i> | |||
75 | </button> | |||
76 | </div> | |||
77 | <div class="row"> | |||
78 | <button id="blank-selected" style="float:left" class="btn tooltipped" data-position="right" data-delay="50" | |||
79 | data-tooltip="Ctrl-B"> | |||
80 | Blank Selected Text | |||
81 | </button> | |||
82 | </div> | |||
83 | <div class="row" ng-show="flashcard.editCardText" ng-style="(flashcard.editCardText.length>160)?{color:'red'}:{}"> | |||
84 | {{flashcard.editCardText.length}}/160 characters | |||
85 | </div> | |||
86 | <div class="row" ng-show="flashcard.editCardText.length < 5"> | |||
87 | Please write a little more! | |||
88 | </div> | |||
89 | <div class="row" ng-show="flashcard.editCardText.length > 140"> | |||
90 | Good flashcards have a<br> | |||
91 | single atomic fact | |||
92 | </div> | |||
93 | </div> | |||
94 | </form> | |||
95 | </div> | |||
96 | ||||
97 | ||||
98 | ||||
99 | ||||
100 | ||||
101 | ||||
102 | ||||
<div class="left-box tooltipped" data-position=" bottom" data-tooltip="Info"> | 24 | 103 | <div ng-show="flashcard.isInDeck()" class="green-text" style="position:absolute; top:-9px;right:0px"> | |
<div class="center-me modal-trigger" href="#editModal" ng-click="flashcard.edit()"><i class="mdi-editor-border-color small"></i></div> | 25 | 104 | <div class="center-me tooltipped" data-position="bottom" data-tooltip="In deck"><i | |
</div> | 26 | 105 | class="mdi-action-done small"></i></div> | |
27 | 106 | </div> | ||
28 | 107 | <div ng-show="false" style="position:absolute; bottom:0px; right:5px;"> | ||
29 | 108 | <span class="center-me">score:{{flashcard.score}}</span> | ||
30 | 109 | </div> | ||
110 | ||||
111 | ||||
112 | ||||
113 | ||||
114 | ||||
<div class="right-box tooltipped" ng-click="flashcard.hide()" data-position="bottom" data-tooltip="Hide"> | 31 | 115 | </div> | |
<div class="center-me"><i class="mdi-action-delete small"></i></div> | 32 | 116 | ||
</div> | 33 | |||
34 | ||||
</div> | 35 | |||
</div> | 36 | |||
37 | ||||
38 | ||||
<!--<div id="editModal" class="modal"> | 39 | |||
<div class="modal-content"> | 40 | |||
<h4 id="flashcardEditText"></h4> | 41 | |||
</div> | 42 | |||
<div class="modal-footer"> | 43 | |||
44 | ||||
</div> | 45 | |||
</div>--> | 46 | |||
47 | ||||
48 | ||||
49 | ||||
<div id="editModal" class="modal row" style="max-height:none;"> | 50 | |||
<form id="edit-card-form"> | 51 | |||
<div class="modal-content col"> | 52 | |||
<div class="row" style="margin-bottom:0"> | 53 | |||
<div class="card cyan-text text-darken-2" | 54 | |||
style="width:300px; height:180px; margin-bottom:0; font-size:120%;"> | 55 | |||
<div class="valign-wrapper"> | 56 | |||
<div id="edit-card-input" ng-model="newCardFormattedText" style="outline:0px solid transparent;" | 57 | |||
class="card-content valign center-align" | 58 | |||
contenteditable select-non-editable="true" ng-change="flashcard.refreshEditCardInput()"> | 59 | |||
</div> | 60 | |||
</div> | 61 | |||
</div> | 62 | |||
</div> | 63 | |||
</div> | 64 | |||
<div class="col"> | 65 | |||
<div class="row"> | 66 | |||
</div> | 67 | |||
<div class="row"> | 68 | |||
<button class="btn modal-close tooltipped" type="submit" ng-click="flashcard.pushCard()" | 69 | |||
data-position="left" | 70 | |||
data-delay="50" ng-class="flashcard.submit_enabled?{}:'disabled'" | 71 | |||
data-tooltip="Enter"> | 72 | |||
Edit | 73 | |||
<i class="mdi-hardware-keyboard-return right"></i> | 74 | |||
</button> | 75 | |||
</div> | 76 | |||
<div class="row"> | 77 | |||
<button id="blank-selected" style="float:left" class="btn tooltipped" data-position="right" data-delay="50" | 78 | |||
data-tooltip="Ctrl-B"> | 79 | |||
Blank Selected Text | 80 | |||
</button> | 81 | |||
</div> | 82 | |||
<div class="row" ng-show="flashcard.editCardText" ng-style="(flashcard.editCardText.length>160)?{color:'red'}:{}"> | 83 | |||
{{flashcard.editCardText.length}}/160 characters | 84 | |||
</div> | 85 | |||
<div class="row" ng-show="flashcard.editCardText.length < 5"> | 86 |