Commit 8e3988f5e9d0972b393bab4f9e6c1708015992dc
1 parent
31711803f0
Exists in
master
fix bugs about bolds; allow viewing help without being logged in
Showing 6 changed files with 71 additions and 80 deletions Inline Diff
config.js
View file @
8e3988f
angular.module('flashy', [ | 1 | 1 | angular.module('flashy', [ | |
'flashy.LoginController', | 2 | 2 | 'flashy.LoginController', | |
'flashy.RootController', | 3 | 3 | 'flashy.RootController', | |
'flashy.FeedController', | 4 | 4 | 'flashy.FeedController', | |
'flashy.DeckController', | 5 | 5 | 'flashy.DeckController', | |
'flashy.ClassAddController', | 6 | 6 | 'flashy.ClassAddController', | |
'flashy.RequestResetController', | 7 | 7 | 'flashy.RequestResetController', | |
'flashy.StudyController', | 8 | 8 | 'flashy.StudyController', | |
'flashy.UserService', | 9 | 9 | 'flashy.UserService', | |
'flashy.FlashcardDirective', | 10 | 10 | 'flashy.FlashcardDirective', | |
'flashy.FlashcardFactory', | 11 | 11 | 'flashy.FlashcardFactory', | |
'flashy.ResetPasswordController', | 12 | 12 | 'flashy.ResetPasswordController', | |
'flashy.VerifyEmailController', | 13 | 13 | 'flashy.VerifyEmailController', | |
'flashy.CardListController', | 14 | 14 | 'flashy.CardListController', | |
'flashy.HelpController', | 15 | 15 | 'flashy.HelpController', | |
'flashy.SettingsController', | 16 | 16 | 'flashy.SettingsController', | |
'ngCookies']). | 17 | 17 | 'ngCookies']). | |
config(function($stateProvider, $urlRouterProvider, $resourceProvider, $httpProvider, $locationProvider) { | 18 | 18 | config(function($stateProvider, $urlRouterProvider, $resourceProvider, $httpProvider, $locationProvider) { | |
'use strict'; | 19 | 19 | 'use strict'; | |
$httpProvider.defaults.withCredentials = true; | 20 | 20 | $httpProvider.defaults.withCredentials = true; | |
$httpProvider.defaults.xsrfCookieName = 'csrftoken'; | 21 | 21 | $httpProvider.defaults.xsrfCookieName = 'csrftoken'; | |
$httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken'; | 22 | 22 | $httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken'; | |
$resourceProvider.defaults.stripTrailingSlashes = false; | 23 | 23 | $resourceProvider.defaults.stripTrailingSlashes = false; | |
var arrayMethods = Object.getOwnPropertyNames(Array.prototype); | 24 | 24 | var arrayMethods = Object.getOwnPropertyNames(Array.prototype); | |
arrayMethods.forEach(attachArrayMethodsToNodeList); | 25 | 25 | arrayMethods.forEach(attachArrayMethodsToNodeList); | |
function attachArrayMethodsToNodeList(methodName) { | 26 | 26 | function attachArrayMethodsToNodeList(methodName) { | |
if (methodName !== 'length') { | 27 | 27 | if (methodName !== 'length') { | |
NodeList.prototype[methodName] = Array.prototype[methodName]; | 28 | 28 | NodeList.prototype[methodName] = Array.prototype[methodName]; | |
} | 29 | 29 | } | |
} | 30 | 30 | } | |
31 | 31 | |||
$httpProvider.interceptors.push(function($q, $rootScope) { | 32 | 32 | $httpProvider.interceptors.push(function($q, $rootScope) { | |
return { | 33 | 33 | return { | |
'responseError': function(rejection) { // need a better redirect | 34 | 34 | 'responseError': function(rejection) { // need a better redirect | |
if (rejection.status >= 500) { | 35 | 35 | if (rejection.status >= 500) { | |
console.log('got error'); | 36 | 36 | console.log('got error'); | |
console.log(rejection); | 37 | 37 | console.log(rejection); | |
$rootScope.$broadcast('server_error', rejection); | 38 | 38 | $rootScope.$broadcast('server_error', rejection); | |
} | 39 | 39 | } | |
if (rejection.status == 403) { | 40 | 40 | if (rejection.status == 403) { | |
console.log(rejection); | 41 | 41 | console.log(rejection); | |
if (rejection.data && rejection.data.detail == 'Please verify your email before continuing') { | 42 | 42 | if (rejection.data && rejection.data.detail == 'Please verify your email before continuing') { | |
UserService.showLockedMessage(); | 43 | 43 | UserService.showLockedMessage(); | |
UserService.logout(); | 44 | 44 | UserService.logout(); | |
} | 45 | 45 | } | |
} | 46 | 46 | } | |
if (rejection.status == 429) { | 47 | 47 | if (rejection.status == 429) { | |
console.log(rejection); | 48 | 48 | console.log(rejection); | |
Materialize.toast('Your enthusiasm is appreciated, but we ask that you slow down a little!', 4000); | 49 | 49 | Materialize.toast('Your enthusiasm is appreciated, but we ask that you slow down a little!', 4000); | |
} | 50 | 50 | } | |
return $q.reject(rejection); | 51 | 51 | return $q.reject(rejection); | |
} | 52 | 52 | } | |
}; | 53 | 53 | }; | |
}); | 54 | 54 | }); | |
$locationProvider.html5Mode(true); | 55 | 55 | $locationProvider.html5Mode(true); | |
$urlRouterProvider.otherwise('/login'); | 56 | 56 | $urlRouterProvider.otherwise('/login'); | |
var auth_resolve = { | 57 | 57 | var auth_resolve = { | |
authorize: function($q, $rootScope, $state, $stateParams, UserService) { | 58 | 58 | authorize: function($q, $rootScope, $state, $stateParams, UserService) { | |
console.log('do we need to authorize a user for', $rootScope.nextState.name); | 59 | 59 | console.log('do we need to authorize a user for', $rootScope.nextState.name); | |
if (UserService.noAuthRequired($rootScope.nextState)) { | 60 | 60 | if (UserService.noAuthRequired($rootScope.nextState)) { | |
console.log('no auth required for', $rootScope.nextState.name); | 61 | 61 | console.log('no auth required for', $rootScope.nextState.name); | |
return UserService.getUserData(); | 62 | 62 | return UserService.getUserData(); | |
} | 63 | 63 | } | |
console.log('resolving user before continuing to ' + $rootScope.nextState.name); | 64 | 64 | console.log('resolving user before continuing to ' + $rootScope.nextState.name); | |
var redirectAsNeeded = function() { | 65 | 65 | var redirectAsNeeded = function() { | |
if (!UserService.isLoggedIn()) { | 66 | 66 | if (!UserService.isLoggedIn()) { | |
console.log(UserService.getUserData()); | 67 | 67 | console.log(UserService.getUserData()); | |
console.log('making the user log in'); | 68 | 68 | console.log('making the user log in'); | |
$state.go('login'); | 69 | 69 | $state.go('login'); | |
} | 70 | 70 | } | |
if (!UserService.authorizedFor($rootScope.nextState, $rootScope.nextStateParams)) { | 71 | 71 | if (!UserService.authorizedFor($rootScope.nextState, $rootScope.nextStateParams)) { | |
console.log('user not authorized for ' + $rootScope.nextState.name); | 72 | 72 | console.log('user not authorized for ' + $rootScope.nextState.name); | |
$state.go('addclass'); | 73 | 73 | $state.go('addclass'); | |
} | 74 | 74 | } | |
}; | 75 | 75 | }; | |
if (UserService.isResolved()) return redirectAsNeeded(); | 76 | 76 | if (UserService.isResolved()) return redirectAsNeeded(); | |
return UserService.getUserData().then(redirectAsNeeded); | 77 | 77 | return UserService.getUserData().then(redirectAsNeeded); | |
} | 78 | 78 | } | |
}; | 79 | 79 | }; | |
$stateProvider. | 80 | 80 | $stateProvider. | |
state('login', { | 81 | 81 | state('login', { | |
resolve: auth_resolve, | 82 | 82 | resolve: auth_resolve, | |
url: '/login', | 83 | 83 | url: '/login', | |
templateUrl: 'templates/login.html', | 84 | 84 | templateUrl: 'templates/login.html', | |
controller: 'LoginController' | 85 | 85 | controller: 'LoginController' | |
}). | 86 | 86 | }). | |
state('root', { | 87 | 87 | state('root', { | |
resolve: auth_resolve, | 88 | 88 | resolve: auth_resolve, | |
url: '', | 89 | 89 | url: '', | |
controller: 'RootController' | 90 | 90 | controller: 'RootController' | |
}). | 91 | 91 | }). | |
state('feed', { | 92 | 92 | state('feed', { | |
resolve: auth_resolve, | 93 | 93 | resolve: auth_resolve, | |
url: '/feed/{sectionId}', | 94 | 94 | url: '/feed/{sectionId}', | |
templateUrl: 'templates/feed.html', | 95 | 95 | templateUrl: 'templates/feed.html', | |
controller: 'FeedController' | 96 | 96 | controller: 'FeedController' | |
}). | 97 | 97 | }). | |
state('cardlist', { | 98 | 98 | state('cardlist', { | |
resolve: auth_resolve, | 99 | 99 | resolve: auth_resolve, | |
url: '/cards/{sectionId}', | 100 | 100 | url: '/cards/{sectionId}', | |
templateUrl: 'templates/cardlist.html', | 101 | 101 | templateUrl: 'templates/cardlist.html', | |
controller: 'CardListController' | 102 | 102 | controller: 'CardListController' | |
}). | 103 | 103 | }). | |
state('addclass', { | 104 | 104 | state('addclass', { | |
resolve: auth_resolve, | 105 | 105 | resolve: auth_resolve, | |
url: '/addclass', | 106 | 106 | url: '/addclass', | |
templateUrl: 'templates/addclass.html', | 107 | 107 | templateUrl: 'templates/addclass.html', | |
controller: 'ClassAddController' | 108 | 108 | controller: 'ClassAddController' | |
}). | 109 | 109 | }). | |
state('deck', { | 110 | 110 | state('deck', { | |
resolve: auth_resolve, | 111 | 111 | resolve: auth_resolve, | |
url: '/deck/{sectionId}', | 112 | 112 | url: '/deck/{sectionId}', | |
templateUrl: 'templates/deck.html', | 113 | 113 | templateUrl: 'templates/deck.html', | |
controller: 'DeckController' | 114 | 114 | controller: 'DeckController' | |
}). | 115 | 115 | }). | |
state('study', { | 116 | 116 | state('study', { | |
resolve: auth_resolve, | 117 | 117 | resolve: auth_resolve, | |
url: '/study', | 118 | 118 | url: '/study', | |
templateUrl: 'templates/study.html', | 119 | 119 | templateUrl: 'templates/study.html', | |
controller: 'StudyController' | 120 | 120 | controller: 'StudyController' | |
}). | 121 | 121 | }). | |
/*state('flashcard', { | 122 | 122 | /*state('flashcard', { | |
resolve: auth_resolve, | 123 | 123 | resolve: auth_resolve, | |
url: '/flashcard', | 124 | 124 | url: '/flashcard', | |
templateUrl: 'templates/flashcard.html', | 125 | 125 | templateUrl: 'templates/flashcard.html', | |
controller: 'FlashcardController' | 126 | 126 | controller: 'FlashcardController' | |
}).*/ | 127 | 127 | }).*/ | |
state('settings', { | 128 | 128 | state('settings', { | |
resolve: auth_resolve, | 129 | 129 | resolve: auth_resolve, | |
url: '/settings', | 130 | 130 | url: '/settings', | |
templateUrl: 'templates/settings.html', | 131 | 131 | templateUrl: 'templates/settings.html', | |
controller: 'SettingsController' | 132 | 132 | controller: 'SettingsController' | |
}). | 133 | 133 | }). | |
state('requestpasswordreset', { | 134 | 134 | state('requestpasswordreset', { | |
url: '/requestpasswordreset', | 135 | 135 | url: '/requestpasswordreset', | |
templateUrl: 'templates/requestpasswordreset.html', | 136 | 136 | templateUrl: 'templates/requestpasswordreset.html', | |
controller: 'RequestResetController' | 137 | 137 | controller: 'RequestResetController' | |
}). | 138 | 138 | }). | |
state('resetpassword', { | 139 | 139 | state('resetpassword', { | |
url: '/resetpassword/{uid}/{token}', | 140 | 140 | url: '/resetpassword/{uid}/{token}', | |
templateUrl: 'templates/resetpassword.html', | 141 | 141 | templateUrl: 'templates/resetpassword.html', | |
controller: 'ResetPasswordController' | 142 | 142 | controller: 'ResetPasswordController' | |
}). | 143 | 143 | }). | |
state('verifyemail', { | 144 | 144 | state('verifyemail', { | |
url: '/verifyemail/{key}', | 145 | 145 | url: '/verifyemail/{key}', | |
templateUrl: 'templates/verifyemail.html', | 146 | 146 | templateUrl: 'templates/verifyemail.html', | |
controller: 'VerifyEmailController' | 147 | 147 | controller: 'VerifyEmailController' | |
}). | 148 | 148 | }). | |
state('404', { | 149 | 149 | state('404', { | |
url: '/404', | 150 | 150 | url: '/404', | |
template: "<h1>This page doesn't exist!</h1>" | 151 | 151 | template: "<h1>This page doesn't exist!</h1>" | |
}). | 152 | 152 | }). | |
state('help', { | 153 | 153 | state('help', { | |
resolve: auth_resolve, | 154 | |||
url: '/help', | 155 | 154 | url: '/help', | |
templateUrl: 'templates/help.html', | 156 | 155 | templateUrl: 'templates/help.html', | |
controller: 'HelpController' | 157 | 156 | controller: 'HelpController' | |
}); | 158 | 157 | }); | |
}). | 159 | 158 | }). | |
run(function($rootScope, $state, $stateParams, $location, UserService) { | 160 | 159 | run(function($rootScope, $state, $stateParams, $location, UserService) { | |
$rootScope.$on('$stateChangeError', function(event, toState, toParams, fromState, fromParams, error) { | 161 | 160 | $rootScope.$on('$stateChangeError', function(event, toState, toParams, fromState, fromParams, error) { | |
console.log('failed to change state: ' + error); | 162 | 161 | console.log('failed to change state: ' + error); | |
$state.go('login'); | 163 | 162 | $state.go('login'); | |
}); | 164 | 163 | }); | |
$rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams) { | 165 | 164 | $rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams) { | |
$rootScope.nextState = toState; | 166 | 165 | $rootScope.nextState = toState; | |
$rootScope.nextStateParams = toParams; | 167 | 166 | $rootScope.nextStateParams = toParams; | |
console.log('changing state to', toState); | 168 | 167 | console.log('changing state to', toState); | |
if (['feed', 'deck', 'cardlist'].indexOf(toState.name) >= 0) { | 169 | 168 | if (['feed', 'deck', 'cardlist'].indexOf(toState.name) >= 0) { | |
localStorage.setItem('last_state', toState.name); | 170 | 169 | localStorage.setItem('last_state', toState.name); | |
localStorage.setItem('last_state_params', JSON.stringify(toParams)); | 171 | 170 | localStorage.setItem('last_state_params', JSON.stringify(toParams)); | |
} | 172 | 171 | } | |
}); | 173 | 172 | }); |
home.html
View file @
8e3988f
<!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-sidenav" | 22 | 22 | <a ng-show="UserService.isLoggedIn()" href="#" data-activates="mobile-sidenav" | |
class="left button-collapse hide-on-med-and-up"><i class="mdi-navigation-menu"></i></a> | 23 | 23 | class="left button-collapse hide-on-med-and-up"><i class="mdi-navigation-menu"></i></a> | |
24 | 24 | |||
<!-- User's classes dropdown --> | 25 | 25 | <!-- User's classes dropdown --> | |
<ul id="classDropdown" class="dropdown-content"> | 26 | 26 | <ul id="classDropdown" class="dropdown-content"> | |
<li ui-sref-active="active" ng-repeat="section in UserService.getUserData().sections"> | 27 | 27 | <li ui-sref-active="active" ng-repeat="section in UserService.getUserData().sections"> | |
<a ui-sref="feed({sectionId:section.id})">{{section.short_name}}</a> | 28 | 28 | <a ui-sref="feed({sectionId:section.id})">{{section.short_name}}</a> | |
</li> | 29 | 29 | </li> | |
<li class="divider"></li> | 30 | 30 | <li class="divider"></li> | |
<li><a ui-sref="addclass">Add Class</a></li> | 31 | 31 | <li><a ui-sref="addclass">Add Class</a></li> | |
</ul> | 32 | 32 | </ul> | |
<ul ng-show="UserService.isLoggedIn()" class="left hide-on-small-and-down"> | 33 | 33 | <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" | 34 | 34 | <li><a style="font-size:20px; font-weight:700;" class="dropdown-button ng-cloak hide-on-small-and-down" | |
href="#!" id="class-list" | 35 | 35 | href="#!" id="class-list" | |
data-activates="classDropdown" data-beloworigin="true">{{currentSection.id?currentSection.short_name:"Classes"}}<i | 36 | 36 | data-activates="classDropdown" data-beloworigin="true">{{currentSection.id?currentSection.short_name:"Classes"}}<i | |
class="mdi-navigation-arrow-drop-down right"></i></a></li> | 37 | 37 | 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})" | 38 | 38 | <li ng-show="currentSection.id" ui-sref-active="active"><a ui-sref="feed({sectionId:currentSection.id})" | |
class="tooltipped" | 39 | 39 | class="tooltipped" | |
data-position="bottom" | 40 | 40 | data-position="bottom" | |
data-delay="50" data-tooltip="Feed"><i | 41 | 41 | data-delay="50" data-tooltip="Feed"><i | |
class="mdi-action-view-module"></i></a></li> | 42 | 42 | class="mdi-action-view-module"></i></a></li> | |
<li ng-show="currentSection.id" ui-sref-active="active" id="class-list"><a | 43 | 43 | <li ng-show="currentSection.id" ui-sref-active="active" id="class-list"><a | |
ui-sref="deck({sectionId:currentSection.id})" | 44 | 44 | 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 | |||
57 | <ul ng-cloak id="nav-mobile" class="right hide-on-small-and-down"> | |||
58 | ||||
59 | <li ui-sref-active="active"><a ui-sref="help"><i class="tiny mdi-action-help tooltipped" | |||
60 | data-position="bottom" | |||
61 | data-delay="50" data-tooltip="Help"></i></a></li> | |||
62 | </ul> | |||
<ul ng-show="UserService.isLoggedIn()" ng-cloak id="nav-mobile" class="right hide-on-small-and-down"> | 57 | 63 | <ul ng-show="UserService.isLoggedIn()" ng-cloak id="nav-mobile" class="right hide-on-small-and-down"> | |
58 | 64 | |||
<li ui-sref-active="active"><a ui-sref="study" class="tooltipped" data-position="bottom" data-delay="50" | 59 | 65 | <li ui-sref-active="active"><a ui-sref="study" class="tooltipped" data-position="bottom" data-delay="50" | |
data-tooltip="Study"> | 60 | 66 | data-tooltip="Study"> | |
<i class="tiny mdi-action-pageview"></i></a></li> | 61 | 67 | <i class="tiny mdi-action-pageview"></i></a></li> | |
62 | 68 | |||
<!-- Settings Dropdown --> | 63 | |||
<ul id="settingsDropdown" class="dropdown-content"> | 64 | |||
65 | 69 | |||
66 | ||||
</ul> | 67 | |||
68 | ||||
<li ui-sref-active="active"><a ui-sref="help"><i class="tiny mdi-action-help tooltipped" | 69 | |||
data-position="bottom" | 70 | |||
data-delay="50" data-tooltip="Help"></i></a></li> | 71 | |||
<li ui-sref-active="active"><a ui-sref="settings"><i data-position="bottom" data-delay="50" | 72 | 70 | <li ui-sref-active="active"><a ui-sref="settings"><i data-position="bottom" data-delay="50" | |
data-tooltip="Settings" | 73 | 71 | data-tooltip="Settings" | |
class="mdi-action-settings tooltipped"></i></a></li> | 74 | 72 | 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 | 73 | <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 | 74 | class="mdi-content-forward tooltipped"></i></a></li> | |
77 | 75 | |||
</ul> | 78 | 76 | </ul> | |
79 | 77 | |||
<!-- Slide-in side-nav for small screens --> | 80 | 78 | <!-- Slide-in side-nav for small screens --> | |
<ul ng-show="UserService.isLoggedIn()" class="side-nav" id="mobile-sidenav"> | 81 | 79 | <ul ng-show="UserService.isLoggedIn()" class="side-nav" id="mobile-sidenav"> | |
<span ng-show="currentSection.id"> | 82 | 80 | <span ng-show="currentSection.id"> | |
<li ui-sref-active="active"><a ui-sref="feed({sectionId:currentSection.id})"> | 83 | 81 | <li ui-sref-active="active"><a ui-sref="feed({sectionId:currentSection.id})"> | |
<i class="mdi-action-view-module left"></i> | 84 | 82 | <i class="mdi-action-view-module left"></i> | |
Feed</a> | 85 | 83 | Feed</a> | |
</li> | 86 | 84 | </li> | |
<li ui-sref-active="active"><a ui-sref="deck({sectionId:currentSection.id})"> | 87 | 85 | <li ui-sref-active="active"><a ui-sref="deck({sectionId:currentSection.id})"> | |
<i class="mdi-action-view-carousel left"> </i> | 88 | 86 | <i class="mdi-action-view-carousel left"> </i> | |
Deck | 89 | 87 | Deck | |
</a> | 90 | 88 | </a> | |
</li> | 91 | 89 | </li> | |
<li ui-sref-active="active"><a ui-sref="cardlist({sectionId:currentSection.id})"> | 92 | 90 | <li ui-sref-active="active"><a ui-sref="cardlist({sectionId:currentSection.id})"> | |
<i class="mdi-action-view-list left"></i> | 93 | 91 | <i class="mdi-action-view-list left"></i> | |
Card List | 94 | 92 | Card List | |
</a> | 95 | 93 | </a> | |
</li> | 96 | 94 | </li> | |
<hr> | 97 | 95 | <hr> | |
</span> | 98 | 96 | </span> | |
<!-- Collapsible menu for all the User's classes --> | 99 | 97 | <!-- Collapsible menu for all the User's classes --> | |
<ul class="collapsible" data-collapsible="accordion"> | 100 | 98 | <ul class="collapsible" data-collapsible="accordion"> | |
<li class="bold"> | 101 | 99 | <li class="bold"> | |
<a class="collapsible-header black-text"> | 102 | 100 | <a class="collapsible-header black-text"> | |
Classes | 103 | 101 | Classes | |
<i class="mdi-navigation-arrow-drop-down right"></i> | 104 | 102 | <i class="mdi-navigation-arrow-drop-down right"></i> | |
</a> | 105 | 103 | </a> | |
</li> | 106 | 104 | </li> | |
<div class="collapsible-body" style="display: block"> | 107 | 105 | <div class="collapsible-body" style="display: block"> | |
<ul> | 108 | 106 | <ul> | |
<li ui-sref-active="active" ng-repeat="section in UserService.getUserData().sections"> | 109 | 107 | <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> | 110 | 108 | <a class="class bold" ui-sref="feed({sectionId:section.id})">{{section.short_name}}</a> | |
</li> | 111 | 109 | </li> | |
<hr> | 112 | 110 | <hr> | |
<li><a ui-sref="addclass"><i class="tiny mdi-content-add">Add Class</i></a></li> | 113 | 111 | <li><a ui-sref="addclass"><i class="tiny mdi-content-add">Add Class</i></a></li> | |
</ul> | 114 | 112 | </ul> | |
</div> | 115 | 113 | </div> | |
</ul> | 116 | 114 | </ul> | |
<li><a ui-sref="study">Study</a></li> | 117 | 115 | <li><a ui-sref="study">Study</a></li> | |
<li><a ui-sref="settings">Settings</a></li> | 118 | 116 | <li><a ui-sref="settings">Settings</a></li> | |
<li><a ui-sref="help">FAQ</a></li> | 119 | 117 | <li><a ui-sref="help">FAQ</a></li> | |
<li><a ng-click="logout()">Logout</a></li> | 120 | 118 | <li><a ng-click="logout()">Logout</a></li> | |
</ul> | 121 | 119 | </ul> | |
</div> | 122 | 120 | </div> | |
</nav> | 123 | 121 | </nav> | |
124 | 122 | |||
</header> | 125 | 123 | </header> | |
126 | 124 | |||
127 | 125 | |||
<!-- Menu Bar --> | 128 | 126 | <!-- Menu Bar --> | |
<main ui-view></main> | 129 | 127 | <main ui-view></main> | |
130 | 128 | |||
</body> | 131 | 129 | </body> | |
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.js"></script> | 132 | 130 | <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> | 133 | 131 | <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> | 134 | 132 | <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> | 135 | 133 | <script src="//code.jquery.com/jquery-2.1.4.min.js"></script> | |
<script type="text/javascript" src="scripts/materialize.js"></script> | 136 | 134 | <script type="text/javascript" src="scripts/materialize.js"></script> | |
<script type="text/javascript" src="scripts/jquery.collapsible.js"></script> | 137 | 135 | <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> | 138 | 136 | <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> | 139 | 137 | <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> | 140 | 138 | <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> | 141 | 139 | <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> | 142 | 140 | <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular-sanitize.js"></script> | |
<script src="static/js/angular-websocket.js"></script> | 143 | 141 | <script src="static/js/angular-websocket.js"></script> | |
<script src="static/js/angular-contenteditable.js"></script> | 144 | 142 | <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> | 145 | 143 | <script src="https://cdnjs.cloudflare.com/ajax/libs/angular-filter/0.5.4/angular-filter.js"></script> | |
146 | 144 | |||
<script src="config.js"></script> | 147 | 145 | <script src="config.js"></script> | |
148 | 146 | |||
<script src="scripts/FlashcardFactory.js"></script> | 149 | 147 | <script src="scripts/FlashcardFactory.js"></script> | |
<script src="scripts/DeckFactory.js"></script> | 150 | 148 | <script src="scripts/DeckFactory.js"></script> | |
151 | 149 | |||
<!-- Controllers --> | 152 | 150 | <!-- Controllers --> | |
<script src="scripts/FeedController.js"></script> | 153 | 151 | <script src="scripts/FeedController.js"></script> | |
<script src="scripts/RootController.js"></script> | 154 | 152 | <script src="scripts/RootController.js"></script> | |
<script src="scripts/SettingsController.js"></script> | 155 | 153 | <script src="scripts/SettingsController.js"></script> |
scripts/FeedController.js
View file @
8e3988f
angular.module('flashy.FeedController', | 1 | 1 | angular.module('flashy.FeedController', | |
['ui.router', | 2 | 2 | ['ui.router', | |
'ngAnimate', | 3 | 3 | 'ngAnimate', | |
'ngWebSocket', | 4 | 4 | 'ngWebSocket', | |
'contenteditable', | 5 | 5 | 'contenteditable', | |
'flashy.DeckFactory']).controller('FeedController', | 6 | 6 | 'flashy.DeckFactory']).controller('FeedController', | |
function($scope, $rootScope, $state, $http, $window, $timeout, $stateParams, $websocket, $interval, UserService, Flashcard, Deck) { | 7 | 7 | function($scope, $rootScope, $state, $http, $window, $timeout, $stateParams, $websocket, $interval, UserService, Flashcard, Deck) { | |
angular.module('flashy.CardGridController').CardGridController.apply(this, arguments); | 8 | 8 | angular.module('flashy.CardGridController').CardGridController.apply(this, arguments); | |
var promise; | 9 | 9 | var promise; | |
sectionId = parseInt($stateParams.sectionId); | 10 | 10 | sectionId = parseInt($stateParams.sectionId); | |
$scope.updateCardScore = function(card, scoreChange) { | 11 | 11 | $scope.updateCardScore = function(card, scoreChange) { | |
console.log('update card score'); | 12 | 12 | console.log('update card score'); | |
// if no colNum is attached, then this doesn't exist on the feed yet | 13 | 13 | // if no colNum is attached, then this doesn't exist on the feed yet | |
if (typeof card.colNum === 'undefined' || typeof card.colRank === 'undefined') { | 14 | 14 | if (typeof card.colNum === 'undefined' || typeof card.colRank === 'undefined') { | |
console.log('no col num'); | 15 | 15 | console.log('no col num'); | |
return; | 16 | 16 | return; | |
} | 17 | 17 | } | |
/*$scope.cardCols[card.colNum].sort(function(a, b) { | 18 | 18 | /*$scope.cardCols[card.colNum].sort(function(a, b) { | |
return b.score - a.score; | 19 | 19 | return b.score - a.score; | |
}); | 20 | 20 | }); | |
console.log($scope.cardCols); | 21 | 21 | console.log($scope.cardCols); | |
$scope.updateColRanks($scope.cardCols[card.colNum]); | 22 | 22 | $scope.updateColRanks($scope.cardCols[card.colNum]); | |
return;*/ | 23 | 23 | return;*/ | |
console.log(card.score); | 24 | 24 | console.log(card.score); | |
card.score += scoreChange; | 25 | 25 | card.score += scoreChange; | |
console.log(card.score); | 26 | 26 | console.log(card.score); | |
var col = card.colNum; | 27 | 27 | var col = card.colNum; | |
var rank = card.colRank; | 28 | 28 | var rank = card.colRank; | |
var s = Math.sign(scoreChange); | 29 | 29 | var s = Math.sign(scoreChange); | |
30 | 30 | |||
//rank -= s; | 31 | 31 | //rank -= s; | |
if (rank < 0) return; | 32 | 32 | if (rank < 0) return; | |
if (rank == $scope.cardCols[col].length) return; | 33 | 33 | if (rank == $scope.cardCols[col].length) return; | |
34 | 34 | |||
$scope.affectedCards = []; | 35 | 35 | $scope.affectedCards = []; | |
//console.log('before whiel, rank:' + rank); | 36 | 36 | //console.log('before whiel, rank:' + rank); | |
if (s > 0) { | 37 | 37 | if (s > 0) { | |
rank -= 1; | 38 | 38 | rank -= 1; | |
//console.log('+'); | 39 | 39 | //console.log('+'); | |
while ($scope.cardCols[col][rank].score < card.score) { | 40 | 40 | while ($scope.cardCols[col][rank].score < card.score) { | |
//console.log('while'); | 41 | 41 | //console.log('while'); | |
$scope.cardCols[col][rank].colRank += 1; | 42 | 42 | $scope.cardCols[col][rank].colRank += 1; | |
$scope.affectedCards.push($scope.cardCols[col][rank]); | 43 | 43 | $scope.affectedCards.push($scope.cardCols[col][rank]); | |
rank -= 1; | 44 | 44 | rank -= 1; | |
if (rank < 0) break; | 45 | 45 | if (rank < 0) break; | |
if (rank == $scope.cardCols[col].length) break; | 46 | 46 | if (rank == $scope.cardCols[col].length) break; | |
} | 47 | 47 | } | |
} else { | 48 | 48 | } else { | |
rank += 1; | 49 | 49 | rank += 1; | |
console.log('-'); | 50 | 50 | console.log('-'); | |
while ($scope.cardCols[col][rank].score > card.score) { | 51 | 51 | while ($scope.cardCols[col][rank].score > card.score) { | |
//console.log('while'); | 52 | 52 | //console.log('while'); | |
$scope.cardCols[col][rank].colRank -= 1; | 53 | 53 | $scope.cardCols[col][rank].colRank -= 1; | |
$scope.affectedCards.push($scope.cardCols[col][rank]); | 54 | 54 | $scope.affectedCards.push($scope.cardCols[col][rank]); | |
rank += 1; | 55 | 55 | rank += 1; | |
if (rank < 0) break; | 56 | 56 | if (rank < 0) break; | |
if (rank == $scope.cardCols[col].length) break; | 57 | 57 | if (rank == $scope.cardCols[col].length) break; | |
} | 58 | 58 | } | |
} | 59 | 59 | } | |
rank += s; | 60 | 60 | rank += s; | |
//console.log('after a whiel, rank:' + rank); | 61 | 61 | //console.log('after a whiel, rank:' + rank); | |
62 | 62 | |||
console.log($scope.affectedCards); | 63 | 63 | console.log($scope.affectedCards); | |
64 | 64 | |||
var upMove = $scope.height; | 65 | 65 | var upMove = $scope.height; | |
var downMove = $scope.height; | 66 | 66 | var downMove = $scope.height; | |
$scope.$apply(function() { | 67 | 67 | $scope.$apply(function() { | |
$('.card.flashy.card-moveUp').css({ | 68 | 68 | $('.card.flashy.card-moveUp').css({ | |
'margin-top': 300 + 'px !important', // how much moveUp moves | 69 | 69 | 'margin-top': 300 + 'px !important', // how much moveUp moves | |
}); | 70 | 70 | }); | |
71 | 71 | |||
$('.card.flashy.card-moveDown').css({ | 72 | 72 | $('.card.flashy.card-moveDown').css({ | |
'margin-top': 300 + 'px !important', // how much moveDown moves | 73 | 73 | 'margin-top': 300 + 'px !important', // how much moveDown moves | |
}); | 74 | 74 | }); | |
}); | 75 | 75 | }); | |
76 | 76 | |||
if (s > 0) { | 77 | 77 | if (s > 0) { | |
card.moveUp = true; | 78 | 78 | card.moveUp = true; | |
upMove *= $scope.affectedCards.length; | 79 | 79 | upMove *= $scope.affectedCards.length; | |
/*for (i=0; i<$scope.affectedCards.length; i++) { | 80 | 80 | /*for (i=0; i<$scope.affectedCards.length; i++) { | |
$scope.affectedCards[i].moveDown = true; | 81 | 81 | $scope.affectedCards[i].moveDown = true; | |
}*/ | 82 | 82 | }*/ | |
} else { | 83 | 83 | } else { | |
card.moveDown = true; | 84 | 84 | card.moveDown = true; | |
downMove *= $scope.affectedCards; | 85 | 85 | downMove *= $scope.affectedCards; | |
/*for (i=0; i<$scope.affectedCards.length; i++) { | 86 | 86 | /*for (i=0; i<$scope.affectedCards.length; i++) { | |
$scope.affectedCards[i].moveUp = true; | 87 | 87 | $scope.affectedCards[i].moveUp = true; | |
}*/ | 88 | 88 | }*/ | |
} | 89 | 89 | } | |
90 | 90 | |||
$timeout(function() { | 91 | 91 | $timeout(function() { | |
$('.card.flashy.card-moveUp').css({ | 92 | 92 | $('.card.flashy.card-moveUp').css({ | |
'margin-top': '6px', | 93 | 93 | 'margin-top': '6px', | |
}); | 94 | 94 | }); | |
95 | 95 | |||
$('.card.flashy.card-moveDown').css({ | 96 | 96 | $('.card.flashy.card-moveDown').css({ | |
'margin-top': '6px', | 97 | 97 | 'margin-top': '6px', | |
}); | 98 | 98 | }); | |
if (s > 0) { | 99 | 99 | if (s > 0) { | |
card.moveUp = false; | 100 | 100 | card.moveUp = false; | |
for (i = 0; i < $scope.affectedCards.length; i++) { | 101 | 101 | for (i = 0; i < $scope.affectedCards.length; i++) { | |
$scope.affectedCards[i].moveDown = false; | 102 | 102 | $scope.affectedCards[i].moveDown = false; | |
} | 103 | 103 | } | |
} else { | 104 | 104 | } else { | |
card.moveDown = false; | 105 | 105 | card.moveDown = false; | |
for (i = 0; i < $scope.affectedCards.length; i++) { | 106 | 106 | for (i = 0; i < $scope.affectedCards.length; i++) { | |
$scope.affectedCards[i].moveUp = false; | 107 | 107 | $scope.affectedCards[i].moveUp = false; | |
} | 108 | 108 | } | |
} | 109 | 109 | } | |
}, 1000); | 110 | 110 | }, 1000); | |
$scope.cardCols[col].splice(rank, 0, $scope.cardCols[col].splice(card.colRank, 1)[0]); | 111 | 111 | $scope.cardCols[col].splice(rank, 0, $scope.cardCols[col].splice(card.colRank, 1)[0]); | |
card.colRank = rank; | 112 | 112 | card.colRank = rank; | |
//$scope.updateColRanks($scope.cardCols[card.colNum]); // can be optimized out | 113 | 113 | //$scope.updateColRanks($scope.cardCols[card.colNum]); // can be optimized out | |
}; | 114 | 114 | }; | |
115 | 115 | |||
$scope.feed_ws = $websocket($scope.ws_host + '/ws/feed/' + sectionId + '?subscribe-broadcast'); | 116 | 116 | $scope.feed_ws = $websocket($scope.ws_host + '/ws/feed/' + sectionId + '?subscribe-broadcast'); | |
$scope.feed_ws.onMessage(function(e) { | 117 | 117 | $scope.feed_ws.onMessage(function(e) { | |
data = JSON.parse(e.data); | 118 | 118 | data = JSON.parse(e.data); | |
console.log(data.event_type, 'message', data.flashcard); | 119 | 119 | console.log(data.event_type, 'message', data.flashcard); | |
if (data.event_type == 'new_card') { | 120 | 120 | if (data.event_type == 'new_card') { | |
$scope.addCardToGrid(new Flashcard(data.flashcard, $scope.deck)); | 121 | 121 | $scope.addCardToGrid(new Flashcard(data.flashcard, $scope.deck)); | |
} else if (data.event_type == 'score_change') { | 122 | 122 | } else if (data.event_type == 'score_change') { | |
card = new Flashcard(data.flashcard); // doesnt create a card if it exists | 123 | 123 | card = new Flashcard(data.flashcard); // doesnt create a card if it exists | |
//card.score = data.flashcard.score; | 124 | 124 | //card.score = data.flashcard.score; | |
console.log('score change'); | 125 | 125 | console.log('score change'); | |
$scope.updateCardScore(card, data.flashcard.score - card.score); | 126 | 126 | $scope.updateCardScore(card, data.flashcard.score - card.score); | |
} | 127 | 127 | } | |
}); | 128 | 128 | }); | |
129 | 129 | |||
$scope.pushCard = function() { | 130 | 130 | $scope.pushCard = function() { | |
var myCard = { | 131 | 131 | var myCard = { | |
// we can't trim this string because it'd mess up the blanks. Something to fix. | 132 | 132 | // we can't trim this string because it'd mess up the blanks. Something to fix. | |
'text': $('#new-card-input').text(), | 133 | 133 | 'text': $('#new-card-input').text(), | |
'mask': $scope.newCardBlanks, | 134 | 134 | 'mask': $scope.newCardBlanks, | |
section: $scope.section.id | 135 | 135 | section: $scope.section.id | |
}; | 136 | 136 | }; | |
if (!$scope.submit_enabled) { | 137 | 137 | if (!$scope.submit_enabled) { | |
return; | 138 | 138 | return; | |
} | 139 | 139 | } | |
if (myCard.text == '') { | 140 | 140 | if (myCard.text == '') { | |
console.log('blank flashcard not pushed:' + myCard.text); | 141 | 141 | console.log('blank flashcard not pushed:' + myCard.text); | |
return closeNewCard(); | 142 | 142 | return closeNewCard(); | |
} | 143 | 143 | } | |
$http.post('/api/flashcards/', myCard). | 144 | 144 | $http.post('/api/flashcards/', myCard). | |
success(function(data) { | 145 | 145 | success(function(data) { | |
console.log('flashcard pushed: ' + myCard.text); | 146 | 146 | console.log('flashcard pushed: ' + myCard.text); | |
if (!UserService.hasVerifiedEmail()) { | 147 | 147 | if (!UserService.hasVerifiedEmail()) { | |
Materialize.toast("<p>Thanks for contributing! However, others won't see your card until you verify your email address<p>", 4000); | 148 | 148 | Materialize.toast("<p>Thanks for contributing! However, others won't see your card until you verify your email address<p>", 4000); | |
} | 149 | 149 | } | |
}); | 150 | 150 | }); | |
return $scope.closeNewCardModal(); | 151 | 151 | return $scope.closeNewCardModal(); | |
}; | 152 | 152 | }; | |
153 | 153 | |||
/* Key bindings for the whole feed window. Hotkey it up! */ | 154 | 154 | /* Key bindings for the whole feed window. Hotkey it up! */ | |
var listenForC = true; | 155 | 155 | var listenForC = true; | |
156 | 156 | |||
// Need to pass these options into openmodal and leanmodal, | 157 | 157 | // Need to pass these options into openmodal and leanmodal, | |
// otherwise the ready handler doesn't get called | 158 | 158 | // otherwise the ready handler doesn't get called | |
159 | 159 | |||
modal_options = { | 160 | 160 | modal_options = { | |
dismissible: true, // Modal can be dismissed by clicking outside of the modal | 161 | 161 | dismissible: true, // Modal can be dismissed by clicking outside of the modal | |
opacity: 0, // Opacity of modal background | 162 | 162 | opacity: 0, // Opacity of modal background | |
in_duration: 300, // Transition in duration | 163 | 163 | in_duration: 300, // Transition in duration | |
out_duration: 200, // Transition out duration | 164 | 164 | out_duration: 200, // Transition out duration | |
ready: function() { | 165 | 165 | ready: function() { | |
$('#new-card-input').focus(); | 166 | 166 | $('#new-card-input').focus(); | |
document.execCommand('selectAll', false, null); | 167 | 167 | document.execCommand('selectAll', false, null); | |
} | 168 | 168 | } | |
}; | 169 | 169 | }; | |
170 | 170 | |||
$(document).keydown(function(e) { | 171 | 171 | $(document).keydown(function(e) { | |
var keyed = e.which; | 172 | 172 | var keyed = e.which; | |
if (keyed == 67 && listenForC) { // "c" for compose | 173 | 173 | if (keyed == 67 && listenForC) { // "c" for compose | |
if ($scope.currentEditingCard) return; | 174 | 174 | if ($scope.currentEditingCard) return; | |
$scope.openNewCardModal(); | 175 | 175 | $scope.openNewCardModal(); | |
e.preventDefault(); | 176 | 176 | e.preventDefault(); | |
return false; | 177 | 177 | return false; | |
} else if (keyed == 27) { // clear on ESC | 178 | 178 | } else if (keyed == 27) { // clear on ESC | |
$scope.closeNewCardModal(); | 179 | 179 | $scope.closeNewCardModal(); | |
$scope.discardEditChanges(); | 180 | 180 | $scope.discardEditChanges(); | |
} | 181 | 181 | } | |
}); | 182 | 182 | }); | |
183 | 183 | |||
$scope.openNewCardModal = function() { | 184 | 184 | $scope.openNewCardModal = function() { | |
$('#newCard').openModal(modal_options); | 185 | 185 | $('#newCard').openModal(modal_options); | |
listenForC = false; | 186 | 186 | listenForC = false; | |
$('#new-card-input').html('Write a flashcard!'); | 187 | 187 | $('#new-card-input').html('Write a flashcard!'); | |
}; | 188 | 188 | }; | |
189 | 189 | |||
$scope.closeNewCardModal = function() { | 190 | 190 | $scope.closeNewCardModal = function() { | |
listenForC = true; | 191 | 191 | listenForC = true; | |
$('#new-card-input').html('').blur(); | 192 | 192 | $('#new-card-input').html('').blur(); | |
$('#newCard').closeModal(modal_options); | 193 | 193 | $('#newCard').closeModal(modal_options); | |
}; | 194 | 194 | }; | |
195 | 195 | |||
$('.tooltipped').tooltip({delay: 50}); | 196 | 196 | $('.tooltipped').tooltip({delay: 50}); | |
// the "href" attribute of .modal-trigger must specify the modal ID that wants to be triggered | 197 | 197 | // the "href" attribute of .modal-trigger must specify the modal ID that wants to be triggered | |
$('.modal-trigger').leanModal(modal_options); | 198 | 198 | $('.modal-trigger').leanModal(modal_options); | |
199 | 199 | |||
$('#new-card-input').on('keydown', function(e) { | 200 | 200 | $('#new-card-input').on('keydown', function(e) { | |
if (e.which == 13) { | 201 | 201 | if (e.which == 13) { | |
e.preventDefault(); | 202 | 202 | e.preventDefault(); | |
if ($scope.submit_enabled) { | 203 | 203 | if ($scope.submit_enabled) { | |
$scope.pushCard(); | 204 | 204 | $scope.pushCard(); | |
} | 205 | 205 | } | |
return false; | 206 | 206 | return false; | |
} | 207 | 207 | } | |
}); | 208 | 208 | }); | |
209 | 209 | |||
$('button#blank-selected').click(function() { | 210 | 210 | ||
console.log(window.getSelection()); | 211 | |||
document.execCommand('bold'); | 212 | |||
}); | 213 | |||
$scope.newCardBlanks = []; | 214 | 211 | $scope.newCardBlanks = []; | |
$scope.refreshNewCardInput = function() { | 215 | 212 | $scope.refreshNewCardInput = function() { | |
$scope.newCardText = $('#new-card-input').text(); | 216 | 213 | $scope.newCardText = $('#new-card-input').text(); | |
$scope.submit_enabled = $scope.newCardText.length >= 5 && $scope.newCardText.length <= 160; | 217 | 214 | $scope.submit_enabled = $scope.newCardText.length >= 5 && $scope.newCardText.length <= 160; | |
var i = 0; | 218 | 215 | var i = 0; | |
$scope.newCardBlanks = []; | 219 | 216 | $scope.newCardBlanks = []; | |
$('#new-card-input')[0].childNodes.forEach(function(node) { | 220 | 217 | $('#new-card-input')[0].childNodes.forEach(function(node) { | |
node = $(node)[0]; | 221 | 218 | node = $(node)[0]; | |
if (node.tagName == 'B') { | 222 | 219 | if (node.tagName == 'B') { | |
var text = $(node).text(); | 223 | 220 | var text = $(node).text(); | |
var leftspaces = 0, rightspaces = 0; | 224 | 221 | var leftspaces = 0, rightspaces = 0; | |
// awful way to find the first non-space character from the left or the right. thanks.js | 225 | 222 | // awful way to find the first non-space character from the left or the right. thanks.js | |
while (text[leftspaces] == ' ' || text[leftspaces] == '\xa0') leftspaces++; | 226 | 223 | while (text[leftspaces] == ' ' || text[leftspaces] == '\xa0') leftspaces++; | |
while (text[text.length - 1 - rightspaces] == ' ' || text[text.length - 1 - rightspaces] == '\xa0') rightspaces++; | 227 | 224 | while (text[text.length - 1 - rightspaces] == ' ' || text[text.length - 1 - rightspaces] == '\xa0') rightspaces++; | |
console.log(leftspaces, text.length); | 228 | 225 | console.log(leftspaces, text.length); | |
if (leftspaces != text.length) $scope.newCardBlanks.push([i + leftspaces, i + text.length - rightspaces]); | 229 | 226 | if (leftspaces != text.length) $scope.newCardBlanks.push([i + leftspaces, i + text.length - rightspaces]); | |
i += text.length; | 230 | 227 | i += text.length; | |
} else if (!node.data) { | 231 | 228 | } else if (!node.data) { | |
i += $(node).text().length; | 232 | 229 | i += $(node).text().length; | |
} else { | 233 | 230 | } else { | |
i += node.data.length; | 234 | 231 | i += node.data.length; | |
} | 235 | 232 | } | |
}); | 236 | 233 | }); | |
$scope.newCardBlanks.sort(function(a, b) { | 237 | 234 | $scope.newCardBlanks.sort(function(a, b) { | |
return a[0] - b[0]; | 238 | 235 | return a[0] - b[0]; | |
}); | 239 | 236 | }); | |
i = 0; | 240 | 237 | i = 0; | |
newtext = ''; | 241 | 238 | newtext = ''; | |
$scope.newCardBlanks.forEach(function(blank) { | 242 | 239 | $scope.newCardBlanks.forEach(function(blank) { | |
newtext += $scope.newCardText.slice(i, blank[0]); | 243 | 240 | newtext += $scope.newCardText.slice(i, blank[0]); | |
newtext += '<b>' + $scope.newCardText.slice(blank[0], blank[1]) + '</b>'; | 244 | 241 | newtext += '<b>' + $scope.newCardText.slice(blank[0], blank[1]) + '</b>'; | |
i = blank[1]; | 245 | 242 | i = blank[1]; | |
}); | 246 | 243 | }); | |
newtext += $scope.newCardText.slice(i); | 247 | 244 | newtext += $scope.newCardText.slice(i); | |
//$scope.newCardFormattedText = newtext; | 248 | 245 | //$scope.newCardFormattedText = newtext; | |
}; | 249 | 246 | }; | |
$scope.shuffleCards = function() { | 250 | 247 | $scope.shuffleCards = function() { | |
$timeout(function() { | 251 | 248 | $timeout(function() { | |
(function(o) { | 252 | 249 | (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); | 253 | 250 | 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; | 254 | 251 | return o; | |
})($scope.cardCols[0]); | 255 | 252 | })($scope.cardCols[0]); | |
}); | 256 | 253 | }); | |
}; | 257 | 254 | }; |
scripts/FlashcardFactory.js
View file @
8e3988f
angular.module('flashy.FlashcardFactory', ['ui.router']). | 1 | 1 | angular.module('flashy.FlashcardFactory', ['ui.router']). | |
factory('Flashcard', function ($http, UserService) { | 2 | 2 | factory('Flashcard', function ($http, UserService) { | |
var FlashcardCache = []; | 3 | 3 | var FlashcardCache = []; | |
var Deck = null; | 4 | 4 | var Deck = null; | |
var Flashcard = function (data) { | 5 | 5 | var Flashcard = function (data) { | |
if (typeof data == 'number') return FlashcardCache[data]; | 6 | 6 | if (typeof data == 'number') return FlashcardCache[data]; | |
if (FlashcardCache[data.id]) return FlashcardCache[data.id]; | 7 | 7 | if (FlashcardCache[data.id]) return FlashcardCache[data.id]; | |
for (var k in data) this[k] = data[k]; | 8 | 8 | for (var k in data) this[k] = data[k]; | |
this.mask = data.display_mask; | 9 | 9 | this.mask = data.display_mask; | |
this.moveUp = false; | 10 | 10 | this.moveUp = false; | |
this.moveDown = false; | 11 | 11 | this.moveDown = false; | |
FlashcardCache[this.id] = this; | 12 | 12 | FlashcardCache[this.id] = this; | |
this.refreshFormattedText(); | 13 | 13 | this.refreshFormattedText(); | |
}; | 14 | 14 | }; | |
Flashcard.prototype.refreshFormattedText = function () { | 15 | 15 | Flashcard.prototype.refreshFormattedText = function () { | |
this.textPieces = []; | 16 | 16 | this.textPieces = []; | |
this.mask.sort(function (a, b) { | 17 | 17 | this.mask.sort(function (a, b) { | |
return a[0] - b[0]; | 18 | 18 | return a[0] - b[0]; | |
}); | 19 | 19 | }); | |
var i = 0; | 20 | 20 | var i = 0; | |
this.mask.forEach(function (blank) { | 21 | 21 | this.mask.forEach(function (blank) { | |
this.textPieces.push({text: this.text.slice(i, blank[0])}); | 22 | 22 | this.textPieces.push({text: this.text.slice(i, blank[0])}); | |
this.textPieces.push({text: this.text.slice(blank[0], blank[1]), blank: true}); | 23 | 23 | this.textPieces.push({text: this.text.slice(blank[0], blank[1]), blank: true}); | |
i = blank[1]; | 24 | 24 | i = blank[1]; | |
}, this); | 25 | 25 | }, this); | |
this.textPieces.push({text: this.text.slice(i)}); | 26 | 26 | this.textPieces.push({text: this.text.slice(i)}); | |
this.formatted_text = ''; | 27 | 27 | this.formatted_text = ''; | |
for (i in this.textPieces) { | 28 | 28 | for (i in this.textPieces) { | |
p = this.textPieces[i]; | 29 | 29 | p = this.textPieces[i]; | |
this.formatted_text += p.blank ? '<b>' + p.text + '</b>' : p.text; | 30 | 30 | this.formatted_text += p.blank ? '<b>' + p.text + '</b>' : p.text; | |
} | 31 | 31 | } | |
return this; | 32 | 32 | return this; | |
}; | 33 | 33 | }; | |
Flashcard.prototype.isAuthoredByUser = function () { | 34 | 34 | Flashcard.prototype.isAuthoredByUser = function () { | |
return this.is_authored_by_user; | 35 | 35 | return this.is_authored_by_user; | |
}; | 36 | 36 | }; | |
Flashcard.prototype.isInDeck = function () { | 37 | 37 | Flashcard.prototype.isInDeck = function () { | |
return !(typeof Deck.contains(this.id) === 'undefined'); | 38 | 38 | return !(typeof Deck.contains(this.id) === 'undefined'); | |
}; | 39 | 39 | }; | |
Flashcard.prototype.pullUnpull = function () { | 40 | 40 | Flashcard.prototype.pullUnpull = function () { | |
if (this.isInDeck()) this.unpull(); | 41 | 41 | if (this.isInDeck()) this.unpull(); | |
else this.pull(); | 42 | 42 | else this.pull(); | |
}; | 43 | 43 | }; | |
Flashcard.prototype.pull = function () { | 44 | 44 | Flashcard.prototype.pull = function () { | |
if (this.isInDeck()) return console.log('Not pulling', this.id, "because it's already in deck"); | 45 | 45 | if (this.isInDeck()) return console.log('Not pulling', this.id, "because it's already in deck"); | |
return $http.post('/api/flashcards/' + this.id + '/pull/'); | 46 | 46 | return $http.post('/api/flashcards/' + this.id + '/pull/'); | |
}; | 47 | 47 | }; | |
Flashcard.prototype.unpull = function () { | 48 | 48 | Flashcard.prototype.unpull = function () { | |
if (!this.isInDeck()) return console.log('Not unpulling', this.id, "because it's not in deck"); | 49 | 49 | if (!this.isInDeck()) return console.log('Not unpulling', this.id, "because it's not in deck"); | |
return $http.post('/api/flashcards/' + this.id + '/unpull/'); | 50 | 50 | return $http.post('/api/flashcards/' + this.id + '/unpull/'); | |
}; | 51 | 51 | }; | |
Flashcard.prototype.hide = function () { | 52 | 52 | Flashcard.prototype.hide = function () { | |
return $http.post('/api/flashcards/' + this.id + '/hide/'); | 53 | 53 | return $http.post('/api/flashcards/' + this.id + '/hide/'); | |
}; | 54 | 54 | }; | |
Flashcard.prototype.report = function (reason) { | 55 | 55 | Flashcard.prototype.report = function (reason) { | |
if (!reason) reason = 'unspecified'; | 56 | 56 | if (!reason) reason = 'unspecified'; | |
this.isReported = true; | 57 | 57 | this.isReported = true; | |
return $http.post('/api/flashcards/' + this.id + '/report/', {reason: reason}).success(function () { | 58 | 58 | return $http.post('/api/flashcards/' + this.id + '/report/', {reason: reason}).success(function () { | |
Materialize.toast('Report successful; thanks for letting us know!', 4000); | 59 | 59 | Materialize.toast('Report successful; thanks for letting us know!', 4000); | |
}); | 60 | 60 | }); | |
}; | 61 | 61 | }; | |
62 | 62 | |||
Flashcard.prototype.unhide = function () { | 63 | 63 | Flashcard.prototype.unhide = function () { | |
return $http.post('/api/flashcards/' + this.id + '/unhide/'); | 64 | 64 | return $http.post('/api/flashcards/' + this.id + '/unhide/'); | |
}; | 65 | 65 | }; | |
66 | 66 | |||
Flashcard.prototype.edit = function (newversion) { | 67 | 67 | Flashcard.prototype.edit = function (newversion) { | |
this.text = newversion.text; | 68 | 68 | this.text = newversion.text; | |
this.mask = newversion.display_mask; | 69 | 69 | this.mask = newversion.display_mask; | |
this.material_date = newversion.material_date; | 70 | 70 | this.material_date = newversion.material_date; | |
return this.refreshFormattedText(); | 71 | 71 | return this.refreshFormattedText(); | |
}; | 72 | 72 | }; | |
73 | ||||
Flashcard.prototype.editModalOptions = { | 74 | 73 | Flashcard.prototype.editModalOptions = { | |
dismissible: true, // Modal can be dismissed by clicking outside of the modal | 75 | 74 | dismissible: true, // Modal can be dismissed by clicking outside of the modal | |
opacity: 0, // Opacity of modal background | 76 | 75 | opacity: 0, // Opacity of modal background | |
in_duration: 300, // Transition in duration | 77 | 76 | in_duration: 300, // Transition in duration | |
out_duration: 200, // Transition out duration | 78 | 77 | out_duration: 200, // Transition out duration | |
}; | 79 | 78 | }; | |
80 | 79 | |||
Flashcard.cleanup = function () { | 81 | 80 | Flashcard.cleanup = function () { | |
Deck = null; | 82 | 81 | Deck = null; | |
FlashcardCache = []; | 83 | 82 | FlashcardCache = []; | |
}; | 84 | 83 | }; | |
85 | 84 |
scripts/HelpController.js
View file @
8e3988f
angular.module('flashy.HelpController', ['ui.router']). | 1 | 1 | angular.module('flashy.HelpController', ['ui.router']). | |
2 | 2 | |||
controller('HelpController', ['$scope', '$state', '$http', '$timeout', 'UserService', | 3 | 3 | controller('HelpController', function($scope, $state, $http, $timeout) { | |
function($scope, $state, $http, $timeout, UserService) { | 4 | 4 | $scope.toggleContent = function(event, index) { | |
$scope.toggleContent = function(event, index) { | 5 | 5 | console.log(event, index); | |
console.log(event, index); | 6 | |||
7 | 6 | |||
if ($('#content-' + index).hasClass('open')) { // let's close it | 8 | 7 | if ($('#content-' + index).hasClass('open')) { // let's close it | |
// Note: 250 is duration (ms) of animation | 9 | 8 | // Note: 250 is duration (ms) of animation | |
$('#content-' + index).slideUp(250).removeClass('open'); | 10 | 9 | $('#content-' + index).slideUp(250).removeClass('open'); | |
} else { // let'd open it | 11 | 10 | } else { // let'd open it | |
$('#content-' + index).slideDown(250).addClass('open'); | 12 | 11 | $('#content-' + index).slideDown(250).addClass('open'); | |
} | 13 | 12 | } | |
14 | 13 | |||
// event.currentTarget | 15 | 14 | // event.currentTarget | |
}; | 16 | 15 | }; | |
17 | 16 | |||
$scope.closeContent = function(event) { | 18 | 17 | $scope.closeContent = function(event) { | |
19 | 18 | |||
}; | 20 | 19 | }; | |
21 | 20 | |||
// JSON OF FAQ ENTRIES | 22 | 21 | // JSON OF FAQ ENTRIES | |
$scope.entries = [ | 23 | 22 | $scope.entries = [ | |
{ | 24 | 23 | { | |
// icon: 'mdi-editor-insert-emoticon small', | 25 | 24 | // icon: 'mdi-editor-insert-emoticon small', | |
question: 'What is Flashy?', | 26 | 25 | question: 'What is Flashy?', | |
answer: '<p>Flashy is a service for creating, sharing, and reviewing flashcards for your courses.' + | 27 | 26 | answer: '<p>Flashy is a service for creating, sharing, and reviewing flashcards for your courses.' + | |
'</p><p>Flashy is optimized for contributing cards in real time during lecture to a shared live' + | 28 | 27 | '</p><p>Flashy is optimized for contributing cards in real time during lecture to a shared live' + | |
" feed. Don't want to contribute cards? That's fine! By adding others' cards to your deck, you" + | 29 | 28 | " feed. Don't want to contribute cards? That's fine! By adding others' cards to your deck, you" + | |
' help identify high-quality cards which should remain at the top of the feed for others to choose.' + | 30 | 29 | ' help identify high-quality cards which should remain at the top of the feed for others to choose.' + | |
'</p><p>Based on the principles of spaced repetition, Flashy also intelligently determines which' + | 31 | 30 | '</p><p>Based on the principles of spaced repetition, Flashy also intelligently determines which' + | |
' cards you are most at risk of forgetting, based on your review history. Receive push ' + | 32 | 31 | ' cards you are most at risk of forgetting, based on your review history. Receive push ' + | |
"notifications on your Android device's Chrome browser without installing any other app," + | 33 | 32 | "notifications on your Android device's Chrome browser without installing any other app," + | |
" and we'll notify you when you have a few cards which need to be reviewed.</p>" | 34 | 33 | " and we'll notify you when you have a few cards which need to be reviewed.</p>" | |
}, | 35 | 34 | }, | |
{ | 36 | 35 | { | |
// icon: 'mdi-file-cloud-queue small', | 37 | 36 | // icon: 'mdi-file-cloud-queue small', | |
question: 'Does Flashy work outside of UCSD?', | 38 | 37 | question: 'Does Flashy work outside of UCSD?', | |
answer: "To simplify development, Flashy was configured only for courses at UCSD. If you'd like Flashy for your school, please send us an email to let us know!" | 39 | 38 | answer: "To simplify development, Flashy was configured only for courses at UCSD. If you'd like Flashy for your school, please send us an email to let us know!" | |
}, | 40 | 39 | }, | |
{ | 41 | 40 | { | |
// icon: 'mdi-hardware-security small', | 42 | 41 | // icon: 'mdi-hardware-security small', | |
question: 'How do registration and verification work?', | 43 | 42 | question: 'How do registration and verification work?', | |
answer: "An account is required to use Flashy. We store the cards you save to your deck with your account. When you register, you'll be able to use the site immediately, but you must verify ownership of your email address within 24 hours. After 24 hours have passed, you'll need to verify your address before continuing to use the site. Don't worry, your cards and deck won't be deleted." | 44 | 43 | answer: "An account is required to use Flashy. We store the cards you save to your deck with your account. When you register, you'll be able to use the site immediately, but you must verify ownership of your email address within 24 hours. After 24 hours have passed, you'll need to verify your address before continuing to use the site. Don't worry, your cards and deck won't be deleted." | |
}, | 45 | 44 | }, | |
{ | 46 | 45 | { | |
question: "My question isn't answered above", | 47 | 46 | question: "My question isn't answered above", | |
answer: ' <a href="mailto:or.so.help.me@flashy.cards">Send us an email!</a>' | 48 | 47 | answer: ' <a href="mailto:or.so.help.me@flashy.cards">Send us an email!</a>' | |
}]; | 49 | 48 | }]; | |
50 | 49 | |||
// Functions | 51 | 50 | // Functions | |
$scope.toggleContent = function(event, index) { | 52 | 51 | $scope.toggleContent = function(event, index) { | |
if ($('#content-' + index).hasClass('open')) { // let's close it | 53 | 52 | if ($('#content-' + index).hasClass('open')) { // let's close it | |
// Note: 250 is duration (ms) of animation | 54 | 53 | // Note: 250 is duration (ms) of animation | |
$('#content-' + index).slideUp(250).removeClass('open'); | 55 | 54 | $('#content-' + index).slideUp(250).removeClass('open'); | |
} else { // let's open it | 56 | 55 | } else { // let's open it | |
$('#content-' + index).slideDown(250).addClass('open'); | 57 | 56 | $('#content-' + index).slideDown(250).addClass('open'); | |
} | 58 | 57 | } | |
}; | 59 | 58 | }; | |
60 | 59 | |||
$scope.expandAllContent = function() { | 61 | 60 | $scope.expandAllContent = function() { | |
for (var i = 0; i < $scope.entries.length; i++) { | 62 | 61 | for (var i = 0; i < $scope.entries.length; i++) { | |
$('#content-' + i).slideDown(0).addClass('open'); | 63 | 62 | $('#content-' + i).slideDown(0).addClass('open'); | |
} | 64 | 63 | } | |
}; | 65 | 64 | }; | |
66 | 65 | |||
$scope.collapseAllContent = function() { | 67 | 66 | $scope.collapseAllContent = function() { | |
for (var i = 0; i < $scope.entries.length; i++) { | 68 | 67 | for (var i = 0; i < $scope.entries.length; i++) { | |
$('#content-' + i).slideUp(0).removeClass('open'); | 69 | 68 | $('#content-' + i).slideUp(0).removeClass('open'); | |
} | 70 | 69 | } | |
}; | 71 | 70 | }; | |
}]); | 72 | 71 | }); | |
73 | 72 | |||
templates/feed.html
View file @
8e3988f
<!-- Edit Modal --> | 1 | 1 | <!-- Edit Modal --> | |
<div id="editModal" class="modal row" style="max-height:none;"> | 2 | 2 | <div id="editModal" class="modal row" style="max-height:none;"> | |
<form id="edit-card-form"> | 3 | 3 | <form id="edit-card-form"> | |
<div class="modal-content col"> | 4 | 4 | <div class="modal-content col"> | |
<div class="row" style="margin-bottom:0"> | 5 | 5 | <div class="row" style="margin-bottom:0"> | |
<div class="card cyan-text text-darken-2" | 6 | 6 | <div class="card cyan-text text-darken-2" | |
style="width:300px; height:180px; margin-bottom:0; font-size:120%;"> | 7 | 7 | style="width:300px; height:180px; margin-bottom:0; font-size:120%;"> | |
<div class="valign-wrapper"> | 8 | 8 | <div class="valign-wrapper"> | |
<div id="edit-card-input" ng-model="editCardFormattedText" style="outline:0px solid transparent;" | 9 | 9 | <div id="edit-card-input" ng-model="editCardFormattedText" style="outline:0px solid transparent;" | |
class="card-content valign center-align" | 10 | 10 | class="card-content valign center-align" | |
contenteditable select-non-editable="true" ng-change="refreshEditCardInput()"> | 11 | 11 | contenteditable select-non-editable="true" ng-change="refreshEditCardInput()"> | |
</div> | 12 | 12 | </div> | |
</div> | 13 | 13 | </div> | |
</div> | 14 | 14 | </div> | |
</div> | 15 | 15 | </div> | |
</div> | 16 | 16 | </div> | |
<div class="col"> | 17 | 17 | <div class="col"> | |
<div class="row"> | 18 | 18 | <div class="row"> | |
</div> | 19 | 19 | </div> | |
<div class="row"> | 20 | 20 | <div class="row"> | |
<button class="btn modal-close" type="submit" ng-click="saveEditChanges()" | 21 | 21 | <button class="btn modal-close" type="submit" ng-click="saveEditChanges()" | |
data-position="left" | 22 | 22 | data-position="left" | |
data-delay="50" ng-class="submit_enabled?{}:'disabled'"> | 23 | 23 | data-delay="50" ng-class="submit_enabled?{}:'disabled'"> | |
Save Changes | 24 | 24 | Save Changes | |
<i class="mdi-action-done right"></i> | 25 | 25 | <i class="mdi-action-done right"></i> | |
</button> | 26 | 26 | </button> | |
</div> | 27 | 27 | </div> | |
28 | 28 | |||
29 | 29 | |||
<div class="row"> | 30 | 30 | <div class="row"> | |
<button class="btn modal-close red" ng-click="discardEditChanges()" | 31 | 31 | <button class="btn modal-close red" ng-click="discardEditChanges()" | |
data-position="left" | 32 | 32 | data-position="left" | |
data-delay="50"> | 33 | 33 | data-delay="50"> | |
Discard Changes | 34 | 34 | Discard Changes | |
<i class="mdi-content-clear right"></i> | 35 | 35 | <i class="mdi-content-clear right"></i> | |
</button> | 36 | 36 | </button> | |
</div> | 37 | 37 | </div> | |
38 | 38 | |||
<div class="row"> | 39 | 39 | <div class="row"> | |
<button id="blank-selected" style="float:left" class="btn" data-position="right" | 40 | 40 | <button class="blank-selected-btn btn tooltipped" style="float:left" onclick="document.execCommand('bold')" data-position="right" data-delay="50"> | |
onclick="document.execCommand('bold')" data-delay="50"> | 41 | |||
Blank Selected Text | 42 | 41 | Blank Selected Text | |
</button> | 43 | 42 | </button> | |
</div> | 44 | 43 | </div> | |
45 | 44 | |||
46 | 45 | |||
<div class="row" ng-show="editCardText" ng-style="(editCardText.length>160)?{color:'red'}:{}"> | 47 | 46 | <div class="row" ng-show="editCardText" ng-style="(editCardText.length>160)?{color:'red'}:{}"> | |
{{editCardText.length}}/160 characters | 48 | 47 | {{editCardText.length}}/160 characters | |
</div> | 49 | 48 | </div> | |
<div class="row" ng-show="editCardText.length < 5"> | 50 | 49 | <div class="row" ng-show="editCardText.length < 5"> | |
Please write a little more! | 51 | 50 | Please write a little more! | |
</div> | 52 | 51 | </div> | |
<div class="row" ng-show="editCardText.length > 140"> | 53 | 52 | <div class="row" ng-show="editCardText.length > 140"> | |
Good flashcards have a<br> | 54 | 53 | Good flashcards have a<br> | |
single atomic fact | 55 | 54 | single atomic fact | |
</div> | 56 | 55 | </div> | |
</div> | 57 | 56 | </div> | |
</form> | 58 | 57 | </form> | |
</div> | 59 | 58 | </div> | |
60 | 59 | |||
61 | 60 | |||
<div class="row"> | 62 | 61 | <div class="row"> | |
<h2 class="weight" ng-cloak ng-show="showGrid && cards.length == 0">No cards. Be the first one to add a card!</h2> | 63 | 62 | <h2 class="weight" ng-cloak ng-show="showGrid && cards.length == 0">No cards. Be the first one to add a card!</h2> | |
64 | 63 | |||
<div class="progress center-align" style="margin: 70px auto auto;width:50%;" ng-if="!cardCols.length || !showGrid"> | 65 | 64 | <div class="progress center-align" style="margin: 70px auto auto;width:50%;" ng-if="!cardCols.length || !showGrid"> | |
<div class="indeterminate"></div> | 66 | 65 | <div class="indeterminate"></div> | |
</div> | 67 | 66 | </div> | |
68 | 67 | |||
<div class="cardColumn" ng-repeat="col in cardCols"> | 69 | 68 | <div class="cardColumn" ng-repeat="col in cardCols"> | |
<div class="repeated-card" ng-repeat="card in col"> | 70 | 69 | <div class="repeated-card" ng-repeat="card in col"> | |
<flashcard flashcard-obj="card" edit-fn="editCard"/> | 71 | 70 | <flashcard flashcard-obj="card" edit-fn="editCard"/> | |
</div> | 72 | 71 | </div> | |
</div> | 73 | 72 | </div> | |
</div> | 74 | 73 | </div> | |
75 | 74 | |||
76 | 75 | |||
<!--Lil plus button in corner--> | 77 | 76 | <!--Lil plus button in corner--> | |
<div class="fixed-action-btn" style="bottom: 24px; right: 24px;"> | 78 | 77 | <div class="fixed-action-btn" style="bottom: 24px; right: 24px;"> | |
<a data-target="newCard" class="btn-floating btn-large modal-trigger tooltipped" data-position="left" | 79 | 78 | <a data-target="newCard" class="btn-floating btn-large modal-trigger tooltipped" data-position="left" | |
data-delay="50" ng-click="openNewCardModal()" | 80 | 79 | data-delay="50" ng-click="openNewCardModal()" | |
data-tooltip="(C)ompose"> | 81 | 80 | data-tooltip="(C)ompose"> | |
<i class="large mdi-content-add"></i> | 82 | 81 | <i class="large mdi-content-add"></i> | |
</a> | 83 | 82 | </a> | |
</div> | 84 | 83 | </div> | |
85 | 84 | |||
<div id="newCard" class="modal bottom-sheet row" style="max-height:none;"> | 86 | 85 | <div id="newCard" class="modal bottom-sheet row" style="max-height:none;"> | |
<form id="new-card-form" ng-submit="false"> | 87 | 86 | <form id="new-card-form" ng-submit="false"> | |
<div class="modal-content col"> | 88 | 87 | <div class="modal-content col"> | |
<div class="row" style="margin-bottom:0"> | 89 | 88 | <div class="row" style="margin-bottom:0"> | |
<div class="card cyan-text text-darken-2" | 90 | 89 | <div class="card cyan-text text-darken-2" | |
style="width:300px; height:180px; margin-bottom:0; font-size:120%;"> | 91 | 90 | style="width:300px; height:180px; margin-bottom:0; font-size:120%;"> | |
<div class="valign-wrapper"> | 92 | 91 | <div class="valign-wrapper"> | |
<div id="new-card-input" ng-model="newCardFormattedText" style="outline:0px solid transparent;" | 93 | 92 | <div id="new-card-input" ng-model="newCardFormattedText" style="outline:0px solid transparent;" | |
class="card-content valign center-align" | 94 | 93 | class="card-content valign center-align" | |
contenteditable select-non-editable="true" ng-change="refreshNewCardInput()"> | 95 | 94 | contenteditable select-non-editable="true" ng-change="refreshNewCardInput()"> | |
96 | 95 | |||
</div> | 97 | 96 | </div> | |
</div> | 98 | 97 | </div> | |
99 | 98 | |||
</div> | 100 | 99 | </div> | |
</div> | 101 | 100 | </div> | |
</div> | 102 | 101 | </div> | |
103 | 102 | |||
<div class="col"> | 104 | 103 | <div class="col"> | |
<div class="row"> | 105 | 104 | <div class="row"> | |
106 | 105 | |||
</div> | 107 | 106 | </div> | |
<div class="row"> | 108 | 107 | <div class="row"> | |
<button class="btn modal-close tooltipped" type="submit" ng-click="pushCard()" | 109 | 108 | <button class="btn modal-close tooltipped" type="submit" ng-click="pushCard()" | |
data-position="left" | 110 | 109 | data-position="left" | |
data-delay="50" ng-class="submit_enabled?{}:'disabled'" | 111 | 110 | data-delay="50" ng-class="submit_enabled?{}:'disabled'" | |
data-tooltip="Enter">Contribute | 112 | 111 | data-tooltip="Enter">Contribute | |
<i class="mdi-hardware-keyboard-return right"></i> | 113 | 112 | <i class="mdi-hardware-keyboard-return right"></i> | |
</button> | 114 | 113 | </button> | |
</div> | 115 | 114 | </div> | |
<div class="row"> | 116 | 115 | <div class="row"> | |
<button id="blank-selected" style="float:left" class="btn tooltipped" data-position="right" data-delay="50" | 117 | 116 | <button style="float:left" class="blank-selected-btn btn tooltipped" data-position="right" data-delay="50" | |
data-tooltip="Ctrl-B">Blank Selected Text | 118 | 117 | data-tooltip="Ctrl-B" onclick="document.execCommand('bold')" >Blank Selected Text | |
</button> | 119 | 118 | </button> | |
</div> | 120 | 119 | </div> | |
<div class="row" ng-show="newCardText" ng-style="(newCardText.length>160)?{color:'red'}:{}"> | 121 | 120 | <div class="row" ng-show="newCardText" ng-style="(newCardText.length>160)?{color:'red'}:{}"> |