Commit 7545660bf6dc22fda2d7b125c3e08d671d1bd803

Authored by Masud Rahman

Merge branch 'master' of git.ucsd.edu:110swag/flashy-frontend

Showing 12 changed files Side-by-side Diff

... ... @@ -4,7 +4,6 @@
4 4 'flashy.FeedController',
5 5 'flashy.DeckController',
6 6 'flashy.ClassAddController',
7   - 'flashy.ClassDropController',
8 7 'flashy.RequestResetController',
9 8 'flashy.StudyController',
10 9 'flashy.UserService',
... ... @@ -107,12 +106,6 @@
107 106 url: '/addclass',
108 107 templateUrl: 'templates/addclass.html',
109 108 controller: 'ClassAddController'
110   - }).
111   - state('dropclass', {
112   - resolve: auth_resolve,
113   - url: '/settings/dropclass',
114   - templateUrl: 'templates/dropclass.html',
115   - controller: 'ClassDropController'
116 109 }).
117 110 state('deck', {
118 111 resolve: auth_resolve,
... ... @@ -170,7 +170,6 @@
170 170 <script src="scripts/DeckController.js"></script>
171 171 <script src="scripts/RequestResetController.js"></script>
172 172 <script src="scripts/ClassAddController.js"></script>
173   -<script src="scripts/ClassDropController.js"></script>
174 173 <script src="scripts/StudyController.js"></script>
175 174 <script src="scripts/ResetPasswordController.js"></script>
176 175 <script src="scripts/CardListController.js"></script>
scripts/CardGridController.js View file @ 7545660
1 1 angular.module('flashy.CardGridController', ['ui.router', 'ngAnimate', 'ngWebSocket', 'flashy.DeckFactory']).CardGridController =
2 2 function($scope, $rootScope, $state, $http, $window, $timeout, $stateParams, $websocket, $interval, UserService, Flashcard, Deck) {
  3 + sectionId = parseInt($stateParams.sectionId);
3 4 $scope.cards = []; // all cards
4 5 $scope.cardCols = []; // organized data
5 6 $scope.cardColsShow = []; // displayed data
6 7 $scope.numCols = 0;
7   - $scope.cardTable = {}; // look up table of cards: {'colNum':col, 'obj':card}
8   - $scope.sectionId = parseInt($stateParams.sectionId);
9   - $scope.section = $rootScope.SectionResource.get({sectionId: $scope.sectionId});
10   - $scope.deck = new Deck($scope.sectionId, {
  8 + $scope.section = $rootScope.SectionResource.get({sectionId: sectionId});
  9 + $scope.deck = new Deck(sectionId, {
11 10 cardHideCallback: function(card) {
12 11 $scope.hideCardFromGrid(card);
13 12 }
... ... @@ -93,6 +92,7 @@
93 92  
94 93 $scope.$on('$destroy', function() {
95 94 $scope.deck.cleanup();
  95 + Flashcard.cleanup();
96 96 $rootScope.currentSection = {};
97 97 $(document).off('keydown');
98 98 });
scripts/CardListController.js View file @ 7545660
1   -angular.module('flashy.CardListController', ['ui.router', 'angular.filter', 'ngSanitize']).
2   - controller('CardListController', function($scope, $rootScope, $state, $http, $stateParams, Flashcard) {
  1 +angular.module('flashy.CardListController', ['ui.router', 'angular.filter', 'ngSanitize', 'flashy.DeckFactory']).
  2 + controller('CardListController', function($scope, $rootScope, $state, $http, $stateParams, Flashcard, Deck) {
3 3 // cards array
4   - sectionId = $stateParams.sectionId;
  4 + sectionId = parseInt($stateParams.sectionId);
  5 + $scope.deck = new Deck(sectionId, {
  6 + cardPullCallback: function(card) {
  7 + Materialize.toast('Pulled!', 3000);
  8 + },
  9 + cardUnpullCallback: function(card) {
  10 + Materialize.toast('Unpulled!', 3000);
  11 + },
  12 + cardHideCallback: function(card) {
  13 + card.is_hidden = true;
  14 + Materialize.toast('Hidden!', 3000);
  15 + },
  16 + cardUnhideCallback: function(card) {
  17 + card.is_hidden = false;
  18 + Materialize.toast('Unhidden!', 3000);
  19 + }
  20 + });
5 21 $rootScope.currentSection = $rootScope.SectionResource.get({sectionId: sectionId});
6 22 $scope.cards = [];
7 23  
8 24 $http.get('/api/sections/' + sectionId + '/flashcards/?hidden=yes').
9 25 success(function(data) {
10   - for (i in data) $scope.cards[data[i].id] = new Flashcard(data[i], $scope.cards);
  26 + for (i in data) $scope.cards[data[i].id] = new Flashcard(data[i], $scope.deck);
11 27 }).
12 28 error(function(err) {
13 29 console.log('pulling feed failed');
14 30 });
15 31  
16   - $scope.viewFeed = function() {
17   - $state.go('feed', {sectionId: sectionId});
18   - console.log('go to feed');
19   - };
20   -
21   -
22   - // unhide card
23   - $scope.unhide = function(card) {
24   - $http.post('/api/flashcards/' + card.id + '/unhide/').
25   - success(function(data) {
26   - console.log(card.text + ' unhidden');
27   -
28   - // locally change hidden
29   - card.is_hidden = false;
30   - Materialize.toast('Unhidden', 3000, 'rounded');
31   - }).
32   - error(function(err) {
33   - console.log('no unhide for you');
34   - });
35   - };
36   -
37   - // hide card
38   - $scope.hide = function(card) {
39   - $http.post('/api/flashcards/' + card.id + '/hide/').
40   - success(function(data) {
41   - console.log(card.text + ' hidden');
42   -
43   - // locally change hidden
44   - card.is_hidden = true;
45   - Materialize.toast('Hidden', 3000, 'rounded');
46   - }).
47   - error(function(err) {
48   - console.log('no hide for you');
49   - });
50   - };
51   -
52   - // pull card
53   - $scope.pull = function(card) {
54   - $http.post('/api/flashcards/' + card.id + '/pull/').
55   - success(function(data) {
56   - console.log(card.text + ' pulled');
57   -
58   - // locally change boolean for display purposes
59   - card.is_in_deck = true;
60   - Materialize.toast('Added to Your Deck', 3000, 'rounded');
61   - }).
62   - error(function(err) {
63   - console.log('no pull for you');
64   - });
65   - };
66   -
67   - // unpull card
68   - $scope.unpull = function(card) {
69   - $http.post('/api/flashcards/' + card.id + '/unpull/').
70   - success(function(data) {
71   - console.log(card.text + ' unpulled');
72   -
73   - // local change for display purposes
74   - card.is_in_deck = false;
75   - Materialize.toast('Removed from Your Deck', 3000, 'rounded');
76   - }).
77   - error(function(err) {
78   - console.log('no unpull for you');
79   - });
80   - };
81   -
82 32 // flag/report card
83 33 $scope.flag = function(card) {
84 34 $http.post('/api/flashcards/' + card.id + '/report/').
85 35 success(function(data) {
86 36 console.log(card.text + ' reported');
87   -
88   - // local change for display purposes
89   - Materialize.toast('Card Flagged', 3000, 'rounded');
90 37 }).
91 38 error(function(err) {
92 39 console.log('no flag for you');
... ... @@ -161,6 +108,10 @@
161 108 (week == 9 && $scope.filter['week9']) ||
162 109 (week == 10 && $scope.filter['week10']);
163 110 };
  111 + $scope.$on('$destroy', function() {
  112 + $scope.deck.cleanup();
  113 + Flashcard.cleanup();
  114 + });
164 115  
165 116 }
166 117 ).
scripts/ClassDropController.js View file @ 7545660
1   -angular.module('flashy.ClassDropController', ['ui.router']).
2   - controller('ClassDropController', function($rootScope, $resource, $scope, $state, $http, UserService) {
3   - $scope.hi = 'hi';
4   - $rootScope.SectionResource = $resource('/api/sections/:sectionId/');
5   - $rootScope.currentSection = {};
6   - $rootScope.UserService = UserService;
7   -
8   - $scope.dropClass = function(section) {
9   - $http.post('/api/sections/' + section.id + '/drop/').
10   - success(function(data) {
11   - console.log(section.short_name + ' dropped');
12   -
13   - Materialize.toast('Dropped', 3000, 'rounded');
14   - }).
15   - error(function(err) {
16   - console.log('no drop for you');
17   - });
18   - };
19   -
20   - });
scripts/DeckFactory.js View file @ 7545660
... ... @@ -30,6 +30,9 @@
30 30 if (data.event_type == 'card_hidden') {
31 31 if (callbacks.cardHideCallback) callbacks.cardHideCallback(card);
32 32 }
  33 + if (data.event_type == 'card_unhidden') {
  34 + if (callbacks.cardUnhideCallback) callbacks.cardUnhideCallback(card);
  35 + }
33 36 });
34 37 this.deckPromise = $http.get('/api/sections/' + sectionId + '/deck/').success(function (data) {
35 38 for (i in data) obj.cards[data[i].id] = new Flashcard(data[i], obj);
scripts/FeedController.js View file @ 7545660
... ... @@ -26,7 +26,7 @@
26 26 $scope.updateColRanks($scope.cardCols[card.colNum]);
27 27 };
28 28  
29   - $scope.feed_ws = $websocket($scope.ws_host + '/ws/feed/' + $scope.sectionId + '?subscribe-broadcast');
  29 + $scope.feed_ws = $websocket($scope.ws_host + '/ws/feed/' + sectionId + '?subscribe-broadcast');
30 30 $scope.feed_ws.onMessage(function(e) {
31 31 data = JSON.parse(e.data);
32 32 console.log('message', data);
... ... @@ -166,7 +166,7 @@
166 166 $scope.$on('$destroy', function() {
167 167 $scope.feed_ws.close();
168 168 });
169   - return $http.get('/api/sections/' + $scope.sectionId + '/feed/').
  169 + return $http.get('/api/sections/' + sectionId + '/feed/').
170 170 success(function(data) {
171 171 console.log(data);
172 172 $scope.cards = data.map(function(card) {
scripts/FlashcardFactory.js View file @ 7545660
1 1 angular.module('flashy.FlashcardFactory', ['ui.router']).
2 2 factory('Flashcard', function ($http) {
3 3 var FlashcardCache = [];
  4 + var Deck = null;
4 5 var Flashcard = function (data, deck) {
5 6 if (typeof data == 'number') return FlashcardCache[data];
6 7 if (FlashcardCache[data.id]) return FlashcardCache[data.id];
7   - if (deck) this.deck = deck;
  8 + if (!Deck && deck) Deck = deck;
8 9 for (var k in data) this[k] = data[k];
9 10 this.textPieces = [];
10 11 this.mask.sort(function (a, b) {
... ... @@ -26,7 +27,7 @@
26 27 };
27 28  
28 29 Flashcard.prototype.isInDeck = function () {
29   - return !(typeof this.deck.contains(this.id) === 'undefined');
  30 + return !(typeof Deck.contains(this.id) === 'undefined');
30 31 };
31 32 Flashcard.prototype.pullUnpull = function () {
32 33 if (this.isInDeck()) this.unpull();
... ... @@ -42,6 +43,13 @@
42 43 };
43 44 Flashcard.prototype.hide = function () {
44 45 return $http.post('/api/flashcards/' + this.id + '/hide/');
  46 + };
  47 + Flashcard.prototype.unhide = function () {
  48 + return $http.post('/api/flashcards/' + this.id + '/unhide/');
  49 + };
  50 + Flashcard.cleanup = function () {
  51 + Deck = null;
  52 + FlashcardCache = [];
45 53 };
46 54  
47 55 return Flashcard;
scripts/SettingsController.js View file @ 7545660
1 1 angular.module('flashy.SettingsController', ['ui.router']).
2 2  
3   - controller('SettingsController', function($scope, $http) {
4   - $scope.changePassword = function(oldPassword, newPassword, confirmedNewPassword) {
  3 + controller('SettingsController', function($rootScope, $resource, $scope, $state, $http, UserService) {
  4 + $scope.error = false;
  5 + $scope.success = false;
  6 + $scope.mismatch = false;
  7 + $scope.unacceptable = false;
5 8  
  9 + $scope.changePassword = function(oldPassword, newPassword, confirmedNewPassword) {
  10 + console.log('in change password');
  11 +
  12 + $http.patch('/api/me/', {
  13 + 'old_password': oldPassword,
  14 + 'new_password': newPassword
  15 + }).
  16 + success(function(data) {
  17 +
  18 + console.log('password successfully changes');
  19 +
  20 + }).
  21 + error(function(data) {
  22 + console.log('not changed');
  23 + });
  24 +
  25 +
6 26 };
  27 +
  28 + $rootScope.SectionResource = $resource('/api/sections/:sectionId/');
  29 + $rootScope.currentSection = {};
  30 + $rootScope.UserService = UserService;
  31 +
  32 + $scope.dropClass = function(section) {
  33 + $http.post('/api/sections/' + section.id + '/drop/').
  34 + success(function(data) {
  35 + console.log(section.short_name + ' dropped');
  36 +
  37 + Materialize.toast('Dropped', 3000, 'rounded');
  38 + }).
  39 + error(function(err) {
  40 + console.log('no drop for you');
  41 + });
  42 + };
  43 +
  44 +
  45 +
7 46 console.log('checking to see if chrome');
  47 +
8 48 if (!chrome) {
  49 + pushSwitch.disabled = true;
9 50 return;
10 51 }
  52 +
11 53 console.log('chrome');
12 54  
13 55 console.log('executing things outside of module');
14 56 var PUSH_SERVER_URL = '/api/subscribe/';
  57 + var UNPUSH_SERVER_URL = '/api/unsubscribe/';
15 58  
16 59 function onPushSubscription(pushSubscription) {
17 60 console.log('pushSubscription = ', pushSubscription.endpoint);
... ... @@ -27,6 +70,16 @@
27 70 $http.post(PUSH_SERVER_URL, {'registration_id': subscriptionId});
28 71 }
29 72  
  73 + function removeSubscription(pushSubscription) {
  74 + console.log('removing subscription');
  75 + console.log('pushSubscription endpoint = ', pushSubscription.endpoint);
  76 +
  77 + var subscriptionId = pushSubscription.subscriptionId;
  78 +
  79 + console.log('registration_id: ', subscriptionId);
  80 + $http.post(UNPUSH_SERVER_URL, {'registration_id': subscriptionId});
  81 + }
  82 +
30 83 function subscribeDevice() {
31 84 // We need the service worker registration to access the push manager
32 85 navigator.serviceWorker.ready.then(function(serviceWorkerRegistration) {
33 86  
... ... @@ -41,12 +94,15 @@
41 94 console.log('subscribe() Error: Push permission status = ',
42 95 permissionStatus);
43 96 if (permissionStatus.status === 'denied') {
  97 + pushSwitch.checked = false;
  98 + pushSwitch.disabled = true;
44 99 // The user blocked the permission prompt
45 100 console.log('Ooops Notifications are Blocked',
46 101 'Unfortunately you just permanently blocked notifications. ' +
47 102 'Please unblock / allow them to switch on push ' +
48 103 'notifications.');
49 104 } else {
  105 + pushSwitch.checked = false;
50 106 console.log('Ooops Push Couldn\'t Register',
51 107 '<p>When we tried to ' +
52 108 'get the subscription ID for GCM, something went wrong,' +
... ... @@ -58,6 +114,7 @@
58 114 '</p>');
59 115 }
60 116 }).catch(function(err) {
  117 + pushSwitch.checked = false;
61 118 console.log('Ooops Push Couldn\'t Register',
62 119 '<p>When we tried to ' +
63 120 'get the subscription ID for GCM, something went wrong, not ' +
64 121  
... ... @@ -71,10 +128,13 @@
71 128 } else {
72 129 // Use notification permission to do something
73 130 if (Notification.permission === 'denied') {
  131 + pushSwitch.disabled = true;
  132 + pushSwitch.checked = false;
74 133 console.log('Ooops Notifications are Blocked',
75 134 'Unfortunately you just permanently blocked notifications. ' +
76 135 'Please unblock / allow them to switch on push notifications.');
77 136 } else {
  137 + pushSwitch.checked = false;
78 138 console.log('Ooops Push Couldn\'t Register',
79 139 '<p>When we tried to ' +
80 140 'get the subscription ID for GCM, something went wrong, not ' +
81 141  
82 142  
83 143  
... ... @@ -96,21 +156,27 @@
96 156 function(pushSubscription) {
97 157 // Check we have everything we need to unsubscribe
98 158 if (!pushSubscription) {
  159 + pushSwitch.checked = false;
99 160 return;
100 161 }
101 162  
102 163 // TODO: Remove the device details from the server
103 164 // i.e. the pushSubscription.subscriptionId and
104 165 // pushSubscription.endpoint
  166 + var subscriptionId = pushSubscription.subscriptionId;
105 167  
106 168 pushSubscription.unsubscribe().then(function(successful) {
107 169 console.log('Unsubscribed from push: ', successful);
  170 +
108 171 if (!successful) {
109 172 // The unsubscribe was unsuccessful, but we can
110 173 // remove the subscriptionId from our server
111 174 // and notifications will stop
112 175 // This just may be in a bad state when the user returns
113   - console.error('We were unable to unregister from push');
  176 + pushSwitch.checked = true;
  177 + removeSubscription(pushSubscription);
  178 + console.error('We were unable to unregister from push, but we removed'+
  179 + 'registration id from the server');
114 180 }
115 181  
116 182 }).catch(function(e) {
... ... @@ -128,6 +194,7 @@
128 194 // If the notification permission is denied, it's a permanent block
129 195 switch (permissionStatus.status) {
130 196 case 'denied':
  197 + pushSwitch.disabled = true;
131 198 console.log('Ooops Push has been Blocked',
132 199 'Unfortunately the user permanently blocked push. Please unblock / ' +
133 200 'allow them to switch on push notifications.');
... ... @@ -137,6 +204,7 @@
137 204 console.log('case granted');
138 205 break;
139 206 case 'prompt':
  207 + pushSwitch.checked = false;
140 208 console.log('case prompt');
141 209 break;
142 210 }
... ... @@ -163,6 +231,7 @@
163 231 return;
164 232 }
165 233  
  234 + console.log('update current state.');
166 235 // Update the current state with the
167 236 // subscriptionid and endpoint
168 237 onPushSubscription(subscription);
... ... @@ -179,13 +248,9 @@
179 248 }
180 249  
181 250 function setUpNotificationPermission() {
182   - // If the notification permission is denied, it's a permanent block
183   - if (Notification.permission === 'denied') {
184   - console.log('Ooops Notifications are Blocked',
185   - 'Unfortunately notifications are permanently blocked. Please unblock / ' +
186   - 'allow them to switch on push notifications.');
187   - return;
188   - } else if (Notification.permission === 'default') {
  251 + console.log('setting notification setting');
  252 +
  253 + if (Notification.permission === 'default') {
189 254 console.log('notification permissions === default');
190 255 return;
191 256 }
... ... @@ -214,6 +279,27 @@
214 279  
215 280 // Once the service worker is registered set the initial state
216 281 function initialiseState() {
  282 + // Check if notifications are supported
  283 + if (!('showNotification' in ServiceWorkerRegistration.prototype)) {
  284 + console.warn('Notifications aren\'t supported.');
  285 + return;
  286 + }
  287 + // Check the current Notification permission.
  288 + // If its denied, it's a permanent block until the
  289 + // user changes the permission
  290 + else if (Notification.permission === 'denied') {
  291 + console.log('Ooops Notifications are Blocked',
  292 + 'Unfortunately notifications are permanently blocked. Please unblock / ' +
  293 + 'allow them to switch on push notifications.');
  294 + return;
  295 + }
  296 + // Check if push messaging is supported
  297 + else if (!('PushManager' in window)) {
  298 + console.warn('Push messaging isn\'t supported.');
  299 + return;
  300 + }
  301 +
  302 + pushSwitch.disabled = false;
217 303 // Is the Permissions API supported
218 304 if ('permissions' in navigator) {
219 305 console.log('setting push permissions');
... ... @@ -226,6 +312,21 @@
226 312 }
227 313  
228 314 var enablePushSwitch = $('.js-checkbox');
  315 +
  316 + var pushSwitch = document.getElementById("notifbox");
  317 + pushSwitch.disabled = true;
  318 +
  319 + var ua = navigator.userAgent.toLowerCase();
  320 + var isAndroid = ua.indexOf("android") > -1; //&& ua.indexOf("mobile");
  321 +
  322 + if(!isAndroid) {
  323 + // Do something!
  324 + // Redirect to Android-site?
  325 + pushSwitch.disabled = true;
  326 + console.log("not android");
  327 + return;
  328 + }
  329 +
229 330 enablePushSwitch.change(function(e) {
230 331 console.log('checkbox changed');
231 332 if (e.target.checked) {
... ... @@ -242,6 +343,7 @@
242 343 navigator.serviceWorker.register('service-worker.js')
243 344 .then(initialiseState);
244 345 } else {
  346 + // disable button if serviceworker is not available
245 347 // Service Workers aren't supported so you should hide the push UI
246 348 // If it's currently visible.
247 349 console.log('Ooops Service Workers aren\'t Supported',
templates/cardlist.html View file @ 7545660
1 1 <body>
2   - <div class="row">
3   - <a class="btn" id="showHidden" ng-click="show = !show" style="margin-top: 15px">Show Hidden</a>
  2 +<div class="row">
  3 + <a class="btn" id="showHidden" ng-click="show = !show" style="margin-top: 15px">Show Hidden</a>
4 4  
5   - <div class="input-field col s6 right">
6   - <i class="mdi-action-search prefix"></i>
7   - <input id="search" type="text" class="validate" ng-model="searchText"/>
8   - <label for="search">Search</label>
9   - </div>
  5 + <div class="input-field col s6 right">
  6 + <i class="mdi-action-search prefix"></i>
  7 + <input id="search" type="text" class="validate" ng-model="searchText"/>
  8 + <label for="search">Search</label>
10 9 </div>
  10 +</div>
11 11  
12   - <div class="row">
13   - <form>
14   - <div class="col s12">
15   - <div class="col s2">
16   - <input type="checkbox" class="filled-in" id="weekOneCheck" ng-model="filter['week1']"/>
17   - <label for="weekOneCheck">Week One</label>
18   - </div>
19   - <div class="col s2">
20   - <input type="checkbox" class="filled-in" id="weekTwoCheck" ng-model="filter['week2']"/>
21   - <label for="weekTwoCheck">Week Two</label>
22   - </div>
23   - <div class="col s2">
24   - <input type="checkbox" class="filled-in" id="weekThreeCheck" ng-model="filter['week3']"/>
25   - <label for="weekThreeCheck">Week Three</label>
26   - </div>
27   - <div class="col s2">
28   - <input type="checkbox" class="filled-in" id="weekFourCheck" ng-model="filter['week4']"/>
29   - <label for="weekFourCheck">Week Four</label>
30   - </div>
31   - <div class="col s2">
32   - <input type="checkbox" class="filled-in" id="weekFiveCheck" ng-model="filter['week5']"/>
33   - <label for="weekFiveCheck">Week Five</label>
34   - </div>
  12 +<div class="row">
  13 + <form>
  14 + <div class="col s12">
  15 + <div class="col s2">
  16 + <input type="checkbox" class="filled-in" id="weekOneCheck" ng-model="filter['week1']"/>
  17 + <label for="weekOneCheck">Week One</label>
35 18 </div>
36   - <div class="col s12">
37   - <div class="col s2">
38   - <input type="checkbox" class="filled-in" id="weekSixCheck" ng-model="filter['week6']"/>
39   - <label for="weekSixCheck">Week Six</label>
40   - </div>
41   - <div class="col s2">
42   - <input type="checkbox" class="filled-in" id="weekSevenCheck" ng-model="filter['week7']"/>
43   - <label for="weekSevenCheck">Week Seven</label>
44   - </div>
45   - <div class="col s2">
46   - <input type="checkbox" class="filled-in" id="weekEightCheck" ng-model="filter['week8']"/>
47   - <label for="weekEightCheck">Week Eight</label>
48   - </div>
49   - <div class="col s2">
50   - <input type="checkbox" class="filled-in" id="weekNineCheck" ng-model="filter['week9']"/>
51   - <label for="weekNineCheck">Week Nine</label>
52   - </div>
53   - <div class="col s2">
54   - <input type="checkbox" class="filled-in" id="weekTenCheck" ng-model="filter['week10']"/>
55   - <label for="weekTenCheck">Week Ten</label>
56   - </div>
  19 + <div class="col s2">
  20 + <input type="checkbox" class="filled-in" id="weekTwoCheck" ng-model="filter['week2']"/>
  21 + <label for="weekTwoCheck">Week Two</label>
57 22 </div>
58   - </form>
59   - </div>
  23 + <div class="col s2">
  24 + <input type="checkbox" class="filled-in" id="weekThreeCheck" ng-model="filter['week3']"/>
  25 + <label for="weekThreeCheck">Week Three</label>
  26 + </div>
  27 + <div class="col s2">
  28 + <input type="checkbox" class="filled-in" id="weekFourCheck" ng-model="filter['week4']"/>
  29 + <label for="weekFourCheck">Week Four</label>
  30 + </div>
  31 + <div class="col s2">
  32 + <input type="checkbox" class="filled-in" id="weekFiveCheck" ng-model="filter['week5']"/>
  33 + <label for="weekFiveCheck">Week Five</label>
  34 + </div>
  35 + </div>
  36 + <div class="col s12">
  37 + <div class="col s2">
  38 + <input type="checkbox" class="filled-in" id="weekSixCheck" ng-model="filter['week6']"/>
  39 + <label for="weekSixCheck">Week Six</label>
  40 + </div>
  41 + <div class="col s2">
  42 + <input type="checkbox" class="filled-in" id="weekSevenCheck" ng-model="filter['week7']"/>
  43 + <label for="weekSevenCheck">Week Seven</label>
  44 + </div>
  45 + <div class="col s2">
  46 + <input type="checkbox" class="filled-in" id="weekEightCheck" ng-model="filter['week8']"/>
  47 + <label for="weekEightCheck">Week Eight</label>
  48 + </div>
  49 + <div class="col s2">
  50 + <input type="checkbox" class="filled-in" id="weekNineCheck" ng-model="filter['week9']"/>
  51 + <label for="weekNineCheck">Week Nine</label>
  52 + </div>
  53 + <div class="col s2">
  54 + <input type="checkbox" class="filled-in" id="weekTenCheck" ng-model="filter['week10']"/>
  55 + <label for="weekTenCheck">Week Ten</label>
  56 + </div>
  57 + </div>
  58 + </form>
  59 +</div>
60 60  
61   - <div class="list" style="padding: 0px 25px">
62   - <ul class="collection"
63   - ng-repeat="(weeknum, week_cards) in cards | filter:searchText | filter:filterByDate | groupBy: 'material_week_num'">
64   - <li class="collection-header"><h3>Week {{weeknum}}</h3></li>
65   - <li class="collection-item" ng-click="expand = !expand" ng-repeat="card in week_cards" ng-show="show || !card.is_hidden">
66   - <div>
67   - <span ng-bind-html="card | displayCard"></span>
68   - <span class="badge">{{dayofweek(card)}}</span>
69   - <p class="right-align" ng-show="expand">
70   - <a href="" class="tooltipped" ng-click="pull(card)" ng-show="!card.is_in_deck" data-position="bottom" data-delay="50" data-tooltip="Add to Deck">
71   - <i class="mdi-content-add-circle-outline small"></i></a>
72   - <a href="" class="tooltipped" ng-click="unpull(card)" ng-show="card.is_in_deck" data-position="bottom" data-delay="50" data-tooltip="Add to Deck">
73   - <i class="mdi-content-remove-circle-outline small"></i></a>
74   - <a href="" class="tooltipped" ng-click="hide(card)" ng-show="!card.is_hidden" data-position="bottom" data-delay="50" data-tooltip="Hide">
75   - <i class="mdi-action-visibility-off small"></i></a>
76   - <a href="" class="tooltipped" ng-click="unhide(card)" ng-show="card.is_hidden" data-position="bottom" data-delay="50" data-tooltip="Unhide">
77   - <i class="mdi-action-visibility small"></i></a>
78   - <a href="" ng-click="flag(card)" data-position="bottom" data-delay="50" data-tooltip="Flag">
79   - <i class="mdi-content-flag small"></i></a>
80   - </p>
81   - </div>
82   - </li>
83   - </ul>
84   - </div>
  61 +<div class="list" style="padding: 0px 25px">
  62 + <ul class="collection"
  63 + ng-repeat="(weeknum, week_cards) in cards | filter:searchText | filter:filterByDate | groupBy: 'material_week_num'">
  64 + <li class="collection-header"><h3>Week {{weeknum}}</h3></li>
  65 + <li class="collection-item" ng-click="expand = !expand" ng-repeat="card in week_cards"
  66 + ng-show="show || !card.is_hidden">
  67 + <i ng-show="card.isInDeck()" class="mdi-action-done small green-text"></i>
  68 + <span ng-bind-html="card | displayCard"></span>
  69 + <span class="badge">{{dayofweek(card)}}</span>
85 70  
  71 + <p class="right-align" ng-show="expand">
  72 + <a href="" class="tooltipped" ng-click="card.pull()" ng-show="!card.isInDeck()" data-position="bottom"
  73 + data-delay="50" data-tooltip="Add to Deck">
  74 + <i class="mdi-content-add-circle-outline small"></i></a>
  75 + <a href="" class="tooltipped" ng-click="card.unpull()" ng-show="card.isInDeck()" data-position="bottom"
  76 + data-delay="50" data-tooltip="Add to Deck">
  77 + <i class="mdi-content-remove-circle-outline small"></i></a>
  78 + <a href="" class="tooltipped" ng-click="card.hide()" ng-show="!card.is_hidden" data-position="bottom"
  79 + data-delay="50" data-tooltip="Hide">
  80 + <i class="mdi-action-visibility-off small"></i></a>
  81 + <a href="" class="tooltipped" ng-click="card.unhide()" ng-show="card.is_hidden" data-position="bottom"
  82 + data-delay="50" data-tooltip="Unhide">
  83 + <i class="mdi-action-visibility small"></i></a>
  84 + <a href="" ng-click="flag(card)" data-position="bottom" data-delay="50" data-tooltip="Flag">
  85 + <i class="mdi-content-flag small"></i></a>
  86 + </p>
  87 + </li>
  88 + </ul>
  89 +</div>
86 90  
87   - <div class="fixed-action-btn back-to-top" style="bottom: 45px; right: 24px; display: none;">
88   - <a class="btn-floating btn-large">
89   - <i class="mdi-editor-publish medium"></i>
90   - </a>
91   - </div>
  91 +
  92 +<div class="fixed-action-btn back-to-top" style="bottom: 45px; right: 24px; display: none;">
  93 + <a class="btn-floating btn-large">
  94 + <i class="mdi-editor-publish medium"></i>
  95 + </a>
  96 +</div>
92 97 </body>
templates/dropclass.html View file @ 7545660
1   -<div class="row">
2   - <div class="col s8 offset-s2">
3   - <div class="card-panel" id="dropClassForm">
4   -
5   - <h2>Enrolled Classes</h2>
6   - <div class="row" style="padding: 0px 25px">
7   - <table class="hoverable responsive-table">
8   - <thead>
9   - <tr>
10   - <th data-field="id">Class</th>
11   - <th data-field="drop">Drop?</th>
12   - </tr>
13   - </thead>
14   -
15   - <tbody>
16   - <tr ng-repeat="section in UserService.getUserData().sections">
17   - <td>
18   - <span>{{section.short_name}}</span>
19   - <p>{{section.long_name}}</p>
20   - </td>
21   - <td><a href="" ng-click="dropClass(section)"><i class="mdi-content-clear small"></i></a></td>
22   - </tr>
23   - </tbody>
24   - </table>
25   - </div>
26   - </div>
27   - </div>
28   -</div>
templates/settings.html View file @ 7545660
1   -<div class="card" id="resetPasswordForm">
  1 +<div class="row">
  2 + <div class="col s6 offset-s3">
  3 + <div class="card-panel" id="dropClassForm">
  4 + <h2>Notification Settings</h2>
  5 + <!--
  6 + class="js-checkbox" name="notifbox" value="toggle notifs"> -->
  7 + <form action="#">
  8 + <input type="checkbox" id = "notifbox" class="js-checkbox" />
  9 + <label for="notifbox">Enable notifications</label>
  10 + </form>
  11 + </div>
  12 + </div>
  13 +</div>
2 14  
3   - <!--
4   - class="js-checkbox" name="notifbox" value="toggle notifs"> -->
5   - <form action="#">
6   - <input type="checkbox" id = "notifbox" class="js-checkbox" />
7   - <label for="notifbox">Check this to enable notifications</label>
8   - </form>
  15 +<div class="row">
  16 + <div class="col s6 offset-s3">
  17 + <div class="card-panel" id="resetPasswordForm">
9 18  
10   - <h2>Change Password</h2>
  19 + <h2>Change Password</h2>
11 20  
12   - <div class="row">
13   - <form class="col s12">
  21 + <form name="ChangePasswordForm">
14 22  
15   - <div class="row">
16   - <div class="input-field col s12">
17   - <input id="password" type="password" ng-model="oldPassword" class="validate">
18   - <label for="password">Old Password</label>
  23 + <div class="row">
  24 + <div class="input-field col s12">
  25 + <input id="password" required type="password" name="oldpw" ng-model="oldPassword" class="validate">
  26 + <label for="password">Old Password</label>
  27 + </div>
19 28 </div>
20   - </div>
21 29  
22   - <div class="row">
23   - <div class="input-field col s12">
24   - <input id="password" type="password" ng-model="newPassword" class="validate">
25   - <label for="password">New Password</label>
  30 + <div role="alert">
  31 + <span class="error" ng-show="ChangePasswordForm.oldpw.$error.required">
  32 + Required!</span>
26 33 </div>
27   - </div>
28 34  
29   - <div class="row">
30   - <div class="input-field col s12">
31   - <input id="password" type="password" ng-model="confirmedNewPassword" class="validate">
32   - <label for="password">Confirm New Password</label>
  35 +
  36 + <div class="row">
  37 + <div class="input-field col s12">
  38 + <input id="password" required ng-minlength=8 type="password" name="newpw" ng-model="newPassword" class="validate">
  39 + <label for="password">New Password</label>
  40 + </div>
33 41 </div>
34   - </div>
  42 +
  43 + <div role="alert">
  44 + <span class="error" ng-show="ChangePasswordForm.newpw.$error.minlength">
  45 + New password must be at least 8 characters. </span>
  46 + </div>
35 47  
  48 + <div class="row">
  49 + <div class="input-field col s12">
  50 + <input id="password" required ng-minlength=8 compare-to="newpw" type="password" name="confirmpw" ng-model="confirmedNewPassword" class="validate">
  51 + <label for="password">Confirm New Password</label>
  52 + </div>
  53 + </div>
  54 +
  55 + <div role="alert">
  56 + <span class="error" ng-show="ChangePasswordForm.confirm.$error.minlength">
  57 + Must be the same as the new password. </span>
  58 + </div>
36 59  
37   - </form>
38 60  
39   - <a class="waves-effect waves-light btn" id="resetPWButton"
40   - ng-click="changePassword(oldPassword, newPassword, confirmedNewPassword)">Reset Password</a>
41   -
  61 + </form>
  62 + <a class="waves-effect waves-light btn" id="resetPWButton"
  63 + ng-click="changePassword(oldPassword, newPassword, confirmedNewPassword)">Change Password</a>
  64 + </div>
42 65 </div>
  66 +</div>
  67 +
  68 +<div class="row">
  69 + <div class="col s6 offset-s3">
  70 + <div class="card-panel" id="dropClassForm">
  71 +
  72 + <h2>Enrolled Classes</h2>
  73 + <div class="row" style="padding: 0px 25px">
  74 + <table class="hoverable responsive-table">
  75 + <thead>
  76 + <tr>
  77 + <th data-field="id">Class</th>
  78 + <th data-field="drop">Drop?</th>
  79 + </tr>
  80 + </thead>
  81 +
  82 + <tbody>
  83 + <tr ng-repeat="section in UserService.getUserData().sections">
  84 + <td>
  85 + <span>{{section.short_name}}</span>
  86 + <p>{{section.long_name}}</p>
  87 + </td>
  88 + <td><a href="" ng-click="dropClass(section)"><i class="mdi-content-clear small"></i></a></td>
  89 + </tr>
  90 + </tbody>
  91 + </table>
  92 + </div>
  93 + </div>
  94 + </div>
43 95 </div>