Compare View

switch
from
...
to
 
Commits (3)

Diff

Showing 4 changed files Side-by-side Diff

scripts/FeedController.js View file @ 0c0dbdc
... ... @@ -0,0 +1,208 @@
  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 + });
0 209 \ No newline at end of file
scripts/FlashcardDirective.js View file @ 0c0dbdc
1 1 angular.module('flashy.FlashcardDirective', []).
2 2  
3 3 directive('flashcard',
4   - function($http, $state, $window) {
  4 +
  5 +
  6 + function($http, $state, $window) {
5 7 return {
6   - templateUrl: '/app/templates/flashcard.html',
7   - restrict: 'E',
8   - scope: {
9   - flashcard: '=flashcardObj', // flashcard-obj in parent html
10   - refresh: '&' // eval refresh in parent html
11   - },
12   - colNum: 0,
13   - colRank: 0,
14   - //link: function(scope, element) {
15   - // $('.tooltipped').tooltip();
16   - // /* Handles width of the card */
17   - //}
  8 + templateUrl: '/app/templates/flashcard.html',
  9 + restrict: 'E',
  10 + scope: {
  11 + flashcard: '=flashcardObj', // flashcard-obj in parent html
  12 + refresh: '&' // eval refresh in parent html
  13 + },
  14 + colNum: 0,
  15 + colRank: 0,
  16 + link: function(scope, element) {
  17 + $('.tooltipped').tooltip();
  18 + // /* Handles width of the card */
  19 + }
18 20 };
19   - }
  21 + }
  22 +
20 23 );
21   -
22 24 \ No newline at end of file
  25 +
scripts/FlashcardFactory.js View file @ 0c0dbdc
1 1 angular.module('flashy.FlashcardFactory', ['ui.router']).
2   - factory('Flashcard', function ($http) {
  2 + factory('Flashcard', function ($http, UserService) {
3 3 var FlashcardCache = [];
4 4 var Deck = null;
5 5 var Flashcard = function (data) {
... ... @@ -54,5 +54,111 @@ angular.module(&#39;flashy.FlashcardFactory&#39;, [&#39;ui.router&#39;]).
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 +
57 163 return Flashcard;
58 164 });
templates/flashcard.html View file @ 0c0dbdc
  1 +<div class="card flashy smallify black-text text-darken-2" ng-class="{'in-deck':flashcard.isInDeck()}">
  2 +
1 3 <div class="card flashy black-text"
2 4 ng-class="{'in-deck':flashcard.isInDeck()}">
3 5 <div class="valign-wrapper">
4 6 <div class="card-content valign center-align" ng-bind-html="flashcard.formatted_text"></div>
5 7 </div>
  8 +
  9 +
  10 +
  11 +
  12 +
6 13 <div class="card-overlay">
7 14 <div class="top-box no-user-select"
8 15 ng-click="flashcard.pullUnpull()">
... ... @@ -12,15 +19,87 @@
12 19 </div>
13 20 </div>
14 21 <div class="bottom-box no-user-select">
15   - <div class="left-box tooltipped" data-position="bottom" data-tooltip="Info">
16   - <div class="center-me"><i class="mdi-action-info-outline small"></i></div>
  22 +
  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>
17 26 </div>
  27 +
  28 +
  29 +
  30 +
18 31 <div class="right-box tooltipped" ng-click="flashcard.hide()" data-position="bottom" data-tooltip="Hide">
19 32 <div class="center-me"><i class="mdi-action-delete small"></i></div>
20 33 </div>
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 +
24 103 <div ng-show="flashcard.isInDeck()" class="green-text" style="position:absolute; top:-9px;right:0px">
25 104 <div class="center-me tooltipped" data-position="bottom" data-tooltip="In deck"><i
26 105 class="mdi-action-done small"></i></div>
... ... @@ -28,4 +107,9 @@
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 +
31 115 </div>