diff --git a/bower.json b/bower.json index 3f4eee4a3f..2d62dbefef 100644 --- a/bower.json +++ b/bower.json @@ -45,10 +45,10 @@ "angular-ui-router": "~0.2.13" }, "devDependencies": { - "angular-mocks": "1.3.3" + "angular-mocks": "1.3.9" }, "resolutions": { - "angular": "1.3.3", + "angular": "1.3.9", "jquery": ">=1.9.0" } } diff --git a/migrations/20150107_plan_dateUpdated_null.js b/migrations/20150107_plan_dateUpdated_null.js index ae231a0414..6e03b41a55 100644 --- a/migrations/20150107_plan_dateUpdated_null.js +++ b/migrations/20150107_plan_dateUpdated_null.js @@ -1,5 +1,8 @@ db.users.update( {'purchased.plan.customerId':{$ne:null}, 'purchased.plan.dateUpdated':null}, - {$set: {'purchased.plan.datedUpdated': new Date('12/01/2014')}}, + { + $set: {'purchased.plan.dateUpdated': new Date('12/01/2014')}, + $unset: {'purchased.plan.datedUpdated':''} + }, {multi:true} -); \ No newline at end of file +); diff --git a/public/css/tasks.styl b/public/css/tasks.styl index 7e50dfbcf3..f12308bd82 100644 --- a/public/css/tasks.styl +++ b/public/css/tasks.styl @@ -36,11 +36,16 @@ for $stage in $stages &:focus border: 1px solid darken($stage[1],30%) outline: 0 + .task-actions + background-color: darken($stage[1], 30%) .action-yesno label, - .task-action-btn + .task-action-btn, + .task-actions a background-color: darken($stage[1], 30%) &:hover, &:focus background-color: darken($stage[1], 40%) + .task-actions a:nth-of-type(2) + border-top: 1px solid darken($stage[1],50%) // If there are two habit buttons (+ -), add a border to separate them .task-options background-color: $stage[1] .option-group:not(.task-checklist) @@ -183,7 +188,7 @@ for $stage in $stages // task content .task-text display: block - padding: 0.75em 0 0.75em 3.5em + padding: 0.75em 0 0.75em 3.75em line-height: 1.4 word-wrap: break-word @@ -196,11 +201,6 @@ for $stage in $stages background-size:1.5em vertical-align: middle -.habit-wide .task-text - padding-left: 7em -.habit-narrow .task-text - padding-left: 0.75em - // when a task is being dragged .task.ui-sortable-helper box-shadow: 0 0 3px rgba(0,0,0,0.15), 0 0 5px rgba(0,0,0,0.1) @@ -486,7 +486,41 @@ form min-width: 2.5em .save-close text-align: center - @extend $hrpg-button + @extend $hrpg-button + +// Habits – task button styles (+ -) +.habits + .task-actions + display: inline-block + width: 3em + height: 100% + a + display: table; + width: 100% + height: 100% + font-size: 0.8em + span + display: table-cell + text-align: center + vertical-align: middle + width: 100% + height: 100% + &:hover, &:focus + color: #222 + text-decoration: none + .habit-wide + // When there are two buttons... + min-height: 4.5em + .task-actions + a + height: 50% + .habit-narrow + // When there are no buttons... + .task-actions + display: none + .task-text + padding-left: 1em + // todos ui // -------- diff --git a/public/js/app.js b/public/js/app.js index d97c3d3980..3ee68b2a9a 100644 --- a/public/js/app.js +++ b/public/js/app.js @@ -1,9 +1,7 @@ "use strict"; window.habitrpg = angular.module('habitrpg', - ['ngResource', 'ngSanitize', 'userServices', 'groupServices', 'memberServices', 'challengeServices', - 'authServices', 'notificationServices', 'guideServices', 'authCtrl', 'paymentServices', - 'ui.bootstrap', 'ui.keypress', 'ui.router', 'chieffancypants.loadingBar', 'At', 'infinite-scroll', 'ui.select2', 'angular.filter']) + ['ui.bootstrap', 'ui.keypress', 'ui.router', 'chieffancypants.loadingBar', 'At', 'infinite-scroll', 'ui.select2', 'angular.filter', 'ngResource', 'ngSanitize']) // @see https://github.com/angular-ui/ui-router/issues/110 and https://github.com/HabitRPG/habitrpg/issues/1705 // temporary hack until they have a better solution @@ -14,8 +12,8 @@ window.habitrpg = angular.module('habitrpg', .constant("MOBILE_APP", false) //.constant("STORAGE_GROUPS_ID", "") // if we decide to take groups offline - .config(['$stateProvider', '$urlRouterProvider', '$httpProvider', '$provide', 'STORAGE_SETTINGS_ID', - function($stateProvider, $urlRouterProvider, $httpProvider, $provide, STORAGE_SETTINGS_ID) { + .config(['$stateProvider', '$urlRouterProvider', '$httpProvider', 'STORAGE_SETTINGS_ID', + function($stateProvider, $urlRouterProvider, $httpProvider, STORAGE_SETTINGS_ID) { $urlRouterProvider // Setup default selected tabs @@ -222,52 +220,4 @@ window.habitrpg = angular.module('habitrpg', $httpProvider.defaults.headers.common['x-api-user'] = settings.auth.apiId; $httpProvider.defaults.headers.common['x-api-key'] = settings.auth.apiToken; } - - // Handle errors - $provide.factory('myHttpInterceptor', ['$rootScope','$q',function($rootScope,$q) { - return { - response: function(response) { - return response; - }, - responseError: function(response) { - // Offline - if (response.status == 0 || - // don't know why we're getting 404 here, should be 0 - (response.status == 404 && _.isEmpty(response.data))) { - $rootScope.$broadcast('responseText', window.env.t('serverUnreach')); - - // Needs refresh - } else if (response.needRefresh) { - $rootScope.$broadcast('responseError', "The site has been updated and the page needs to refresh. The last action has not been recorded, please refresh and try again."); - - } else if (response.data.code && response.data.code === 'ACCOUNT_SUSPENDED') { - confirm(response.data.err); - localStorage.clear(); - window.location.href = '/logout'; - - // 400 range? - } else if (response.status < 500) { - $rootScope.$broadcast('responseText', response.data.err || response.data); - // Need to reject the prompse so the error is handled correctly - if (response.status === 401) { - return $q.reject(response); - } - - // Error - } else { - var error = 'Please reload, ' + - '"'+window.env.t('error')+' '+(response.data.err || response.data || 'something went wrong')+'" ' + - window.env.t('seeConsole'); - $rootScope.$broadcast('responseError', error); - console.error(response); - } - - return response; - // this completely halts the chain, meaning we can't queue offline actions - //if (canRecover(response)) return responseOrNewPromise - //return $q.reject(response); - } - }; - }]); - $httpProvider.interceptors.push('myHttpInterceptor'); }]) diff --git a/public/js/controllers/authCtrl.js b/public/js/controllers/authCtrl.js index bacc41c28f..a167ecb309 100644 --- a/public/js/controllers/authCtrl.js +++ b/public/js/controllers/authCtrl.js @@ -4,9 +4,9 @@ The authentication controller (login & facebook) */ -angular.module('authCtrl', []) - .controller("AuthCtrl", ['$scope', '$rootScope', 'User', '$http', '$location', '$window','ApiUrlService', '$modal', - function($scope, $rootScope, User, $http, $location, $window, ApiUrlService, $modal) { +angular.module('habitrpg') + .controller("AuthCtrl", ['$scope', '$rootScope', 'User', '$http', '$location', '$window','ApiUrl', '$modal', + function($scope, $rootScope, User, $http, $location, $window, ApiUrl, $modal) { $scope.logout = function() { localStorage.clear(); @@ -36,7 +36,7 @@ angular.module('authCtrl', []) if ($scope.registrationForm.$invalid) { return; } - var url = ApiUrlService.get() + "/api/v2/register"; + var url = ApiUrl.get() + "/api/v2/register"; if($rootScope.selectedLanguage) url = url + '?lang=' + $rootScope.selectedLanguage.code; $http.post(url, $scope.registerVals).success(function(data, status, headers, config) { runAuth(data.id, data.apiToken); @@ -48,7 +48,7 @@ angular.module('authCtrl', []) username: $scope.loginUsername || $('#login-tab input[name="username"]').val(), password: $scope.loginPassword || $('#login-tab input[name="password"]').val() }; - $http.post(ApiUrlService.get() + "/api/v2/user/auth/local", data) + $http.post(ApiUrl.get() + "/api/v2/user/auth/local", data) .success(function(data, status, headers, config) { runAuth(data.id, data.token); }).error(errorAlert); @@ -70,7 +70,7 @@ angular.module('authCtrl', []) if(email == null || email.length == 0) { alert(window.env.t('invalidEmail')); } else { - $http.post(ApiUrlService.get() + '/api/v2/user/reset-password', {email:email}) + $http.post(ApiUrl.get() + '/api/v2/user/reset-password', {email:email}) .success(function(){ alert(window.env.t('newPassSent')); }) @@ -120,7 +120,7 @@ angular.module('authCtrl', []) $scope.socialLogin = function(network){ hello(network).login({scope:'email'}).then(function(auth){ - $http.post(ApiUrlService.get() + "/api/v2/user/auth/social", auth) + $http.post(ApiUrl.get() + "/api/v2/user/auth/social", auth) .success(function(data, status, headers, config) { runAuth(data.id, data.token); }).error(errorAlert); diff --git a/public/js/controllers/footerCtrl.js b/public/js/controllers/footerCtrl.js index ccb4084860..e704785f86 100644 --- a/public/js/controllers/footerCtrl.js +++ b/public/js/controllers/footerCtrl.js @@ -1,108 +1,108 @@ "use strict"; -(typeof habitrpg !== 'undefined' ? habitrpg : habitrpgStatic) - .controller("FooterCtrl", ['$scope', '$rootScope', 'User', '$http', 'Notification', 'ApiUrlService', - function($scope, $rootScope, User, $http, Notification, ApiUrlService) { +angular.module('habitrpg').controller("FooterCtrl", +['$scope', '$rootScope', 'User', '$http', 'Notification', 'ApiUrl', +function($scope, $rootScope, User, $http, Notification, ApiUrl) { - if(typeof habitrpg === "undefined"){ - $scope.languages = env.avalaibleLanguages; - $scope.selectedLanguage = _.find(env.avalaibleLanguages, {code: env.language.code}); + if(typeof habitrpg === "undefined"){ + $scope.languages = env.avalaibleLanguages; + $scope.selectedLanguage = _.find(env.avalaibleLanguages, {code: env.language.code}); - $rootScope.selectedLanguage = $scope.selectedLanguage; - - $scope.changeLang = function(){ - window.location = '?lang='+$scope.selectedLanguage.code; - } + $rootScope.selectedLanguage = $scope.selectedLanguage; + + $scope.changeLang = function(){ + window.location = '?lang='+$scope.selectedLanguage.code; + } + } + + /** + External Scripts + JS files not needed right away (google charts) or entirely optional (analytics) + Each file gets loaded async via $.getScript, so it doesn't bog page-load + */ + $scope.deferredScripts = function(){ + + // Stripe + $.getScript('//checkout.stripe.com/v2/checkout.js'); + + // Google Analytics, only in production + if (window.env.NODE_ENV === 'production') { + (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ + (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), + m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) + })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); + ga('create', window.env.GA_ID, {userId:User.user._id}); + ga('require', 'displayfeatures'); + ga('send', 'pageview'); } - /** - External Scripts - JS files not needed right away (google charts) or entirely optional (analytics) - Each file gets loaded async via $.getScript, so it doesn't bog page-load - */ - $scope.deferredScripts = function(){ + // Scripts only for desktop + if (!window.env.IS_MOBILE) { + // Add This + //$.getScript("//s7.addthis.com/js/300/addthis_widget.js#pubid=ra-5016f6cc44ad68a4"); //FIXME why isn't this working when here? instead it's now in
+ var addthisServices = 'facebook,twitter,googleplus,tumblr,'+window.env.BASE_URL.replace('https://','').replace('http://',''); + window.addthis_config = { + ui_click: true, + services_custom:{ + name: "Download", + url: window.env.BASE_URL+"/export/avatar-"+User.user._id+".png", + icon: window.env.BASE_URL+"/favicon.ico" + }, + services_expanded:addthisServices, + services_compact:addthisServices + }; - // Stripe - $.getScript('//checkout.stripe.com/v2/checkout.js'); - - // Google Analytics, only in production - if (window.env.NODE_ENV === 'production') { - (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ - (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), - m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) - })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); - ga('create', window.env.GA_ID, {userId:User.user._id}); - ga('require', 'displayfeatures'); - ga('send', 'pageview'); - } - - // Scripts only for desktop - if (!window.env.IS_MOBILE) { - // Add This - //$.getScript("//s7.addthis.com/js/300/addthis_widget.js#pubid=ra-5016f6cc44ad68a4"); //FIXME why isn't this working when here? instead it's now in - var addthisServices = 'facebook,twitter,googleplus,tumblr,'+window.env.BASE_URL.replace('https://','').replace('http://',''); - window.addthis_config = { - ui_click: true, - services_custom:{ - name: "Download", - url: window.env.BASE_URL+"/export/avatar-"+User.user._id+".png", - icon: window.env.BASE_URL+"/favicon.ico" - }, - services_expanded:addthisServices, - services_compact:addthisServices - }; - - // Google Charts - $.getScript("//www.google.com/jsapi", function() { - google.load("visualization", "1", { - packages: ["corechart"], - callback: function() {} - }); + // Google Charts + $.getScript("//www.google.com/jsapi", function() { + google.load("visualization", "1", { + packages: ["corechart"], + callback: function() {} }); - } + }); } + } - /** - * Debug functions. Note that the server route for gems is only available if process.env.DEBUG=true - */ - if (_.contains(['development','test'],window.env.NODE_ENV)) { - $scope.setHealthLow = function(){ - User.set({ - 'stats.hp': 1 - }); - } - $scope.addMissedDay = function(){ - if (!confirm("Are you sure you want to reset the day?")) return; - var dayBefore = moment(User.user.lastCron).subtract(1, 'days').toDate(); - User.set({'lastCron': dayBefore}); - Notification.text('-1 day, remember to refresh'); - } - $scope.addTenGems = function(){ - $http.post(ApiUrlService.get() + '/api/v2/user/addTenGems').success(function(){ - User.log({}); - }) - } - $scope.addGold = function(){ - User.set({ - 'stats.gp': User.user.stats.gp + 500, - }); - } - $scope.addLevelsAndGold = function(){ - User.set({ - 'stats.exp': User.user.stats.exp + 10000, - 'stats.gp': User.user.stats.gp + 10000, - 'stats.mp': User.user.stats.mp + 10000 - }); - } - $scope.addOneLevel = function(){ - User.set({ - 'stats.exp': User.user.stats.exp + (Math.round(((Math.pow(User.user.stats.lvl, 2) * 0.25) + (10 * User.user.stats.lvl) + 139.75) / 10) * 10) - }); - } - $scope.addBossQuestProgressUp = function(){ - User.set({ - 'party.quest.progress.up': User.user.party.quest.progress.up + 1000 - }); - } + /** + * Debug functions. Note that the server route for gems is only available if process.env.DEBUG=true + */ + if (_.contains(['development','test'],window.env.NODE_ENV)) { + $scope.setHealthLow = function(){ + User.set({ + 'stats.hp': 1 + }); } - }]) + $scope.addMissedDay = function(){ + if (!confirm("Are you sure you want to reset the day?")) return; + var dayBefore = moment(User.user.lastCron).subtract(1, 'days').toDate(); + User.set({'lastCron': dayBefore}); + Notification.text('-1 day, remember to refresh'); + } + $scope.addTenGems = function(){ + $http.post(ApiUrl.get() + '/api/v2/user/addTenGems').success(function(){ + User.log({}); + }) + } + $scope.addGold = function(){ + User.set({ + 'stats.gp': User.user.stats.gp + 500, + }); + } + $scope.addLevelsAndGold = function(){ + User.set({ + 'stats.exp': User.user.stats.exp + 10000, + 'stats.gp': User.user.stats.gp + 10000, + 'stats.mp': User.user.stats.mp + 10000 + }); + } + $scope.addOneLevel = function(){ + User.set({ + 'stats.exp': User.user.stats.exp + (Math.round(((Math.pow(User.user.stats.lvl, 2) * 0.25) + (10 * User.user.stats.lvl) + 139.75) / 10) * 10) + }); + } + $scope.addBossQuestProgressUp = function(){ + User.set({ + 'party.quest.progress.up': User.user.party.quest.progress.up + 1000 + }); + } + } +}]) diff --git a/public/js/controllers/groupsCtrl.js b/public/js/controllers/groupsCtrl.js index da6f964683..376c25d810 100644 --- a/public/js/controllers/groupsCtrl.js +++ b/public/js/controllers/groupsCtrl.js @@ -212,7 +212,7 @@ habitrpg.controller("GroupsCtrl", ['$scope', '$rootScope', 'Shared', 'Groups', ' }); }]) - .controller('ChatCtrl', ['$scope', 'Groups', 'User', '$http', 'ApiUrlService', 'Notification', 'Members', '$rootScope', function($scope, Groups, User, $http, ApiUrlService, Notification, Members, $rootScope){ + .controller('ChatCtrl', ['$scope', 'Groups', 'User', '$http', 'ApiUrl', 'Notification', 'Members', '$rootScope', function($scope, Groups, User, $http, ApiUrl, Notification, Members, $rootScope){ $scope.message = {content:''}; $scope._sending = false; @@ -276,7 +276,7 @@ habitrpg.controller("GroupsCtrl", ['$scope', '$rootScope', 'Shared', 'Groups', ' } //Chat.Chat.like({gid:group._id,mid:message.id}); - $http.post(ApiUrlService.get() + '/api/v2/groups/' + group._id + '/chat/' + message.id + '/like'); + $http.post(ApiUrl.get() + '/api/v2/groups/' + group._id + '/chat/' + message.id + '/like'); } $scope.flagChatMessage = function(groupId,message) { @@ -304,11 +304,18 @@ habitrpg.controller("GroupsCtrl", ['$scope', '$rootScope', 'Shared', 'Groups', ' 'level': window.env.t('sortLevel'), 'random': window.env.t('sortRandom'), 'pets': window.env.t('sortPets'), + 'habitrpg_date_joined' : window.env.t('sortHabitrpgJoined'), 'party_date_joined': window.env.t('sortJoined'), + 'habitrpg_last_logged_in': window.env.t('sortHabitrpgLastLoggedIn'), 'name': window.env.t('sortName'), 'backgrounds': window.env.t('sortBackgrounds'), }; + $scope.partyOrderAscendingChoices = { + 'ascending': window.env.t('ascendingSort'), + 'descending': window.env.t('descendingSort') + } + }]) .controller("GuildsCtrl", ['$scope', 'Groups', 'User', 'Challenges', '$rootScope', '$state', '$location', '$compile', diff --git a/public/js/controllers/hallCtrl.js b/public/js/controllers/hallCtrl.js index c135f5e8df..6956bfedd5 100644 --- a/public/js/controllers/hallCtrl.js +++ b/public/js/controllers/hallCtrl.js @@ -1,8 +1,8 @@ "use strict"; -habitrpg.controller("HallHeroesCtrl", ['$scope', '$rootScope', 'User', 'Notification', 'ApiUrlService', '$resource', - function($scope, $rootScope, User, Notification, ApiUrlService, $resource) { - var Hero = $resource(ApiUrlService.get() + '/api/v2/hall/heroes/:uid', {uid:'@_id'}); +habitrpg.controller("HallHeroesCtrl", ['$scope', '$rootScope', 'User', 'Notification', 'ApiUrl', '$resource', + function($scope, $rootScope, User, Notification, ApiUrl, $resource) { + var Hero = $resource(ApiUrl.get() + '/api/v2/hall/heroes/:uid', {uid:'@_id'}); $scope.hero = undefined; $scope.loadHero = function(uuid){ $scope.hero = Hero.get({uid:uuid}); @@ -19,9 +19,9 @@ habitrpg.controller("HallHeroesCtrl", ['$scope', '$rootScope', 'User', 'Notifica $scope.heroes = Hero.query(); }]); -habitrpg.controller("HallPatronsCtrl", ['$scope', '$rootScope', 'User', 'Notification', 'ApiUrlService', '$resource', - function($scope, $rootScope, User, Notification, ApiUrlService, $resource) { - var Patron = $resource(ApiUrlService.get() + '/api/v2/hall/patrons/:uid', {uid:'@_id'}); +habitrpg.controller("HallPatronsCtrl", ['$scope', '$rootScope', 'User', 'Notification', 'ApiUrl', '$resource', + function($scope, $rootScope, User, Notification, ApiUrl, $resource) { + var Patron = $resource(ApiUrl.get() + '/api/v2/hall/patrons/:uid', {uid:'@_id'}); var page = 0; $scope.patrons = []; diff --git a/public/js/controllers/headerCtrl.js b/public/js/controllers/headerCtrl.js index 197c48d8bf..ada83f24c2 100644 --- a/public/js/controllers/headerCtrl.js +++ b/public/js/controllers/headerCtrl.js @@ -28,12 +28,21 @@ habitrpg.controller("HeaderCtrl", ['$scope', 'Groups', 'User', case 'backgrounds': return member.preferences.background; break; + case 'habitrpg_date_joined': + return member.auth.timestamps.created; + break + case 'habitrpg_last_logged_in': + return member.auth.timestamps.loggedin; + break default: // party date joined return true; } } - ).reverse() + ) + if (User.user.party.orderAscending == "descending") { + $scope.partyMinusSelf = $scope.partyMinusSelf.reverse() + } }); } ]); diff --git a/public/js/controllers/rootCtrl.js b/public/js/controllers/rootCtrl.js index 2546f8ec0a..e46ffdbc1f 100644 --- a/public/js/controllers/rootCtrl.js +++ b/public/js/controllers/rootCtrl.js @@ -3,8 +3,8 @@ /* Make user and settings available for everyone through root scope. */ -habitrpg.controller("RootCtrl", ['$scope', '$rootScope', '$location', 'User', '$http', '$state', '$stateParams', 'Notification', 'Groups', 'Shared', 'Content', '$modal', '$timeout', 'ApiUrlService', 'Payments', - function($scope, $rootScope, $location, User, $http, $state, $stateParams, Notification, Groups, Shared, Content, $modal, $timeout, ApiUrlService, Payments) { +habitrpg.controller("RootCtrl", ['$scope', '$rootScope', '$location', 'User', '$http', '$state', '$stateParams', 'Notification', 'Groups', 'Shared', 'Content', '$modal', '$timeout', 'ApiUrl', 'Payments', + function($scope, $rootScope, $location, User, $http, $state, $stateParams, Notification, Groups, Shared, Content, $modal, $timeout, ApiUrl, Payments) { var user = User.user; var initSticky = _.once(function(){ @@ -222,7 +222,7 @@ habitrpg.controller("RootCtrl", ['$scope', '$rootScope', '$location', 'User', '$ $scope.spell = null; $rootScope.applyingAction = false; - $http.post(ApiUrlService.get() + '/api/v2/user/class/cast/'+spell.key+'?targetType='+type+'&targetId='+targetId) + $http.post(ApiUrl.get() + '/api/v2/user/class/cast/'+spell.key+'?targetType='+type+'&targetId='+targetId) .success(function(){ var msg = window.env.t('youCast', {spell: spell.text()}); switch (type) { diff --git a/public/js/controllers/settingsCtrl.js b/public/js/controllers/settingsCtrl.js index 8b6f95b696..d033749620 100644 --- a/public/js/controllers/settingsCtrl.js +++ b/public/js/controllers/settingsCtrl.js @@ -2,8 +2,8 @@ // Make user and settings available for everyone through root scope. habitrpg.controller('SettingsCtrl', - ['$scope', 'User', '$rootScope', '$http', 'ApiUrlService', 'Guide', '$location', '$timeout', 'Notification', 'Shared', - function($scope, User, $rootScope, $http, ApiUrlService, Guide, $location, $timeout, Notification, Shared) { + ['$scope', 'User', '$rootScope', '$http', 'ApiUrl', 'Guide', '$location', '$timeout', 'Notification', 'Shared', + function($scope, User, $rootScope, $http, ApiUrl, Guide, $location, $timeout, Notification, Shared) { // FIXME we have this re-declared everywhere, figure which is the canonical version and delete the rest // $scope.auth = function (id, token) { @@ -81,10 +81,11 @@ habitrpg.controller('SettingsCtrl', if (!changeUser.newUsername || !changeUser.password) { return alert(window.env.t('fillAll')); } - $http.post(ApiUrlService.get() + '/api/v2/user/change-username', changeUser) + $http.post(ApiUrl.get() + '/api/v2/user/change-username', changeUser) .success(function(){ alert(window.env.t('usernameSuccess')); $scope.changeUser = {}; + User.sync(); }) .error(function(data){ alert(data.err); @@ -95,7 +96,7 @@ habitrpg.controller('SettingsCtrl', if (!changePass.oldPassword || !changePass.newPassword || !changePass.confirmNewPassword) { return alert(window.env.t('fillAll')); } - $http.post(ApiUrlService.get() + '/api/v2/user/change-password', changePass) + $http.post(ApiUrl.get() + '/api/v2/user/change-password', changePass) .success(function(data, status, headers, config){ if (data.err) return alert(data.err); alert(window.env.t('passSuccess')); @@ -132,7 +133,7 @@ habitrpg.controller('SettingsCtrl', } $scope['delete'] = function(){ - $http['delete'](ApiUrlService.get() + '/api/v2/user') + $http['delete'](ApiUrl.get() + '/api/v2/user') .success(function(res, code){ if (res.err) return alert(res.err); localStorage.clear(); @@ -141,14 +142,14 @@ habitrpg.controller('SettingsCtrl', } $scope.enterCoupon = function(code) { - $http.post(ApiUrlService.get() + '/api/v2/user/coupon/' + code).success(function(res,code){ + $http.post(ApiUrl.get() + '/api/v2/user/coupon/' + code).success(function(res,code){ if (code!==200) return; User.sync(); Notification.text('Coupon applied! Check your inventory'); }); } $scope.generateCodes = function(codes){ - $http.post(ApiUrlService.get() + '/api/v2/coupons/generate/'+codes.event+'?count='+(codes.count || 1)) + $http.post(ApiUrl.get() + '/api/v2/coupons/generate/'+codes.event+'?count='+(codes.count || 1)) .success(function(res,code){ $scope._codes = {}; if (code!==200) return; @@ -190,7 +191,7 @@ habitrpg.controller('SettingsCtrl', } $scope.applyCoupon = function(coupon){ - $http.get(ApiUrlService.get() + '/api/v2/coupons/valid-discount/'+coupon) + $http.get(ApiUrl.get() + '/api/v2/coupons/valid-discount/'+coupon) .success(function(){ Notification.text("Coupon applied!"); var subs = $scope.Content.subscriptionBlocks; diff --git a/public/js/controllers/tasksCtrl.js b/public/js/controllers/tasksCtrl.js index fd8bcfe0a9..cde069d877 100644 --- a/public/js/controllers/tasksCtrl.js +++ b/public/js/controllers/tasksCtrl.js @@ -1,7 +1,7 @@ "use strict"; -habitrpg.controller("TasksCtrl", ['$scope', '$rootScope', '$location', 'User','Notification', '$http', 'ApiUrlService', '$timeout', 'Shared', - function($scope, $rootScope, $location, User, Notification, $http, ApiUrlService, $timeout, Shared) { +habitrpg.controller("TasksCtrl", ['$scope', '$rootScope', '$location', 'User','Notification', '$http', 'ApiUrl', '$timeout', 'Shared', + function($scope, $rootScope, $location, User, Notification, $http, ApiUrl, $timeout, Shared) { $scope.obj = User.user; // used for task-lists $scope.user = User.user; @@ -88,7 +88,7 @@ habitrpg.controller("TasksCtrl", ['$scope', '$rootScope', '$location', 'User','N $scope.unlink = function(task, keep) { // TODO move this to userServices, turn userSerivces.user into ng-resource - $http.post(ApiUrlService.get() + '/api/v2/user/tasks/' + task.id + '/unlink?keep=' + keep) + $http.post(ApiUrl.get() + '/api/v2/user/tasks/' + task.id + '/unlink?keep=' + keep) .success(function(){ User.log({}); }); @@ -202,8 +202,6 @@ habitrpg.controller("TasksCtrl", ['$scope', '$rootScope', '$location', 'User','N $scope.shouldShow = function(task, list, prefs){ if (task._editing) // never hide a task while being edited return true; - if (task.type == 'todo') // TODO: convert To-Dos to use this new system and probably add a "Dated" column (i.e., "Incomplete" (includes dated), "Dated" (has due date and is not complete), "Complete") - return true; var shouldDo = task.type == 'daily' ? habitrpgShared.shouldDo(new Date, task.repeat, prefs) : true; switch (list.view) { case "yellowred": // Habits @@ -214,6 +212,8 @@ habitrpg.controller("TasksCtrl", ['$scope', '$rootScope', '$location', 'User','N return !task.completed && shouldDo; case "complete": // Dailies and To-Dos return task.completed || !shouldDo; + case "dated": // To-Dos + return !task.completed && task.date; case "ingamerewards": // All skills/rewards except the user's own return false; // Because "rewards" list includes only the user's own case "all": diff --git a/public/js/directives/directives.js b/public/js/directives/directives.js index d66dba6406..e4793d7e0c 100644 --- a/public/js/directives/directives.js +++ b/public/js/directives/directives.js @@ -81,8 +81,8 @@ habitrpg }, { header: window.env.t('todos'), type: 'todo', - placeHolder: window.env.t('newTodo') - // view: "remaining" + placeHolder: window.env.t('newTodo'), + view: "remaining" }, { header: window.env.t('rewards'), type: 'reward', diff --git a/public/js/services/authServices.js b/public/js/services/authServices.js deleted file mode 100644 index 46bfaddb0d..0000000000 --- a/public/js/services/authServices.js +++ /dev/null @@ -1,104 +0,0 @@ -'use strict'; - -/** - * Services that persists and retrieves user from localStorage. - * FIXME is this file ever used? - */ - -var facebook = {} - -angular.module('authServices', ['userServices']). -factory('Facebook', - ['$http', '$location', 'User', 'ApiUrlService', - function($http, $location, User, ApiUrlService) { - //TODO FB.init({appId: '${section.parameters['facebook.app.id']}', status: true, cookie: true, xfbml: true}); - var auth, user = User.user; - - facebook.handleStatusChange = function(session) { - if (session.authResponse) { - - FB.api('/me', { - fields: 'name, picture, email' - }, function(response) { - console.log(response.error) - if (!response.error) { - - var data = { - name: response.name, - facebook_id: response.id, - email: response.email - } - - $http.post(ApiUrlService.get() + '/api/v2/user/auth/facebook', data).success(function(data, status, headers, config) { - User.authenticate(data.id, data.token, function(err) { - if (!err) { - alert(window.env.t('loginSuccess')); - $location.path("/habit"); - } - }); - }).error(function(response) { - console.log('error') - }) - - } else { - alert('napaka') - } - //clearAction(); - }); - } else { - document.body.className = 'not_connected'; - //clearAction(); - } - } - - return { - - authUser: function() { - FB.Event.subscribe('auth.statusChange', facebook.handleStatusChange); - }, - - getAuth: function() { - return auth; - }, - - login: function() { - - FB.login(null, { - scope: 'email' - }); - }, - - logout: function() { - FB.logout(function(response) { - window.location.reload(); - }); - } - } - - } -]) - -.factory('LocalAuth', - ['$http', 'User', - function($http, User) { - var auth, - user = User.user; - - return { - getAuth: function() { - return auth; - }, - - login: function() { - user.id = ''; - user.apiToken = ''; - User.authenticate(); - return; - - }, - - logout: function() {} - } - - } -]); diff --git a/public/js/services/challengeServices.js b/public/js/services/challengeServices.js index 0b1d39eaf8..51b91de8c2 100644 --- a/public/js/services/challengeServices.js +++ b/public/js/services/challengeServices.js @@ -4,24 +4,23 @@ * Services that persists and retrieves user from localStorage. */ -angular.module('challengeServices', ['ngResource']). - factory('Challenges', ['ApiUrlService', '$resource', 'User', '$q', 'Members', - function(ApiUrlService, $resource, User, $q, Members) { - var Challenge = $resource(ApiUrlService.get() + '/api/v2/challenges/:cid', - {cid:'@_id'}, - { - //'query': {method: "GET", isArray:false} - join: {method: "POST", url: ApiUrlService.get() + '/api/v2/challenges/:cid/join'}, - leave: {method: "POST", url: ApiUrlService.get() + '/api/v2/challenges/:cid/leave'}, - close: {method: "POST", params: {uid:''}, url: ApiUrlService.get() + '/api/v2/challenges/:cid/close'}, - getMember: {method: "GET", url: ApiUrlService.get() + '/api/v2/challenges/:cid/member/:uid'} - }); +angular.module('habitrpg').factory('Challenges', +['ApiUrl', '$resource', +function(ApiUrl, $resource) { + var Challenge = $resource(ApiUrl.get() + '/api/v2/challenges/:cid', + {cid:'@_id'}, + { + //'query': {method: "GET", isArray:false} + join: {method: "POST", url: ApiUrl.get() + '/api/v2/challenges/:cid/join'}, + leave: {method: "POST", url: ApiUrl.get() + '/api/v2/challenges/:cid/leave'}, + close: {method: "POST", params: {uid:''}, url: ApiUrl.get() + '/api/v2/challenges/:cid/close'}, + getMember: {method: "GET", url: ApiUrl.get() + '/api/v2/challenges/:cid/member/:uid'} + }); - //var challenges = []; + //var challenges = []; - return { - Challenge: Challenge - //challenges: challenges - } - } -]); + return { + Challenge: Challenge + //challenges: challenges + } +}]); diff --git a/public/js/services/groupServices.js b/public/js/services/groupServices.js index 8707424a08..03fe1a708e 100644 --- a/public/js/services/groupServices.js +++ b/public/js/services/groupServices.js @@ -4,76 +4,74 @@ * Services that persists and retrieves user from localStorage. */ -angular.module('groupServices', ['ngResource', 'challengeServices']). - factory('Groups', ['ApiUrlService', '$resource', '$q', '$http', 'User', 'Challenges', - function(ApiUrlService, $resource, $q, $http, User, Challenges) { - - var Group = $resource(ApiUrlService.get() + '/api/v2/groups/:gid', - {gid:'@_id', messageId: '@_messageId'}, - { - get: { - method: "GET", - isArray:false, - // Wrap challenges as ngResource so they have functions like $leave or $join - transformResponse: function(data, headers) { - data = angular.fromJson(data); - _.each(data && data.challenges, function(c) { - angular.extend(c, Challenges.Challenge.prototype); - }); - return data; - } - }, - - postChat: {method: "POST", url: ApiUrlService.get() + '/api/v2/groups/:gid/chat'}, - deleteChatMessage: {method: "DELETE", url: ApiUrlService.get() + '/api/v2/groups/:gid/chat/:messageId'}, - flagChatMessage: {method: "POST", url: ApiUrlService.get() + '/api/v2/groups/:gid/chat/:messageId/flag'}, - clearFlagCount: {method: "POST", url: ApiUrlService.get() + '/api/v2/groups/:gid/chat/:messageId/clearflags'}, - join: {method: "POST", url: ApiUrlService.get() + '/api/v2/groups/:gid/join'}, - leave: {method: "POST", url: ApiUrlService.get() + '/api/v2/groups/:gid/leave'}, - invite: {method: "POST", url: ApiUrlService.get() + '/api/v2/groups/:gid/invite'}, - removeMember: {method: "POST", url: ApiUrlService.get() + '/api/v2/groups/:gid/removeMember'}, - questAccept: {method: "POST", url: ApiUrlService.get() + '/api/v2/groups/:gid/questAccept'}, - questReject: {method: "POST", url: ApiUrlService.get() + '/api/v2/groups/:gid/questReject'}, - questCancel: {method: "POST", url: ApiUrlService.get() + '/api/v2/groups/:gid/questCancel'}, - questAbort: {method: "POST", url: ApiUrlService.get() + '/api/v2/groups/:gid/questAbort'} +angular.module('habitrpg').factory('Groups', +['ApiUrl', '$resource', '$q', '$http', 'User', 'Challenges', +function(ApiUrl, $resource, $q, $http, User, Challenges) { + var Group = $resource(ApiUrl.get() + '/api/v2/groups/:gid', + {gid:'@_id', messageId: '@_messageId'}, + { + get: { + method: "GET", + isArray:false, + // Wrap challenges as ngResource so they have functions like $leave or $join + transformResponse: function(data, headers) { + data = angular.fromJson(data); + _.each(data && data.challenges, function(c) { + angular.extend(c, Challenges.Challenge.prototype); }); - - // Defer loading everything until they're requested - var data = {party: undefined, myGuilds: undefined, publicGuilds: undefined, tavern: undefined}; - - return { - party: function(cb){ - if (!data.party) return (data.party = Group.get({gid: 'party'}, cb)); - return (cb) ? cb(party) : data.party; - }, - publicGuilds: function(){ - //TODO combine these as {type:'guilds,public'} and create a $filter() to separate them - if (!data.publicGuilds) data.publicGuilds = Group.query({type:'public'}); - return data.publicGuilds; - }, - myGuilds: function(){ - if (!data.myGuilds) data.myGuilds = Group.query({type:'guilds'}); - return data.myGuilds; - }, - tavern: function(){ - if (!data.tavern) data.tavern = Group.get({gid:'habitrpg'}); - return data.tavern; - }, - - // On enter, set chat message to "seen" - seenMessage: function(gid){ - $http.post(ApiUrlService.get() + '/api/v2/groups/'+gid+'/chat/seen'); - if (User.user.newMessages) delete User.user.newMessages[gid]; - }, - - // Pass reference to party, myGuilds, publicGuilds, tavern; inside data in order to - // be able to modify them directly (otherwise will be stick with cached version) - data: data, - - Group: Group + return data; } - } - ]) + }, + + postChat: {method: "POST", url: ApiUrl.get() + '/api/v2/groups/:gid/chat'}, + deleteChatMessage: {method: "DELETE", url: ApiUrl.get() + '/api/v2/groups/:gid/chat/:messageId'}, + flagChatMessage: {method: "POST", url: ApiUrl.get() + '/api/v2/groups/:gid/chat/:messageId/flag'}, + clearFlagCount: {method: "POST", url: ApiUrl.get() + '/api/v2/groups/:gid/chat/:messageId/clearflags'}, + join: {method: "POST", url: ApiUrl.get() + '/api/v2/groups/:gid/join'}, + leave: {method: "POST", url: ApiUrl.get() + '/api/v2/groups/:gid/leave'}, + invite: {method: "POST", url: ApiUrl.get() + '/api/v2/groups/:gid/invite'}, + removeMember: {method: "POST", url: ApiUrl.get() + '/api/v2/groups/:gid/removeMember'}, + questAccept: {method: "POST", url: ApiUrl.get() + '/api/v2/groups/:gid/questAccept'}, + questReject: {method: "POST", url: ApiUrl.get() + '/api/v2/groups/:gid/questReject'}, + questCancel: {method: "POST", url: ApiUrl.get() + '/api/v2/groups/:gid/questCancel'}, + questAbort: {method: "POST", url: ApiUrl.get() + '/api/v2/groups/:gid/questAbort'} + }); + + // Defer loading everything until they're requested + var data = {party: undefined, myGuilds: undefined, publicGuilds: undefined, tavern: undefined}; + + return { + party: function(cb){ + if (!data.party) return (data.party = Group.get({gid: 'party'}, cb)); + return (cb) ? cb(party) : data.party; + }, + publicGuilds: function(){ + //TODO combine these as {type:'guilds,public'} and create a $filter() to separate them + if (!data.publicGuilds) data.publicGuilds = Group.query({type:'public'}); + return data.publicGuilds; + }, + myGuilds: function(){ + if (!data.myGuilds) data.myGuilds = Group.query({type:'guilds'}); + return data.myGuilds; + }, + tavern: function(){ + if (!data.tavern) data.tavern = Group.get({gid:'habitrpg'}); + return data.tavern; + }, + + // On enter, set chat message to "seen" + seenMessage: function(gid){ + $http.post(ApiUrl.get() + '/api/v2/groups/'+gid+'/chat/seen'); + if (User.user.newMessages) delete User.user.newMessages[gid]; + }, + + // Pass reference to party, myGuilds, publicGuilds, tavern; inside data in order to + // be able to modify them directly (otherwise will be stick with cached version) + data: data, + + Group: Group + } +}]) /** * TODO Get this working. Make ChatService it's own ngResource, so we can update chat without having to sync the whole * group object (expensive). Also so we can add chat-specific routes diff --git a/public/js/services/guideServices.js b/public/js/services/guideServices.js index 3b808f0ba1..8e4eb1bc60 100644 --- a/public/js/services/guideServices.js +++ b/public/js/services/guideServices.js @@ -4,219 +4,217 @@ * Services for each tour step when you unlock features */ -angular.module('guideServices', []). - factory('Guide', ['$rootScope', 'User', '$timeout', function($rootScope, User, $timeout) { - - /** - * Init and show the welcome tour. Note we do it listening to a $rootScope broadcasted 'userLoaded' message, - * this because we need to determine whether to show the tour *after* the user has been pulled from the server, - * otherwise it's always start off as true, and then get set to false later - */ - $rootScope.$on('userUpdated', initTour); - function initTour(){ - if (User.user.flags.showTour === false) return; - var tourSteps = [ - { - element: ".main-herobox", - title: window.env.t('welcomeHabit'), - content: window.env.t('welcomeHabitT1') + " Justin, " + window.env.t('welcomeHabitT2'), - }, { - element: ".main-herobox", - title: window.env.t('yourAvatar'), - content: window.env.t('yourAvatarText'), - }, { - element: ".main-herobox", - title: window.env.t('avatarCustom'), - content: window.env.t('avatarCustomText'), - }, { - element: "#bars", - title: window.env.t('hitPoints'), - content: window.env.t('hitPointsText'), - }, { - element: "#bars", - title: window.env.t('expPoints'), - content: window.env.t('expPointsText'), - }, { - element: "ul.habits", - title: window.env.t('typeGoals'), - content: window.env.t('typeGoalsText'), - placement: "top" - }, { - element: "ul.habits", - title: window.env.t('habits'), - content: window.env.t('tourHabits'), - placement: "top" - }, { - element: "ul.dailys", - title: window.env.t('dailies'), - content: window.env.t('tourDailies'), - placement: "top" - }, { - element: "ul.todos", - title: window.env.t('todos'), - content: window.env.t('tourTodos'), - placement: "top" - }, { - element: "ul.main-list.rewards", - title: window.env.t('rewards'), - content: window.env.t('tourRewards'), - placement: "top" - }, { - element: "ul.habits li:first-child", - title: window.env.t('hoverOver'), - content: window.env.t('hoverOverText'), - placement: "right" - }, { - element: "ul.habits li:first-child", - title: window.env.t('unlockFeatures'), - content: window.env.t('unlockFeaturesT1') + " " + window.env.t('habitWiki') + " " + window.env.t('unlockFeaturesT2'), - placement: "right" - } - ]; - _.each(tourSteps, function(step){ - if (env.worldDmg.guide) { - step.content = "