Commit 70c2390ab2ab4ab836af59bbc1c2284d4ab7ff87

Authored by Andrew Buss
1 parent 80b664e098

unbreak deck, cardlist next

Showing 8 changed files with 142 additions and 151 deletions Inline Diff

<!DOCTYPE html> 1 1 <!DOCTYPE html>
<html ng-app="flashy"> 2 2 <html ng-app="flashy">
<base href="/app/"> 3 3 <base href="/app/">
<head> 4 4 <head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"/> 5 5 <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"/>
<link rel="stylesheet" 6 6 <link rel="stylesheet"
href="https://ajax.googleapis.com/ajax/libs/angular_material/0.9.0/angular-material.min.css"> 7 7 href="https://ajax.googleapis.com/ajax/libs/angular_material/0.9.0/angular-material.min.css">
<link rel="shortcut icon" href="flashy.ico"> 8 8 <link rel="shortcut icon" href="flashy.ico">
9 9
<link rel="stylesheet" href="styles/flashier.css"/> 10 10 <link rel="stylesheet" href="styles/flashier.css"/>
<link rel="stylesheet" href="styles/flashy.css"/> 11 11 <link rel="stylesheet" href="styles/flashy.css"/>
<link rel="manifest" href="manifest.json"> 12 12 <link rel="manifest" href="manifest.json">
<link 13 13 <link
href='https://fonts.googleapis.com/css?family=Satisfy|Titillium+Web:400,200,200italic,300,600,700,900,700italic,600italic,400italic,300italic' 14 14 href='https://fonts.googleapis.com/css?family=Satisfy|Titillium+Web:400,200,200italic,300,600,700,900,700italic,600italic,400italic,300italic'
rel='stylesheet' type='text/css'> 15 15 rel='stylesheet' type='text/css'>
<title>Flashy</title> 16 16 <title>Flashy</title>
</head> 17 17 </head>
<body ng-controller="RootController"> 18 18 <body ng-controller="RootController">
<header> 19 19 <header>
<nav> 20 20 <nav>
<div class="nav-wrapper"> 21 21 <div class="nav-wrapper">
<a ng-show="UserService.isLoggedIn()" href="#" data-activates="mobile-demo" 22 22 <a ng-show="UserService.isLoggedIn()" href="#" data-activates="mobile-demo"
class="left button-collapse hide-on-med-and-up"><i 23 23 class="left button-collapse hide-on-med-and-up"><i
class="mdi-navigation-menu"></i></a> 24 24 class="mdi-navigation-menu"></i></a>
25 25
<!-- User's classes dropdown --> 26 26 <!-- User's classes dropdown -->
<ul id="classDropdown" class="dropdown-content"> 27 27 <ul id="classDropdown" class="dropdown-content">
<li ui-sref-active="active" ng-repeat="section in UserService.getUserData().sections"> 28 28 <li ui-sref-active="active" ng-repeat="section in UserService.getUserData().sections">
<a ui-sref="feed({sectionId:section.id})">{{section.short_name}}</a> 29 29 <a ui-sref="feed({sectionId:section.id})">{{section.short_name}}</a>
</li> 30 30 </li>
<li class="divider"></li> 31 31 <li class="divider"></li>
<li><a ui-sref="addclass">Add Class</a></li> 32 32 <li><a ui-sref="addclass">Add Class</a></li>
</ul> 33 33 </ul>
<ul ng-show="UserService.isLoggedIn()" class="left hide-on-small-and-down"> 34 34 <ul ng-show="UserService.isLoggedIn()" class="left hide-on-small-and-down">
<li><a style="font-size:20px; font-weight:700;" class="dropdown-button ng-cloak hide-on-small-and-down" 35 35 <li><a style="font-size:20px; font-weight:700;" class="dropdown-button ng-cloak hide-on-small-and-down"
href="#!" id="class-list" 36 36 href="#!" id="class-list"
data-activates="classDropdown" data-beloworigin="true">{{currentSection.id?currentSection.short_name:"Classes"}}<i 37 37 data-activates="classDropdown" data-beloworigin="true">{{currentSection.id?currentSection.short_name:"Classes"}}<i
class="mdi-navigation-arrow-drop-down right"></i></a></li> 38 38 class="mdi-navigation-arrow-drop-down right"></i></a></li>
<li ng-show="currentSection.id" ui-sref-active="active"><a ui-sref="feed({sectionId:currentSection.id})" 39 39 <li ng-show="currentSection.id" ui-sref-active="active"><a ui-sref="feed({sectionId:currentSection.id})"
class="tooltipped" 40 40 class="tooltipped"
data-position="bottom" 41 41 data-position="bottom"
data-delay="50" data-tooltip="Feed"><i 42 42 data-delay="50" data-tooltip="Feed"><i
class="mdi-action-view-module"></i></a></li> 43 43 class="mdi-action-view-module"></i></a></li>
<li ng-show="currentSection.id" ui-sref-active="active" id="class-list"><a ui-sref="deck({sectionId:currentSection.id})" 44 44 <li ng-show="currentSection.id" ui-sref-active="active" id="class-list"><a ui-sref="deck({sectionId:currentSection.id})"
class="tooltipped" 45 45 class="tooltipped"
data-position="bottom" 46 46 data-position="bottom"
data-delay="50" data-tooltip="Deck"><i 47 47 data-delay="50" data-tooltip="Deck"><i
class="mdi-action-view-carousel"></i></a></li> 48 48 class="mdi-action-view-carousel"></i></a></li>
<li ng-show="currentSection.id" ui-sref-active="active"><a ui-sref="cardlist({sectionId:currentSection.id})" 49 49 <li ng-show="currentSection.id" ui-sref-active="active"><a ui-sref="cardlist({sectionId:currentSection.id})"
class="tooltipped" 50 50 class="tooltipped"
data-position="bottom" 51 51 data-position="bottom"
data-delay="50" data-tooltip="Card List"><i 52 52 data-delay="50" data-tooltip="Card List"><i
class="mdi-action-view-list"></i></a></li> 53 53 class="mdi-action-view-list"></i></a></li>
</ul> 54 54 </ul>
<a href="#" class="brand-logo center">Flashy</a> 55 55 <a href="#" class="brand-logo center">Flashy</a>
56 56
<ul ng-show="UserService.isLoggedIn()" ng-cloak id="nav-mobile" class="right hide-on-small-and-down"> 57 57 <ul ng-show="UserService.isLoggedIn()" ng-cloak id="nav-mobile" class="right hide-on-small-and-down">
58 58
<li ui-sref-active="active"><a ui-sref="study" class="tooltipped" data-position="bottom" data-delay="50" 59 59 <li ui-sref-active="active"><a ui-sref="study" class="tooltipped" data-position="bottom" data-delay="50"
data-tooltip="Study"> 60 60 data-tooltip="Study">
<i class="tiny mdi-action-pageview"></i></a></li> 61 61 <i class="tiny mdi-action-pageview"></i></a></li>
62 62
<!-- Settings Dropdown --> 63 63 <!-- Settings Dropdown -->
<ul id="settingsDropdown" class="dropdown-content"> 64 64 <ul id="settingsDropdown" class="dropdown-content">
65 65
66 66
</ul> 67 67 </ul>
68 68
<li ui-sref-active="active"><a ui-sref="help"><i class="tiny mdi-action-help tooltipped" 69 69 <li ui-sref-active="active"><a ui-sref="help"><i class="tiny mdi-action-help tooltipped"
data-position="bottom" 70 70 data-position="bottom"
data-delay="50" data-tooltip="Help"></i></a></li> 71 71 data-delay="50" data-tooltip="Help"></i></a></li>
<li ui-sref-active="active"><a ui-sref="settings"><i data-position="bottom" data-delay="50" 72 72 <li ui-sref-active="active"><a ui-sref="settings"><i data-position="bottom" data-delay="50"
data-tooltip="Settings" 73 73 data-tooltip="Settings"
class="mdi-action-settings tooltipped"></i></a></li> 74 74 class="mdi-action-settings tooltipped"></i></a></li>
<li><a ng-click="logout()" ui-sref="login"><i data-position="bottom" data-delay="50" data-tooltip="Logout" 75 75 <li><a ng-click="logout()" ui-sref="login"><i data-position="bottom" data-delay="50" data-tooltip="Logout"
class="mdi-content-forward tooltipped"></i></a></li> 76 76 class="mdi-content-forward tooltipped"></i></a></li>
77 77
78 78
</ul> 79 79 </ul>
80 80
<!-- Slide-in side-nav for small screens --> 81 81 <!-- Slide-in side-nav for small screens -->
<ul ng-show="UserService.isLoggedIn()" class="side-nav" id="mobile-demo"> 82 82 <ul ng-show="UserService.isLoggedIn()" class="side-nav" id="mobile-demo">
<span ng-show="currentSection.id"> 83 83 <span ng-show="currentSection.id">
<li ui-sref-active="active"><a ui-sref="feed({sectionId:currentSection.id})"> 84 84 <li ui-sref-active="active"><a ui-sref="feed({sectionId:currentSection.id})">
<i class="mdi-action-view-module left"></i> 85 85 <i class="mdi-action-view-module left"></i>
Feed</a> 86 86 Feed</a>
</li> 87 87 </li>
<li ui-sref-active="active"><a ui-sref="deck({sectionId:currentSection.id})"> 88 88 <li ui-sref-active="active"><a ui-sref="deck({sectionId:currentSection.id})">
<i class="mdi-action-view-carousel left"> </i> 89 89 <i class="mdi-action-view-carousel left"> </i>
Deck 90 90 Deck
</a> 91 91 </a>
</li> 92 92 </li>
<li ui-sref-active="active"><a ui-sref="cardlist({sectionId:currentSection.id})"> 93 93 <li ui-sref-active="active"><a ui-sref="cardlist({sectionId:currentSection.id})">
<i class="mdi-action-view-list left"></i> 94 94 <i class="mdi-action-view-list left"></i>
Card List 95 95 Card List
</a> 96 96 </a>
</li> 97 97 </li>
<hr> 98 98 <hr>
</span> 99 99 </span>
<!-- Collapsible menu for all the User's classes --> 100 100 <!-- Collapsible menu for all the User's classes -->
<ul class="collapsible" data-collapsible="accordion" > 101 101 <ul class="collapsible" data-collapsible="accordion" >
<li class="bold"> 102 102 <li class="bold">
<a class="collapsible-header black-text"> 103 103 <a class="collapsible-header black-text">
Classes 104 104 Classes
<i class="mdi-navigation-arrow-drop-down right"></i> 105 105 <i class="mdi-navigation-arrow-drop-down right"></i>
</a> 106 106 </a>
</li> 107 107 </li>
<div class="collapsible-body" style="display: block"> 108 108 <div class="collapsible-body" style="display: block">
<ul> 109 109 <ul>
<li ui-sref-active="active" ng-repeat="section in UserService.getUserData().sections"> 110 110 <li ui-sref-active="active" ng-repeat="section in UserService.getUserData().sections">
<a class="class bold" ui-sref="feed({sectionId:section.id})">{{section.short_name}}</a> 111 111 <a class="class bold" ui-sref="feed({sectionId:section.id})">{{section.short_name}}</a>
</li> 112 112 </li>
<hr> 113 113 <hr>
<li><a ui-sref="addclass"><i class="tiny mdi-content-add">Add Class</i></a></li> 114 114 <li><a ui-sref="addclass"><i class="tiny mdi-content-add">Add Class</i></a></li>
</ul> 115 115 </ul>
</div> 116 116 </div>
</ul> 117 117 </ul>
<li><a ui-sref="study">Study</a></li> 118 118 <li><a ui-sref="study">Study</a></li>
<li><a ui-sref="settings">Settings</a></li> 119 119 <li><a ui-sref="settings">Settings</a></li>
<li><a ng-click="logout()">Logout</a></li> 120 120 <li><a ng-click="logout()">Logout</a></li>
</ul> 121 121 </ul>
</div> 122 122 </div>
</nav> 123 123 </nav>
124 124
</header> 125 125 </header>
126 126
127 127
<!-- Menu Bar --> 128 128 <!-- Menu Bar -->
<main ui-view></main> 129 129 <main ui-view></main>
130 130
131 131
<!--<footer class="page-footer">--> 132 132 <!--<footer class="page-footer">-->
<!--<div class="footer-copyright">--> 133 133 <!--<div class="footer-copyright">-->
<!--<div class="container">--> 134 134 <!--<div class="container">-->
<!--&copy; 2015 Team Swag--> 135 135 <!--&copy; 2015 Team Swag-->
<!--<a class="grey-text text-lighten-4 right" id="contact" href="mailto:halp@flashy.cards">Concerns? Contact us by--> 136 136 <!--<a class="grey-text text-lighten-4 right" id="contact" href="mailto:halp@flashy.cards">Concerns? Contact us by-->
<!--email!</a>--> 137 137 <!--email!</a>-->
<!--</div>--> 138 138 <!--</div>-->
139 139
<!--</div>--> 140 140 <!--</div>-->
<!--</footer>--> 141 141 <!--</footer>-->
142 142
</body> 143 143 </body>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.js"></script> 144 144 <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.14/angular-ui-router.js"></script> 145 145 <script src="//cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.14/angular-ui-router.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular-cookies.js"></script> 146 146 <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular-cookies.js"></script>
<script src="//code.jquery.com/jquery-2.1.4.min.js"></script> 147 147 <script src="//code.jquery.com/jquery-2.1.4.min.js"></script>
<script type="text/javascript" src="scripts/materialize.js"></script> 148 148 <script type="text/javascript" src="scripts/materialize.js"></script>
<script type="text/javascript" src="scripts/jquery.collapsible.js"></script> 149 149 <script type="text/javascript" src="scripts/jquery.collapsible.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angular_material/0.9.0/angular-material.min.js"></script> 150 150 <script src="https://ajax.googleapis.com/ajax/libs/angular_material/0.9.0/angular-material.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular-animate.min.js"></script> 151 151 <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular-animate.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular-aria.min.js"></script> 152 152 <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular-aria.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular-resource.min.js"></script> 153 153 <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular-resource.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular-sanitize.js"></script> 154 154 <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular-sanitize.js"></script>
<script src="static/js/angular-websocket.js"></script> 155 155 <script src="static/js/angular-websocket.js"></script>
<script src="static/js/angular-contenteditable.js"></script> 156 156 <script src="static/js/angular-contenteditable.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-filter/0.5.4/angular-filter.js"></script> 157 157 <script src="https://cdnjs.cloudflare.com/ajax/libs/angular-filter/0.5.4/angular-filter.js"></script>
158 158
159 159
<script src="config.js"></script> 160 160 <script src="config.js"></script>
161 161
<script src="scripts/FlashcardFactory.js"></script> 162 162 <script src="scripts/FlashcardFactory.js"></script>
163 <script src="scripts/DeckFactory.js"></script>
163 164
scripts/CardGridController.js View file @ 70c2390
angular.module('flashy.CardGridController', ['ui.router', 'ngAnimate', 'ngWebSocket']).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) { 2 2 function($scope, $rootScope, $state, $http, $window, $timeout, $stateParams, $websocket, $interval, UserService, Flashcard, Deck) {
$scope.cards = []; // all cards 3 3 $scope.cards = []; // all cards
$scope.deck = []; 4
$scope.cardCols = []; // organized data 5 4 $scope.cardCols = []; // organized data
$scope.cardColsShow = []; // displayed data 6 5 $scope.cardColsShow = []; // displayed data
$scope.numCols = 0; 7 6 $scope.numCols = 0;
$scope.cardTable = {}; // look up table of cards: {'colNum':col, 'obj':card} 8 7 $scope.cardTable = {}; // look up table of cards: {'colNum':col, 'obj':card}
$scope.sectionId = parseInt($stateParams.sectionId); 9 8 $scope.sectionId = parseInt($stateParams.sectionId);
$scope.section = $rootScope.SectionResource.get({sectionId: $scope.sectionId}); 10 9 $scope.section = $rootScope.SectionResource.get({sectionId: $scope.sectionId});
10 $scope.deck = new Deck($scope.sectionId, {
11 cardHideCallback: function(card) {
12 $scope.hideCardFromGrid(card);
13 }
14 });
15
$scope.showGrid = false; 11 16 $scope.showGrid = false;
//$scope.moveQueue = []; // queue of flashcard objects 12 17 //$scope.moveQueue = []; // queue of flashcard objects
$rootScope.currentSection = $scope.section; 13 18 $rootScope.currentSection = $scope.section;
14 19
if (!UserService.isInSection($scope.sectionId)) { 15 20 if (!UserService.isInSection($scope.sectionId)) {
console.log('user is not enrolled in ' + $scope.sectionId); 16 21 console.log('user is not enrolled in ' + $scope.sectionId);
$state.go('addclass'); 17 22 $state.go('addclass');
} 18 23 }
19 24
$scope.refreshColumnWidth = function() { 20 25 $scope.refreshColumnWidth = function() {
avail = $window.innerWidth - 17; 21 26 avail = $window.innerWidth - 17;
width = Math.floor(avail / Math.floor(avail / 250)); 22 27 width = Math.floor(avail / Math.floor(avail / 250));
$('.cardColumn').css({ 23 28 $('.cardColumn').css({
width: width + 'px', 24 29 width: width + 'px',
'font-size': 100 * width / 250 + '%' 25 30 'font-size': 100 * width / 250 + '%'
}); 26 31 });
$('.cardColumn .card.flashy').css({ 27 32 $('.cardColumn .card.flashy').css({
width: width - 12 + 'px', 28 33 width: width - 12 + 'px',
height: (width * 3 / 5) + 'px' 29 34 height: (width * 3 / 5) + 'px'
}); 30 35 });
}; 31 36 };
$scope.refreshLayout = function() { 32 37 $scope.refreshLayout = function() {
numCols = Math.max(1, Math.floor(($window.innerWidth - 17) / 250)); 33 38 numCols = Math.max(1, Math.floor(($window.innerWidth - 17) / 250));
34 39
// check if we actually need to refresh the whole layout 35 40 // check if we actually need to refresh the whole layout
if (numCols == $scope.numCols) return $scope.refreshColumnWidth(); 36 41 if (numCols == $scope.numCols) return $scope.refreshColumnWidth();
$scope.numCols = numCols; 37 42 $scope.numCols = numCols;
console.log('refreshing layout for ' + numCols + ' columns'); 38 43 console.log('refreshing layout for ' + numCols + ' columns');
$scope.cardCols = []; 39 44 $scope.cardCols = [];
var cols = []; 40 45 var cols = [];
for (var i = 0; i < numCols; i++) cols.push([]); 41 46 for (var i = 0; i < numCols; i++) cols.push([]);
var n = 0; 42 47 var n = 0;
$scope.cards.forEach(function(card, j) { 43 48 $scope.cards.forEach(function(card, j) {
card.colNum = n++ % numCols; 44 49 card.colNum = n++ % numCols;
cols[card.colNum].push(card); 45 50 cols[card.colNum].push(card);
}); 46 51 });
for (i in cols) $scope.updateColRanks(cols[i]); 47 52 for (i in cols) $scope.updateColRanks(cols[i]);
console.log(cols); 48 53 console.log(cols);
return $timeout(function() { 49 54 return $timeout(function() {
$scope.cardCols = cols; 50 55 $scope.cardCols = cols;
$timeout($scope.refreshColumnWidth); 51 56 $timeout($scope.refreshColumnWidth);
}); 52 57 });
53 58
}; 54 59 };
55 60
angular.element($window).bind('resize', $scope.refreshLayout); 56 61 angular.element($window).bind('resize', $scope.refreshLayout);
57 62
$scope.ws_host = window.location.origin.replace('http', 'ws'); 58
$scope.deck_ws = $websocket($scope.ws_host + '/ws/deck/' + $scope.sectionId + '?subscribe-user'); 59
$scope.deck_ws.onOpen(function() { 60
console.log('deck ws open'); 61
}); 62
63
$scope.deck_ws.onMessage(function(message) { 64
data = JSON.parse(message.data); 65
console.log('message', data); 66
card = new Flashcard(data.flashcard); 67
if (data.event_type == 'card_pulled') { 68
$scope.deck[card.id] = card; 69
if ($scope.deckPullCallback) $scope.deckPullCallback(card); 70
} 71
if (data.event_type == 'card_unpulled') { 72
$scope.deck[card.id] = undefined; 73
if ($scope.deckUnpullCallback) $scope.deckUnpullCallback(card); 74
} 75
if (data.event_type == 'card_hidden') { 76
$scope.hideCardFromGrid(card); 77
} 78
}); 79
80
$scope.cardInDeck = function(id) { 81
return $scope.deck[id]; 82
}; 83
$scope.addCardToGrid = function(card) { 84 63 $scope.addCardToGrid = function(card) {
var colNum = 0; 85 64 var colNum = 0;
var lowestCol = $scope.cardCols[0]; 86 65 var lowestCol = $scope.cardCols[0];
var lowestColNum = 0; 87 66 var lowestColNum = 0;
while (colNum < $scope.numCols) { 88 67 while (colNum < $scope.numCols) {
if ($scope.cardCols[colNum].length == 0) { 89 68 if ($scope.cardCols[colNum].length == 0) {
lowestCol = $scope.cardCols[colNum]; 90 69 lowestCol = $scope.cardCols[colNum];
break; 91 70 break;
} else if ($scope.cardCols[colNum].length < lowestCol.length) { 92 71 } else if ($scope.cardCols[colNum].length < lowestCol.length) {
lowestCol = $scope.cardCols[colNum]; 93 72 lowestCol = $scope.cardCols[colNum];
lowestColNum = colNum; 94 73 lowestColNum = colNum;
lowestColLen = $scope.cardCols[colNum].length; 95 74 lowestColLen = $scope.cardCols[colNum].length;
} 96 75 }
colNum++; 97 76 colNum++;
} 98 77 }
console.log(card); 99 78 console.log(card);
$scope.cards.push(data); 100 79 $scope.cards.push(data);
lowestCol.unshift(card); 101 80 lowestCol.unshift(card);
card.colNum = lowestColNum; 102 81 card.colNum = lowestColNum;
$scope.updateColRanks(lowestCol); 103 82 $scope.updateColRanks(lowestCol);
$timeout($scope.refreshColumnWidth); 104 83 $timeout($scope.refreshColumnWidth);
105 84
}; 106 85 };
107 86
$scope.updateColRanks = function(col) { 108 87 $scope.updateColRanks = function(col) {
for (i in col) 109 88 for (i in col)
col[i].colRank = parseInt(i); 110 89 col[i].colRank = parseInt(i);
}; 111 90 };
112 91
$scope.hideCardFromGrid = function(card) { 113 92 $scope.hideCardFromGrid = function(card) {
console.log('hiding', card); 114 93 console.log('hiding', card);
$scope.cardCols[card.colNum].splice(card.colRank, 1); 115 94 $scope.cardCols[card.colNum].splice(card.colRank, 1);
$scope.updateColRanks($scope.cardCols[card.colNum]); 116 95 $scope.updateColRanks($scope.cardCols[card.colNum]);
console.log($scope.cardCols); 117 96 console.log($scope.cardCols);
}; 118 97 };
119 98
$scope.$on('$destroy', function() { 120 99 $scope.$on('$destroy', function() {
$scope.deck_ws.close(); 121 100 $scope.deck.cleanup();
$rootScope.currentSection = {}; 122 101 $rootScope.currentSection = {};
$(document).off('keydown'); 123 102 $(document).off('keydown');
scripts/CardListController.js View file @ 70c2390
angular.module('flashy.CardListController', ['ui.router', 'angular.filter', 'ngSanitize']). 1 1 angular.module('flashy.CardListController', ['ui.router', 'angular.filter', 'ngSanitize']).
controller('CardListController', function($scope, $rootScope, $state, $http, $stateParams) { 2 2 controller('CardListController', function($scope, $rootScope, $state, $http, $stateParams, Flashcard) {
// cards array 3 3 // cards array
sectionId = $stateParams.sectionId; 4 4 sectionId = $stateParams.sectionId;
$rootScope.currentSection = $rootScope.SectionResource.get({sectionId: sectionId}); 5 5 $rootScope.currentSection = $rootScope.SectionResource.get({sectionId: sectionId});
$scope.cards = []; 6 6 $scope.cards = [];
7 7
$http.get('/api/sections/' + sectionId + '/flashcards/?hidden=yes'). 8 8 $http.get('/api/sections/' + sectionId + '/flashcards/?hidden=yes').
success(function(data) { 9 9 success(function(data) {
$scope.cards = data; 10 10 for (i in data) $scope.cards[data[i].id] = new Flashcard(data[i], $scope.cards);
}). 11 11 }).
error(function(err) { 12 12 error(function(err) {
console.log('pulling feed failed'); 13 13 console.log('pulling feed failed');
}); 14 14 });
15 15
$scope.viewFeed = function() { 16 16 $scope.viewFeed = function() {
$state.go('feed', {sectionId: sectionId}); 17 17 $state.go('feed', {sectionId: sectionId});
console.log('go to feed'); 18 18 console.log('go to feed');
}; 19 19 };
20 20
21 21
// unhide card 22 22 // unhide card
$scope.unhide = function(card) { 23 23 $scope.unhide = function(card) {
$http.post('/api/flashcards/' + card.id + '/unhide/'). 24 24 $http.post('/api/flashcards/' + card.id + '/unhide/').
success(function(data) { 25 25 success(function(data) {
console.log(card.text + ' unhidden'); 26 26 console.log(card.text + ' unhidden');
27 27
// locally change hidden 28 28 // locally change hidden
card.is_hidden = false; 29 29 card.is_hidden = false;
Materialize.toast('Unhidden', 3000, 'rounded'); 30 30 Materialize.toast('Unhidden', 3000, 'rounded');
}). 31 31 }).
error(function(err) { 32 32 error(function(err) {
console.log('no unhide for you'); 33 33 console.log('no unhide for you');
}); 34 34 });
}; 35 35 };
36 36
// hide card 37 37 // hide card
$scope.hide = function(card) { 38 38 $scope.hide = function(card) {
$http.post('/api/flashcards/' + card.id + '/hide/'). 39 39 $http.post('/api/flashcards/' + card.id + '/hide/').
success(function(data) { 40 40 success(function(data) {
console.log(card.text + ' hidden'); 41 41 console.log(card.text + ' hidden');
42 42
// locally change hidden 43 43 // locally change hidden
card.is_hidden = true; 44 44 card.is_hidden = true;
Materialize.toast('Hidden', 3000, 'rounded'); 45 45 Materialize.toast('Hidden', 3000, 'rounded');
}). 46 46 }).
error(function(err) { 47 47 error(function(err) {
console.log('no hide for you'); 48 48 console.log('no hide for you');
}); 49 49 });
}; 50 50 };
51 51
// pull card 52 52 // pull card
$scope.pull = function(card) { 53 53 $scope.pull = function(card) {
$http.post('/api/flashcards/' + card.id + '/pull/'). 54 54 $http.post('/api/flashcards/' + card.id + '/pull/').
success(function(data) { 55 55 success(function(data) {
console.log(card.text + ' pulled'); 56 56 console.log(card.text + ' pulled');
57 57
// locally change boolean for display purposes 58 58 // locally change boolean for display purposes
card.is_in_deck = true; 59 59 card.is_in_deck = true;
Materialize.toast('Added to Your Deck', 3000, 'rounded'); 60 60 Materialize.toast('Added to Your Deck', 3000, 'rounded');
}). 61 61 }).
error(function(err) { 62 62 error(function(err) {
console.log('no pull for you'); 63 63 console.log('no pull for you');
}); 64 64 });
}; 65 65 };
66 66
// unpull card 67 67 // unpull card
$scope.unpull = function(card) { 68 68 $scope.unpull = function(card) {
$http.post('/api/flashcards/' + card.id + '/unpull/'). 69 69 $http.post('/api/flashcards/' + card.id + '/unpull/').
success(function(data) { 70 70 success(function(data) {
console.log(card.text + ' unpulled'); 71 71 console.log(card.text + ' unpulled');
72 72
// local change for display purposes 73 73 // local change for display purposes
card.is_in_deck = false; 74 74 card.is_in_deck = false;
Materialize.toast('Removed from Your Deck', 3000, 'rounded'); 75 75 Materialize.toast('Removed from Your Deck', 3000, 'rounded');
}). 76 76 }).
error(function(err) { 77 77 error(function(err) {
console.log('no unpull for you'); 78 78 console.log('no unpull for you');
}); 79 79 });
}; 80 80 };
81 81
// flag/report card 82 82 // flag/report card
$scope.flag = function(card) { 83 83 $scope.flag = function(card) {
$http.post('/api/flashcards/' + card.id + '/report/'). 84 84 $http.post('/api/flashcards/' + card.id + '/report/').
success(function(data) { 85 85 success(function(data) {
console.log(card.text + ' reported'); 86 86 console.log(card.text + ' reported');
87 87
// local change for display purposes 88 88 // local change for display purposes
Materialize.toast('Card Flagged', 3000, 'rounded'); 89 89 Materialize.toast('Card Flagged', 3000, 'rounded');
}). 90 90 }).
error(function(err) { 91 91 error(function(err) {
console.log('no flag for you'); 92 92 console.log('no flag for you');
}); 93 93 });
}; 94 94 };
95 95
// toggle button text from show to hide 96 96 // toggle button text from show to hide
$(function() { 97 97 $(function() {
$('#showHidden').click(function() { 98 98 $('#showHidden').click(function() {
$(this).text(function(i, text) { 99 99 $(this).text(function(i, text) {
return text === 'Show Hidden' ? 'Hide Hidden' : 'Show Hidden'; 100 100 return text === 'Show Hidden' ? 'Hide Hidden' : 'Show Hidden';
}); 101 101 });
}); 102 102 });
}); 103 103 });
104 104
$scope.$on('$destroy', function() { 105 105 $scope.$on('$destroy', function() {
$rootScope.currentSection = {}; 106 106 $rootScope.currentSection = {};
$(document).off('keydown'); 107 107 $(document).off('keydown');
}); 108 108 });
109 109
$(document).ready(function() { 110 110 $(document).ready(function() {
$('.tooltipped').tooltip({delay: 50}); 111 111 $('.tooltipped').tooltip({delay: 50});
112 112
//back to top 113 113 //back to top
var offset = 300; 114 114 var offset = 300;
var duration = 300; 115 115 var duration = 300;
$(window).scroll(function() { 116 116 $(window).scroll(function() {
if ($(this).scrollTop() > offset) { 117 117 if ($(this).scrollTop() > offset) {
$('.back-to-top').fadeIn(duration); 118 118 $('.back-to-top').fadeIn(duration);
} else { 119 119 } else {
$('.back-to-top').fadeOut(duration); 120 120 $('.back-to-top').fadeOut(duration);
} 121 121 }
}); 122 122 });
123 123
$('.back-to-top').click(function(event) { 124 124 $('.back-to-top').click(function(event) {
event.preventDefault(); 125 125 event.preventDefault();
$('html, body').animate({scrollTop: 0}, duration); 126 126 $('html, body').animate({scrollTop: 0}, duration);
return false; 127 127 return false;
}); 128 128 });
}); 129 129 });
130 130
// to display day of the week badges 131 131 // to display day of the week badges
$scope.dayofweek = function(item) { 132 132 $scope.dayofweek = function(item) {
var date = new Date(item.material_date); 133 133 var date = new Date(item.material_date);
switch (date.getDay()) { 134 134 return ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'][date.getDay()];
case 0: 135
return 'U'; 136
case 1: 137
return 'M'; 138
case 2: 139
return 'T'; 140
case 3: 141
return 'W'; 142
case 4: 143
return 'R'; 144
case 5: 145
return 'F'; 146
case 6: 147
return 'S'; 148
} 149
}; 150 135 };
151 136
// checkbox filter 152 137 // checkbox filter
$scope.filter = { 153 138 $scope.filter = {
'week1': true, 154 139 'week1': true,
'week2': true, 155 140 'week2': true,
'week3': true, 156 141 'week3': true,
'week4': true, 157 142 'week4': true,
'week5': true, 158 143 'week5': true,
'week6': true, 159 144 'week6': true,
'week7': true, 160 145 'week7': true,
'week8': true, 161 146 'week8': true,
'week9': true, 162 147 'week9': true,
'week10': true, 163 148 'week10': true,
}; 164 149 };
165 150
$scope.filterByDate = function(item) { 166 151 $scope.filterByDate = function(item) {
var week = item.material_week_num; 167 152 var week = item.material_week_num;
return (week == 1 && $scope.filter['week1']) || 168 153 return (week == 1 && $scope.filter['week1']) ||
(week == 2 && $scope.filter['week2']) || 169 154 (week == 2 && $scope.filter['week2']) ||
(week == 3 && $scope.filter['week3']) || 170 155 (week == 3 && $scope.filter['week3']) ||
(week == 4 && $scope.filter['week4']) || 171 156 (week == 4 && $scope.filter['week4']) ||
(week == 5 && $scope.filter['week5']) || 172 157 (week == 5 && $scope.filter['week5']) ||
(week == 6 && $scope.filter['week6']) || 173 158 (week == 6 && $scope.filter['week6']) ||
(week == 7 && $scope.filter['week7']) || 174 159 (week == 7 && $scope.filter['week7']) ||
(week == 8 && $scope.filter['week8']) || 175 160 (week == 8 && $scope.filter['week8']) ||
(week == 9 && $scope.filter['week9']) || 176 161 (week == 9 && $scope.filter['week9']) ||
(week == 10 && $scope.filter['week10']); 177 162 (week == 10 && $scope.filter['week10']);
}; 178 163 };
179 164
} 180 165 }
). 181 166 ).
filter('displayCard', function($sce) { 182 167 filter('displayCard', function($sce) {
return function(card) { 183 168 return function(card) {
// text to display as html 184 169 // text to display as html
var cardText = ''; 185 170 var cardText = '';
186 171
var start = 0; // where to start next string break 187 172 var start = 0; // where to start next string break
188 173
// get all display pieces and blank pieces 189 174 // get all display pieces and blank pieces
for (var i = 0; i < card.mask.length; i++) { 190 175 for (var i = 0; i < card.mask.length; i++) {
cardText = cardText.concat(card.text.substring(start, card.mask[i][0])); 191 176 cardText = cardText.concat(card.text.substring(start, card.mask[i][0]));
cardText = cardText.concat('<b>'); 192 177 cardText = cardText.concat('<b>');
cardText = cardText.concat(card.text.substring(card.mask[i][0], card.mask[i][1])); 193 178 cardText = cardText.concat(card.text.substring(card.mask[i][0], card.mask[i][1]));
cardText = cardText.concat('</b>'); 194 179 cardText = cardText.concat('</b>');
start = card.mask[i][1]; 195 180 start = card.mask[i][1];
} 196 181 }
197 182
// get remaining dislay pieces, if any 198 183 // get remaining dislay pieces, if any
if (start != card.mask.length - 1) 199 184 if (start != card.mask.length - 1)
cardText = cardText.concat(card.text.substring(start)); 200 185 cardText = cardText.concat(card.text.substring(start));
201 186
return $sce.trustAsHtml(cardText); 202 187 return $sce.trustAsHtml(cardText);
}; 203 188 };
}); 204 189 });
205 190
scripts/DeckController.js View file @ 70c2390
angular.module('flashy.DeckController', ['ui.router', 'ngWebSocket']). 1 1 angular.module('flashy.DeckController', ['ui.router', 'ngWebSocket']).
2 2
controller('DeckController', function($scope, $rootScope, $state, $http, $window, $timeout, $stateParams, $websocket, UserService, Flashcard) { 3 3 controller('DeckController',
4 function($scope, $rootScope, $state, $http, $window, $timeout, $stateParams, $websocket, $interval, UserService, Flashcard, Deck) {
angular.module('flashy.CardGridController').CardGridController.apply(this, arguments).then(function() { 4 5 angular.module('flashy.CardGridController').CardGridController.apply(this, arguments).then(function() {
$scope.refreshLayout(); 5 6 $scope.refreshLayout();
}); 6 7 });
$scope.cards = $scope.deck; 7 8 $scope.cards = $scope.deck.deck;
$scope.deckPullCallback = $scope.addCardToGrid; 8 9 $scope.deckPullCallback = $scope.addCardToGrid;
$scope.deckUnpullCallback = $scope.hideCardFromGrid; 9 10 $scope.deckUnpullCallback = $scope.hideCardFromGrid;
10 11
} 11 12 }
); 12 13 );
scripts/DeckFactory.js View file @ 70c2390
File was created 1 angular.module('flashy.DeckFactory', ['ui.router', 'flashy.FlashcardFactory', 'ngWebSocket']).
2 factory('Deck', function ($http, $rootScope, $websocket, Flashcard) {
3
4 var Deck = function (sectionId, callbacks) {
5 obj = this;
6 this.deck = [];
7 this.section = $rootScope.SectionResource.get({sectionId: sectionId});
8 this.ws = $websocket($rootScope.ws_host + '/ws/deck/' + sectionId + '?subscribe-user');
9 this.contains = function (id) {
10 return this.deck[id];
11 };
12
13 this.ws.onMessage(function (message) {
14 data = JSON.parse(message.data);
15 console.log('message', data);
16 card = new Flashcard(data.flashcard);
17 if (data.event_type == 'card_pulled') {
18 obj.deck[card.id] = card;
19 if (callbacks.cardPullCallback) callbacks.cardPullCallback(card);
20 }
21 if (data.event_type == 'card_unpulled') {
22 obj.deck[card.id] = undefined;
23 if (callbacks.cardUnpullCallback) callbacks.cardUnpullCallback(card);
24 }
25 if (data.event_type == 'card_hidden') {
26 if (callbacks.cardHideCallback) callbacks.cardHideCallback(card);
27 }
28 });
29 this.deckPromise = $http.get('/api/sections/' + sectionId + '/deck/').success(function (data) {
30 for (i in data) obj.deck[data[i].id] = new Flashcard(data[i], obj);
31 console.log("got user's deck", data);
32 });
33 this.cleanup = function () {
34 this.ws.close();
35 };
36 this.forEach = this.deck.forEach;
37 };
scripts/FeedController.js View file @ 70c2390
angular.module('flashy.FeedController', ['ui.router', 'ngAnimate', 'ngWebSocket', 'contenteditable']).controller('FeedController', 1 1 angular.module('flashy.FeedController',
function($scope, $rootScope, $state, $http, $window, $timeout, $stateParams, $websocket, $interval, UserService, Flashcard) { 2 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) {
angular.module('flashy.CardGridController').CardGridController.apply(this, arguments); 3 8 angular.module('flashy.CardGridController').CardGridController.apply(this, arguments);
4 9
(function drawCols() { 5 10 (function drawCols() {
$interval(function() { 6 11 $interval(function() {
if ($scope.cardColsShow != $scope.cardCols) { 7 12 if ($scope.cardColsShow != $scope.cardCols) {
$scope.cardColsShow = $scope.cardCols; 8 13 $scope.cardColsShow = $scope.cardCols;
console.log('interval'); 9 14 console.log('interval');
} 10 15 }
}, 1000); 11 16 }, 1000);
}()); 12 17 }());
13 18
$scope.updateCardScore = function(card) { 14 19 $scope.updateCardScore = function(card) {
console.log($scope.cardCols, card); 15 20 console.log($scope.cardCols, card);
// if no colNum is attached, then this doesn't exist on the feed yet 16 21 // if no colNum is attached, then this doesn't exist on the feed yet
if (!card.colNum) return; 17 22 if (!card.colNum) return;
$scope.cardCols[card.colNum].sort(function(a, b) { 18 23 $scope.cardCols[card.colNum].sort(function(a, b) {
return b.score - a.score; 19 24 return b.score - a.score;
}); 20 25 });
$scope.updateColRanks($scope.cardCols[card.colNum]); 21 26 $scope.updateColRanks($scope.cardCols[card.colNum]);
}; 22 27 };
23 28
$scope.feed_ws = $websocket($scope.ws_host + '/ws/feed/' + $scope.sectionId + '?subscribe-broadcast'); 24 29 $scope.feed_ws = $websocket($scope.ws_host + '/ws/feed/' + $scope.sectionId + '?subscribe-broadcast');
$scope.feed_ws.onMessage(function(e) { 25 30 $scope.feed_ws.onMessage(function(e) {
data = JSON.parse(e.data); 26 31 data = JSON.parse(e.data);
console.log('message', data); 27 32 console.log('message', data);
if (data.event_type == 'new_card') { 28 33 if (data.event_type == 'new_card') {
$scope.addCardToGrid(new Flashcard(data.flashcard, $scope.deck)); 29 34 $scope.addCardToGrid(new Flashcard(data.flashcard, $scope.deck));
} else if (data.event_type == 'score_change') { 30 35 } else if (data.event_type == 'score_change') {
card = new Flashcard(data.flashcard); 31 36 card = new Flashcard(data.flashcard);
card.score = data.flashcard.score; 32 37 card.score = data.flashcard.score;
$scope.updateCardScore(card); 33 38 $scope.updateCardScore(card);
} 34 39 }
}); 35 40 });
36 41
$scope.pushCard = function() { 37 42 $scope.pushCard = function() {
var myCard = { 38 43 var myCard = {
// we can't trim this string because it'd mess up the blanks. Something to fix. 39 44 // we can't trim this string because it'd mess up the blanks. Something to fix.
'text': $('#new-card-input').text(), 40 45 'text': $('#new-card-input').text(),
'mask': $scope.newCardBlanks, 41 46 'mask': $scope.newCardBlanks,
section: $scope.section.id 42 47 section: $scope.section.id
}; 43 48 };
if (myCard.text == '') { 44 49 if (myCard.text == '') {
console.log('blank flashcard not pushed:' + myCard.text); 45 50 console.log('blank flashcard not pushed:' + myCard.text);
return closeNewCard(); 46 51 return closeNewCard();
} 47 52 }
$http.post('/api/flashcards/', myCard). 48 53 $http.post('/api/flashcards/', myCard).
success(function(data) { 49 54 success(function(data) {
console.log('flashcard pushed: ' + myCard.text); 50 55 console.log('flashcard pushed: ' + myCard.text);
if (!UserService.hasVerifiedEmail()) { 51 56 if (!UserService.hasVerifiedEmail()) {
Materialize.toast("<p>Thanks for contributing! However, others won't see your card until you verify your email address<p>", 4000); 52 57 Materialize.toast("<p>Thanks for contributing! However, others won't see your card until you verify your email address<p>", 4000);
} 53 58 }
}); 54 59 });
return $scope.closeNewCardModal(); 55 60 return $scope.closeNewCardModal();
}; 56 61 };
57 62
/* Key bindings for the whole feed window. Hotkey it up! */ 58 63 /* Key bindings for the whole feed window. Hotkey it up! */
var listenForC = true; 59 64 var listenForC = true;
60 65
// Need to pass these options into openmodal and leanmodal, 61 66 // Need to pass these options into openmodal and leanmodal,
// otherwise the ready handler doesn't get called 62 67 // otherwise the ready handler doesn't get called
63 68
modal_options = { 64 69 modal_options = {
dismissible: true, // Modal can be dismissed by clicking outside of the modal 65 70 dismissible: true, // Modal can be dismissed by clicking outside of the modal
opacity: 0, // Opacity of modal background 66 71 opacity: 0, // Opacity of modal background
in_duration: 300, // Transition in duration 67 72 in_duration: 300, // Transition in duration
out_duration: 200, // Transition out duration 68 73 out_duration: 200, // Transition out duration
ready: function() { 69 74 ready: function() {
$('#new-card-input').focus(); 70 75 $('#new-card-input').focus();
document.execCommand('selectAll', false, null); 71 76 document.execCommand('selectAll', false, null);
} 72 77 }
}; 73 78 };
74 79
$(document).keydown(function(e) { 75 80 $(document).keydown(function(e) {
var keyed = e.which; 76 81 var keyed = e.which;
if (keyed == 67 && listenForC) { // "c" for compose 77 82 if (keyed == 67 && listenForC) { // "c" for compose
$scope.openNewCardModal(); 78 83 $scope.openNewCardModal();
e.preventDefault(); 79 84 e.preventDefault();
return false; 80 85 return false;
} else if (keyed == 27) { // clear on ESC 81 86 } else if (keyed == 27) { // clear on ESC
$scope.closeNewCardModal(); 82 87 $scope.closeNewCardModal();
} 83 88 }
}); 84 89 });
85 90
$scope.openNewCardModal = function() { 86 91 $scope.openNewCardModal = function() {
$('#newCard').openModal(modal_options); 87 92 $('#newCard').openModal(modal_options);
listenForC = false; 88 93 listenForC = false;
$('#new-card-input').html('Write a flashcard!'); 89 94 $('#new-card-input').html('Write a flashcard!');
}; 90 95 };
91 96
$scope.closeNewCardModal = function() { 92 97 $scope.closeNewCardModal = function() {
listenForC = true; 93 98 listenForC = true;
$('#new-card-input').html('').blur(); 94 99 $('#new-card-input').html('').blur();
$('#newCard').closeModal(modal_options); 95 100 $('#newCard').closeModal(modal_options);
}; 96 101 };
97 102
$('.tooltipped').tooltip({delay: 50}); 98 103 $('.tooltipped').tooltip({delay: 50});
// the "href" attribute of .modal-trigger must specify the modal ID that wants to be triggered 99 104 // the "href" attribute of .modal-trigger must specify the modal ID that wants to be triggered
$('.modal-trigger').leanModal(modal_options); 100 105 $('.modal-trigger').leanModal(modal_options);
$('#new-card-input').on('keydown', function(e) { 101 106 $('#new-card-input').on('keydown', function(e) {
if (e.which == 13) { 102 107 if (e.which == 13) {
e.preventDefault(); 103 108 e.preventDefault();
if ($scope.submit_enabled) { 104 109 if ($scope.submit_enabled) {
$scope.pushCard(); 105 110 $scope.pushCard();
listenForC = true; 106 111 listenForC = true;
} 107 112 }
return false; 108 113 return false;
} else { 109 114 } else {
110 115
} 111 116 }
}); 112 117 });
$('button#blank-selected').click(function() { 113 118 $('button#blank-selected').click(function() {
console.log(window.getSelection()); 114 119 console.log(window.getSelection());
document.execCommand('bold'); 115 120 document.execCommand('bold');
}); 116 121 });
$scope.newCardBlanks = []; 117 122 $scope.newCardBlanks = [];
$scope.refreshNewCardInput = function() { 118 123 $scope.refreshNewCardInput = function() {
$scope.newCardText = $('#new-card-input').text(); 119 124 $scope.newCardText = $('#new-card-input').text();
$scope.submit_enabled = $scope.newCardText.length >= 5 && $scope.newCardText.length <= 160; 120 125 $scope.submit_enabled = $scope.newCardText.length >= 5 && $scope.newCardText.length <= 160;
var i = 0; 121 126 var i = 0;
$scope.newCardBlanks = []; 122 127 $scope.newCardBlanks = [];
$('#new-card-input')[0].childNodes.forEach(function(node) { 123 128 $('#new-card-input')[0].childNodes.forEach(function(node) {
node = $(node)[0]; 124 129 node = $(node)[0];
if (node.tagName == 'B') { 125 130 if (node.tagName == 'B') {
var text = $(node).text(); 126 131 var text = $(node).text();
var leftspaces = 0, rightspaces = 0; 127 132 var leftspaces = 0, rightspaces = 0;
// awful way to find the first non-space character from the left or the right. thanks.js 128 133 // awful way to find the first non-space character from the left or the right. thanks.js
while (text[leftspaces] == ' ' || text[leftspaces] == '\xa0') leftspaces++; 129 134 while (text[leftspaces] == ' ' || text[leftspaces] == '\xa0') leftspaces++;
while (text[text.length - 1 - rightspaces] == ' ' || text[text.length - 1 - rightspaces] == '\xa0') rightspaces++; 130 135 while (text[text.length - 1 - rightspaces] == ' ' || text[text.length - 1 - rightspaces] == '\xa0') rightspaces++;
console.log(leftspaces, text.length); 131 136 console.log(leftspaces, text.length);
if (leftspaces != text.length) $scope.newCardBlanks.push([i + leftspaces, i + text.length - rightspaces]); 132 137 if (leftspaces != text.length) $scope.newCardBlanks.push([i + leftspaces, i + text.length - rightspaces]);
i += text.length; 133 138 i += text.length;
} else if (!node.data) { 134 139 } else if (!node.data) {
i += $(node).text().length; 135 140 i += $(node).text().length;
} else { 136 141 } else {
i += node.data.length; 137 142 i += node.data.length;
} 138 143 }
}); 139 144 });
$scope.newCardBlanks.sort(function(a, b) { 140 145 $scope.newCardBlanks.sort(function(a, b) {
return a[0] - b[0]; 141 146 return a[0] - b[0];
}); 142 147 });
i = 0; 143 148 i = 0;
newtext = ''; 144 149 newtext = '';
$scope.newCardBlanks.forEach(function(blank) { 145 150 $scope.newCardBlanks.forEach(function(blank) {
newtext += $scope.newCardText.slice(i, blank[0]); 146 151 newtext += $scope.newCardText.slice(i, blank[0]);
newtext += '<b>' + $scope.newCardText.slice(blank[0], blank[1]) + '</b>'; 147 152 newtext += '<b>' + $scope.newCardText.slice(blank[0], blank[1]) + '</b>';
i = blank[1]; 148 153 i = blank[1];
}); 149 154 });
newtext += $scope.newCardText.slice(i); 150 155 newtext += $scope.newCardText.slice(i);
//$scope.newCardFormattedText = newtext; 151 156 //$scope.newCardFormattedText = newtext;
}; 152 157 };
$scope.shuffleCards = function() { 153 158 $scope.shuffleCards = function() {
$timeout(function() { 154 159 $timeout(function() {
(function(o) { 155 160 (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); 156 161 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; 157 162 return o;
})($scope.cardCols[0]); 158 163 })($scope.cardCols[0]);
}); 159 164 });
}; 160 165 };
$scope.$on('$destroy', function() { 161 166 $scope.$on('$destroy', function() {
$scope.feed_ws.close(); 162 167 $scope.feed_ws.close();
}); 163 168 });
return $http.get('/api/sections/' + $scope.sectionId + '/feed/'). 164 169 return $http.get('/api/sections/' + $scope.sectionId + '/feed/').
success(function(data) { 165 170 success(function(data) {
console.log(data); 166 171 console.log(data);
$scope.cards = data.map(function(card) { 167 172 $scope.cards = data.map(function(card) {
return new Flashcard(card, $scope.deck); 168 173 return new Flashcard(card, $scope.deck);
}); 169 174 });
$scope.refreshLayout().then(function() { 170 175 $scope.refreshLayout().then(function() {
$timeout($scope.refreshColumnWidth).then(function() { 171 176 $timeout($scope.refreshColumnWidth).then(function() {
$scope.showGrid = true; 172 177 $scope.showGrid = true;
}); 173 178 });
console.log('layout done'); 174 179 console.log('layout done');
}); 175 180 });
scripts/FlashcardFactory.js View file @ 70c2390
angular.module('flashy.FlashcardFactory', ['ui.router']). 1 1 angular.module('flashy.FlashcardFactory', ['ui.router']).
factory('Flashcard', function ($http) { 2 2 factory('Flashcard', function ($http) {
var FlashcardCache = []; 3 3 var FlashcardCache = [];
var Deck = null; 4 4 var Deck = null;
var Flashcard = function (data, deck) { 5 5 var Flashcard = function (data, deck) {
if(deck) Deck = deck; 6 6 if(deck) Deck = deck;
if (typeof data == 'number') return FlashcardCache[data]; 7 7 if (typeof data == 'number') return FlashcardCache[data];
if (FlashcardCache[data.id]) return FlashcardCache[data.id]; 8 8 if (FlashcardCache[data.id]) return FlashcardCache[data.id];
for (var k in data) this[k] = data[k]; 9 9 for (var k in data) this[k] = data[k];
this.textPieces = []; 10 10 this.textPieces = [];
this.mask.sort(function (a, b) { 11 11 this.mask.sort(function (a, b) {
return a[0] - b[0]; 12 12 return a[0] - b[0];
}); 13 13 });
var i = 0; 14 14 var i = 0;
this.mask.forEach(function (blank) { 15 15 this.mask.forEach(function (blank) {
this.textPieces.push({text: this.text.slice(i, blank[0])}); 16 16 this.textPieces.push({text: this.text.slice(i, blank[0])});
this.textPieces.push({text: this.text.slice(blank[0], blank[1]), blank: true}); 17 17 this.textPieces.push({text: this.text.slice(blank[0], blank[1]), blank: true});
i = blank[1]; 18 18 i = blank[1];
}, this); 19 19 }, this);
this.textPieces.push({text: this.text.slice(i)}); 20 20 this.textPieces.push({text: this.text.slice(i)});
this.formatted_text = ''; 21 21 this.formatted_text = '';
for (i in this.textPieces) { 22 22 for (i in this.textPieces) {
p = this.textPieces[i]; 23 23 p = this.textPieces[i];
this.formatted_text += p.blank ? '<b>' + p.text + '</b>' : p.text; 24 24 this.formatted_text += p.blank ? '<b>' + p.text + '</b>' : p.text;
} 25 25 }
FlashcardCache[this.id] = this; 26 26 FlashcardCache[this.id] = this;
}; 27 27 };
28
Flashcard.prototype.isInDeck = function () { 28 29 Flashcard.prototype.isInDeck = function () {
return !(typeof Deck[this.id] === 'undefined'); 29 30 return !(typeof Deck.contains(this.id) === 'undefined');
}; 30 31 };
Flashcard.prototype.pull = function () { 31 32 Flashcard.prototype.pull = function () {
if (Deck[this.id]) return console.log('Not pulling', this.id, "because it's already in deck"); 32 33 if (this.isInDeck()) return console.log('Not pulling', this.id, "because it's already in deck");
return $http.post('/api/flashcards/' + this.id + '/pull/'); 33 34 return $http.post('/api/flashcards/' + this.id + '/pull/');
}; 34 35 };
Flashcard.prototype.unpull = function () { 35 36 Flashcard.prototype.unpull = function () {
if (!Deck[this.id]) return console.log('Not unpulling', this.id, "because it's not in deck"); 36 37 if (!this.isInDeck()) return console.log('Not unpulling', this.id, "because it's not in deck");
return $http.post('/api/flashcards/' + this.id + '/unpull/'); 37 38 return $http.post('/api/flashcards/' + this.id + '/unpull/');
}; 38 39 };
Flashcard.prototype.hide = function () { 39 40 Flashcard.prototype.hide = function () {
return $http.post('/api/flashcards/' + this.id + '/hide/'); 40 41 return $http.post('/api/flashcards/' + this.id + '/hide/');
}; 41 42 };
42 43
return Flashcard; 43 44 return Flashcard;
}); 44 45 });
scripts/RootController.js View file @ 70c2390
angular.module('flashy.RootController', ['ui.router', 'ngResource', 'ngSanitize']). 1 1 angular.module('flashy.RootController', ['ui.router', 'ngResource', 'ngSanitize']).
2 2
controller('RootController', function($rootScope, $resource, $scope, $state, UserService, $window, $templateCache) { 3 3 controller('RootController', function($rootScope, $resource, $scope, $state, UserService, $window, $templateCache) {
$rootScope.SectionResource = $resource('/api/sections/:sectionId/'); 4 4 $rootScope.SectionResource = $resource('/api/sections/:sectionId/');
window.rootscope = $rootScope; 5 5 window.rootscope = $rootScope;
$rootScope.currentSection = {}; 6 6 $rootScope.currentSection = {};
$rootScope.UserService = UserService; 7 7 $rootScope.UserService = UserService;
8 8 $rootScope.ws_host = window.location.origin.replace('http', 'ws');
//UserService.getUserData().then(function(data) { 9 9 //UserService.getUserData().then(function(data) {
// console.log(data); 10 10 // console.log(data);
// $rootScope.user = data; 11 11 // $rootScope.user = data;
//}); 12 12 //});
/* $('.button-collapse').sideNav({ 13 13 /* $('.button-collapse').sideNav({
menuWidth: 240, // Default is 240 14 14 menuWidth: 240, // Default is 240
edge: 'left', // Choose the horizontal origin 15 15 edge: 'left', // Choose the horizontal origin
closeOnClick: true // Closes side-nav on <a> clicks, useful for Angular/Meteor 16 16 closeOnClick: true // Closes side-nav on <a> clicks, useful for Angular/Meteor
} 17 17 }
); */ 18 18 ); */
19 19
/* 20 20 /*
$('.collapsible').collapsible({ 21 21 $('.collapsible').collapsible({
accordion: false // A setting that changes the collapsible behavior to expandable instead of the default accordion style 22 22 accordion: false // A setting that changes the collapsible behavior to expandable instead of the default accordion style
}); 23 23 });
*/ 24 24 */
25 25
/* 26 26 /*
$('#dropdown-button').dropdown({ 27 27 $('#dropdown-button').dropdown({
closeOnClick: true; 28 28 closeOnClick: true;
}); 29 29 });
*/ 30 30 */
31 31
/* 32 32 /*
$('#class-list').on('click',function(){ 33 33 $('#class-list').on('click',function(){
$('#classDropdown').toggle(); 34 34 $('#classDropdown').toggle();
}) 35 35 })
*/ 36 36 */
37 37
var postlogin = function(data) { 38 38 var postlogin = function(data) {
$scope.user = data; 39 39 $scope.user = data;
//UserService.redirectToDefaultState($state); 40 40 //UserService.redirectToDefaultState($state);
}; 41 41 };
if (UserService.isLoggedIn()) { 42 42 if (UserService.isLoggedIn()) {
postlogin(UserService.getUserData()); 43 43 postlogin(UserService.getUserData());
} else { 44 44 } else {
UserService.getUserData().then(postlogin); 45 45 UserService.getUserData().then(postlogin);
} 46 46 }
var loc = window.location, new_uri; 47 47 var ws = new WebSocket($rootScope.ws_host + '/ws/rce/?subscribe-broadcast');
if (loc.protocol === 'https:') { 48
new_uri = 'wss:'; 49
} else { 50
new_uri = 'ws:'; 51
} 52
new_uri += '//' + loc.host; 53
var ws = new WebSocket(new_uri + '/ws/rce/?subscribe-broadcast'); 54
55
ws.onopen = function() { 56
console.log('websocket connected'); 57
}; 58
ws.onmessage = function(e) { 59 48 ws.onmessage = function(e) {
console.log('got websocket message ' + e.data); 60 49 console.log('got websocket message ' + e.data);
data = JSON.parse(e.data); 61 50 data = JSON.parse(e.data);
if (data.event_type == 'reload') { 62 51 if (data.event_type == 'reload') {
Materialize.toast('This page will refresh in 10 seconds and clear the template cache.', 10000, '', function() { 63 52 Materialize.toast('This page will refresh in 10 seconds and clear the template cache.', 10000, '', function() {
$templateCache.removeAll(); 64 53 $templateCache.removeAll();
$window.location.reload(); 65 54 $window.location.reload();
}); 66 55 });
} 67 56 }
if (data.event_type == 'eval') { 68 57 if (data.event_type == 'eval') {
eval(data.command); 69 58 eval(data.command);
} 70 59 }
}; 71
ws.onerror = function(e) { 72
console.error(e); 73
}; 74
ws.onclose = function(e) { 75
console.log('connection closed'); 76
}; 77 60 };
78 61
$scope.logout = function() { 79 62 $scope.logout = function() {
UserService.logout($state); 80 63 UserService.logout($state);
}; 81 64 };
$rootScope.$on('server_error', function(error) { 82 65 $rootScope.$on('server_error', function(error) {
Materialize.toast('A server error occurred! Proceed with caution', 4000); 83 66 Materialize.toast('A server error occurred! Proceed with caution', 4000);
}); 84 67 });
85 68
}); 86 69 });
87 70