From fbe3ecc0334a845551f93d7becd8b839ea33c009 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Wed, 12 Feb 2014 13:59:13 +0100 Subject: [PATCH 01/34] refactor(grunt): simplify run:dev task --- Gruntfile.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gruntfile.js b/Gruntfile.js index 0d7247aa83..ae064377ef 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -126,7 +126,7 @@ module.exports = function(grunt) { // Register tasks. grunt.registerTask('build:prod', ['loadManifestFiles', 'clean:build', 'uglify', 'stylus', 'cssmin', 'copy:build', 'hashres']); - grunt.registerTask('build:dev', ['loadManifestFiles', 'clean:build', 'stylus', 'cssmin', 'copy:build']); + grunt.registerTask('build:dev', ['stylus']); grunt.registerTask('run:dev', [ 'build:dev', 'concurrent' ]); From fb496de42f508bae86ee063f4eb1fe4906486015 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Wed, 12 Feb 2014 14:34:50 +0100 Subject: [PATCH 02/34] refactor(caching): only 1 css file, use grunt-contrib-cssmin to rewrite urls --- Gruntfile.js | 20 ++++++++++++++------ src/middleware.js | 21 ++++++++++----------- 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index ae064377ef..ea26d68449 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -106,22 +106,30 @@ module.exports = function(grunt) { var files = grunt.file.readJSON('./public/manifest.json'); var uglify = {}; var cssmin = {}; + _.each(files, function(val, key){ + var js = uglify['build/' + key + '.js'] = []; + _.each(files[key]['js'], function(val){ js.push('public/' + val); }); + + var css = cssmin['build/' + key + '.css'] = []; + _.each(files[key]['css'], function(val){ - if(val == 'app.css' || val == 'static.css'){ - cssmin['build/' + val] = ['build/' + val] - }else{ - cssmin['build/' + val] = ['public/' + val] - } + var path = (val == 'app.css' || val == 'static.css') ? 'build/' : 'public/'; + css.push(path + val) }); + }); + grunt.config.set('uglify.build.files', uglify); - grunt.config.set('uglify.build.options', {compress: false}) + grunt.config.set('uglify.build.options', {compress: false}); + grunt.config.set('cssmin.build.files', cssmin); + // Rewrite urls to relative path + grunt.config.set('cssmin.build.options', {'target': 'public/css/whatever-css.css'}); }); // Register tasks. diff --git a/src/middleware.js b/src/middleware.js index 30e95ca5c6..4894b586d1 100644 --- a/src/middleware.js +++ b/src/middleware.js @@ -122,22 +122,21 @@ var getManifestFiles = function(page){ if(!files) throw new Error("Page not found!"); - var css = ''; - - _.each(files.css, function(file){ - css += ''; - }); + var code = ''; if(nconf.get('NODE_ENV') === 'production'){ - return css + ''; + code += ''; + code += ''; }else{ - var results = css; - _.each(files.js, function(file){ - results += ''; + _.each(files.css, function(file){ + code += ''; + }); + _.each(files.js, function(file){ + code += ''; }); - return results; } - + + return code; } // Translations From 8fdc5327e9cdde345a47a68710b5d98b71442adc Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Wed, 12 Feb 2014 15:10:22 +0100 Subject: [PATCH 03/34] refactor(grunt and caching): cache icon fonts, spritesmith and use icons from spritesmith for coins notification --- Gruntfile.js | 15 ++++------ public/css/alerts.styl | 33 +++------------------- public/js/controllers/notificationCtrl.js | 1 - public/js/services/notificationServices.js | 11 +++----- 4 files changed, 14 insertions(+), 46 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index ea26d68449..9186a9e800 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -56,7 +56,8 @@ module.exports = function(grunt) { build: { files: [ {expand: true, cwd: 'public/', src: 'favicon.ico', dest: 'build/'}, - {expand: true, cwd: 'public/', src: 'bower_components/habitrpg-shared/dist/spritesmith-*.png', dest: 'build/'} + {expand: true, cwd: 'public/', src: 'bower_components/habitrpg-shared/dist/spritesmith.png', dest: 'build/'}, + {expand: true, cwd: 'public/', src: 'bower_components/bootstrap/dist/fonts/*', dest: 'build/'} ] } }, @@ -69,18 +70,14 @@ module.exports = function(grunt) { }, src: [ 'build/*.js', 'build/*.css', 'build/favicon.ico', - 'build/bower_components/bootstrap/docs/assets/css/*.css', - 'build/bower_components/habitrpg-shared/dist/*.css' + 'build/bower_components/habitrpg-shared/dist/*.png', + 'build/bower_components/bootstrap/dist/fonts/*' ], - dest: 'make-sure-i-do-not-exist' + dest: 'build/*.css' } }, - nodemon: { - dev: { - ignoredFiles: ['public/*', 'Gruntfile.js', 'CHANGELOG.md', 'views/*', 'build/*', '.idea*', '.git*', '*.log'] - } - }, + nodemon: { dev: {} }, watch: { dev: { diff --git a/public/css/alerts.styl b/public/css/alerts.styl index 1520f695f8..40a7b8910b 100644 --- a/public/css/alerts.styl +++ b/public/css/alerts.styl @@ -33,6 +33,10 @@ alert-sm-mixin() .alert alert-sm-mixin() + .notification-icon + transform: scale(0.8) + + // variables gpColor = #FBEFC0 @@ -95,35 +99,6 @@ borderDarken = 20% border-color: darken(dropColor,borderDarken) color: dropText -// alert icons - -.icon-gold - background: url("/bower_components/habitrpg-shared/img/coin_single_gold.png") no-repeat - background-position: center center - background-size: 18px - width: 14px - height: 14px - display: inline-block - vertical-align: middle - -.icon-silver - background: url("/bower_components/habitrpg-shared/img/coin_single_silver.png") no-repeat - background-position: center center - background-size: 18px - width: 14px - height: 14px - display: inline-block - vertical-align: middle - -.icon-death - background: url("/bower_components/habitrpg-shared/img/sprites/dead.png") no-repeat - background-position: center center - background-size: 14px - width: 14px - height: 14px - display: inline-block - vertical-align: middle - .undo-button z-index: 3000 position:absolute diff --git a/public/js/controllers/notificationCtrl.js b/public/js/controllers/notificationCtrl.js index 8633c16fc5..1650a36f25 100644 --- a/public/js/controllers/notificationCtrl.js +++ b/public/js/controllers/notificationCtrl.js @@ -94,7 +94,6 @@ habitrpg.controller('NotificationCtrl', $rootScope.$watch('user.items.' + watched, function(before, after){ if (after == before) return; if (+after < +before) { - Notification.death(); //don't want to day "lost a head" if (watched === 'head') watched = 'helm'; Notification.text('Lost GP, 1 LVL, ' + watched); diff --git a/public/js/services/notificationServices.js b/public/js/services/notificationServices.js index 02f92bbc83..21cb09a306 100644 --- a/public/js/services/notificationServices.js +++ b/public/js/services/notificationServices.js @@ -10,7 +10,7 @@ angular.module("notificationServices", []) top_offset: 20, align: 'right', //('left', 'right', or 'center') width: 250, //(integer, or 'auto') - delay: (type=='error') ? 0 : 7000, + delay: (type=='error') ? 0 : 0, allow_dismiss: true, stackup_spacing: 10 // spacing between consecutive stacecked growls. }); @@ -25,11 +25,11 @@ angular.module("notificationServices", []) gold = Math.floor(absolute); silver = Math.floor((absolute - gold) * 100); if (gold && silver > 0) { - return "" + gold + " " + silver + " "; + return "" + gold + " " + silver + " "; } else if (gold > 0) { - return "" + gold + " "; + return "" + gold + " "; } else if (silver > 0) { - return "" + silver + " "; + return "" + silver + " "; } }; @@ -60,9 +60,6 @@ angular.module("notificationServices", []) lvl: function(){ growl(' ' + window.env.t('levelUp'), 'lvl'); }, - death: function(){ - growl(" " + window.env.t('respawn'), "death"); - }, error: function(error){ growl("  " + error, "danger"); }, From fef858d5556cc65396e9d6f3c1f4f18218ca7fef Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Wed, 12 Feb 2014 15:21:40 +0100 Subject: [PATCH 04/34] refactor(caching): cache emojis and remove gemoji from bower --- bower.json | 1 - src/server.js | 2 ++ views/options/social/challenge-box.jade | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/bower.json b/bower.json index e9f2e6ae37..4af780151c 100644 --- a/bower.json +++ b/bower.json @@ -36,7 +36,6 @@ "JavaScriptButtons": "git://github.com/paypal/JavaScriptButtons.git#master", "Angular-At-Directive": "git://github.com/snicker/Angular-At-Directive#master", "js-emoji": "git://github.com/snicker/js-emoji#master", - "gemoji": "git://github.com/github/gemoji", "sticky": "*", "swagger-ui": "https://github.com/wordnik/swagger-ui.git#105c516f5f055b140e935e9cfe0c36f841921dff", "ngInfiniteScroll": "~1.0.0", diff --git a/src/server.js b/src/server.js index 6cefab8db0..bef7642207 100644 --- a/src/server.js +++ b/src/server.js @@ -116,7 +116,9 @@ if (cluster.isMaster && (isDev || isProd)) { app.use(app.router); var maxAge = isProd ? 31536000000 : 0; + // Cache emojis without copying them to build, they are too many app.use(express['static'](path.join(__dirname, "/../build"), { maxAge: maxAge })); + app.use('/bower_components/habitrpg-shared/img/emoji/unicode', express['static'](path.join(__dirname, "/../public/bower_components/habitrpg-shared/img/emoji/unicode"), { maxAge: maxAge })); app.use(express['static'](path.join(__dirname, "/../public"))); // Custom Directives diff --git a/views/options/social/challenge-box.jade b/views/options/social/challenge-box.jade index ff7cb21926..758a28ece3 100644 --- a/views/options/social/challenge-box.jade +++ b/views/options/social/challenge-box.jade @@ -14,8 +14,8 @@ p |  =env.t('noChallenges') + |  a.label.label-primary(ui-sref='options.social.challenges') - |  span.glyphicon.glyphicon-bullhorn |  =env.t('challenges') From bb6931fe83d91df771b29c5bd0bd11fff7773294 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Wed, 12 Feb 2014 18:08:17 +0100 Subject: [PATCH 05/34] refactor(grunt): cache gifs --- Gruntfile.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Gruntfile.js b/Gruntfile.js index 9186a9e800..05979dbbe5 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -57,6 +57,8 @@ module.exports = function(grunt) { files: [ {expand: true, cwd: 'public/', src: 'favicon.ico', dest: 'build/'}, {expand: true, cwd: 'public/', src: 'bower_components/habitrpg-shared/dist/spritesmith.png', dest: 'build/'}, + {expand: true, cwd: 'public/', src: 'bower_components/habitrpg-shared/img/sprites/backer-only/*.gif', dest: 'build/'}, + {expand: true, cwd: 'public/', src: 'bower_components/habitrpg-shared/img/sprites/npc_ian.gif', dest: 'build/'}, {expand: true, cwd: 'public/', src: 'bower_components/bootstrap/dist/fonts/*', dest: 'build/'} ] } @@ -71,6 +73,8 @@ module.exports = function(grunt) { src: [ 'build/*.js', 'build/*.css', 'build/favicon.ico', 'build/bower_components/habitrpg-shared/dist/*.png', + 'build/bower_components/habitrpg-shared/img/sprites/backer-only/*.gif', + 'build/bower_components/habitrpg-shared/img/sprites/npc_ian.gif', 'build/bower_components/bootstrap/dist/fonts/*' ], dest: 'build/*.css' From 99474729aa3a26e401e0fed627d18273fc9b6662 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Wed, 12 Feb 2014 19:10:45 +0100 Subject: [PATCH 06/34] fix(typo) --- public/js/services/notificationServices.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/js/services/notificationServices.js b/public/js/services/notificationServices.js index 21cb09a306..c67770e8f0 100644 --- a/public/js/services/notificationServices.js +++ b/public/js/services/notificationServices.js @@ -10,7 +10,7 @@ angular.module("notificationServices", []) top_offset: 20, align: 'right', //('left', 'right', or 'center') width: 250, //(integer, or 'auto') - delay: (type=='error') ? 0 : 0, + delay: (type=='error') ? 0 : 7000, allow_dismiss: true, stackup_spacing: 10 // spacing between consecutive stacecked growls. }); From ce82be637d1d707e899aeee5f315da69367fa367 Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Wed, 12 Feb 2014 21:20:42 -0700 Subject: [PATCH 07/34] feat(groups): add group chat notifications --- public/js/app.js | 8 ++++++-- public/js/controllers/groupsCtrl.js | 3 +++ public/js/services/groupServices.js | 10 ++++++++-- src/controllers/groups.js | 8 ++++++++ src/models/group.js | 11 +++++++++++ src/models/user.js | 7 +++++-- src/routes/apiv2.coffee | 11 +++++++++++ 7 files changed, 52 insertions(+), 6 deletions(-) diff --git a/public/js/app.js b/public/js/app.js index 57fb7a25f3..ef55bb10d4 100644 --- a/public/js/app.js +++ b/public/js/app.js @@ -114,8 +114,12 @@ window.habitrpg = angular.module('habitrpg', .state('options.social.guilds.detail', { url: '/:gid', templateUrl: 'partials/options.social.guilds.detail.html', - controller: ['$scope', 'Groups', '$stateParams', function($scope, Groups, $stateParams){ - $scope.group = Groups.Group.get({gid:$stateParams.gid}); + controller: ['$scope', 'Groups', '$stateParams', + function($scope, Groups, $stateParams){ + Groups.Group.get({gid:$stateParams.gid}, function(group){ + $scope.group = group; + Groups.seenMessage(group._id); + }); }] }) diff --git a/public/js/controllers/groupsCtrl.js b/public/js/controllers/groupsCtrl.js index 1c5bd00958..c0ba02c5a1 100644 --- a/public/js/controllers/groupsCtrl.js +++ b/public/js/controllers/groupsCtrl.js @@ -319,6 +319,9 @@ habitrpg.controller("GroupsCtrl", ['$scope', '$rootScope', 'Shared', 'Groups', ' $scope.text = 'Party'; $scope.group = $rootScope.party = Groups.party(); $scope.newGroup = new Groups.Group({type:'party'}); + + Groups.seenMessage($scope.group._id); + $scope.create = function(group){ group.$save(function(newGroup){ $scope.group = newGroup; diff --git a/public/js/services/groupServices.js b/public/js/services/groupServices.js index 1f72b4a648..eb0060c24c 100644 --- a/public/js/services/groupServices.js +++ b/public/js/services/groupServices.js @@ -5,8 +5,8 @@ */ angular.module('groupServices', ['ngResource']). - factory('Groups', ['API_URL', '$resource', '$q', - function(API_URL, $resource, $q) { + factory('Groups', ['API_URL', '$resource', '$q', '$http', 'User', + function(API_URL, $resource, $q, $http, User) { var Group = $resource(API_URL + '/api/v2/groups/:gid', {gid:'@_id', messageId: '@_messageId'}, { @@ -44,6 +44,12 @@ angular.module('groupServices', ['ngResource']). return tavern; }, + // On enter, set chat message to "seen" + seenMessage: function(gid){ + $http.post('/api/v2/groups/'+gid+'/chat/seen'); + User.user.newMessages[gid] = false; + }, + Group: Group } } diff --git a/src/controllers/groups.js b/src/controllers/groups.js index cfdaa2d179..4bdde2b83a 100644 --- a/src/controllers/groups.js +++ b/src/controllers/groups.js @@ -249,6 +249,14 @@ api.deleteChatMessage = function(req, res){ }); } +api.seenMessage = function(req,res,next){ + // Skip the auth step, we want this to be fast. If !found with uuid/token, then it just doesn't save + var update = {$set:{}}; + update['$set']['newMessages.'+req.params.gid+'.value'] = false; + User.update({_id:req.headers['x-api-user'], apiToken:req.headers['x-api-key']},update).exec(); + res.send(200); +} + api.likeChatMessage = function(req, res, next) { var user = res.locals.user; var group = res.locals.group; diff --git a/src/models/group.js b/src/models/group.js index f3b3cad8e5..0ecc16221e 100644 --- a/src/models/group.js +++ b/src/models/group.js @@ -106,6 +106,17 @@ GroupSchema.methods.sendChat = function(message, user){ } group.chat.unshift(message); group.chat.splice(200); + + // Kick off chat notifications in the background. + var lastSeenUpdate = {$set:{}, $inc:{_v:1}}; + lastSeenUpdate['$set']['newMessages.'+group._id] = {name:group.name,value:true}; + if (group._id == 'habitrpg') { + // TODO For Tavern, only notify them if their name was mentioned + // var profileNames = [] // get usernames from regex of @xyz. how to handle space-delimited profile names? + // User.update({'profile.name':{$in:profileNames}},lastSeenUpdate,{multi:true}).exec(); + } else { + mongoose.model('User').update({_id:{$in:group.members, $ne: user ? user._id : ''}},lastSeenUpdate,{multi:true}).exec(); + } } var cleanQuestProgress = function(merge){ diff --git a/src/models/user.js b/src/models/user.js index 2d81658e0f..2614606e91 100644 --- a/src/models/user.js +++ b/src/models/user.js @@ -207,9 +207,11 @@ var UserSchema = new Schema({ lastCron: {type: Date, 'default': Date.now}, + // {GROUP_ID: Boolean}, represents whether they have unseen chat messages + newMessages: {type: Schema.Types.Mixed, 'default': {}}, + party: { // id // FIXME can we use a populated doc instead of fetching party separate from user? - lastMessageSeen: String, order: {type:String, 'default':'level'}, quest: { key: String, @@ -245,7 +247,8 @@ var UserSchema = new Schema({ disableClasses: {type: Boolean, 'default': false}, newTaskEdit: {type: Boolean, 'default': false}, tagsCollapsed: {type: Boolean, 'default': false}, - advancedCollapsed: {type: Boolean, 'default': false} + advancedCollapsed: {type: Boolean, 'default': false}, + toolbarCollapsed: {type:Boolean, 'default':false} }, profile: { blurb: String, diff --git a/src/routes/apiv2.coffee b/src/routes/apiv2.coffee index 513fb7e312..db5a0010f0 100644 --- a/src/routes/apiv2.coffee +++ b/src/routes/apiv2.coffee @@ -488,6 +488,17 @@ module.exports = (swagger, v2) -> middleware: [auth.auth, groups.attachGroup] action: groups.postChat + # placing before route below, so that if !=='seen' it goes to next() + "/groups/{gid}/chat/seen": + spec: + method: 'POST' + description: "Flag chat messages for a particular group as seen" + parameters: [ + path 'gid','Group id','string' + ] + middleware: [] + action: groups.seenMessage + "/groups/{gid}/chat/{messageId}": spec: method: 'DELETE' From f72cb21300c078b439b3334bfa3e205ba04dc949 Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Wed, 12 Feb 2014 21:21:06 -0700 Subject: [PATCH 08/34] feat(toolbar): add toolbar featuring navigation, gems / subs, bailey, & chat / invite notifications --- public/css/index.styl | 16 +++ public/css/npcs.styl | 9 +- views/index.jade | 6 +- views/shared/header/header.jade | 5 - views/shared/header/menu.jade | 167 ++++++++++++++++++++++++-------- 5 files changed, 149 insertions(+), 54 deletions(-) diff --git a/public/css/index.styl b/public/css/index.styl index 6d00b3e041..7ecb15ca2b 100644 --- a/public/css/index.styl +++ b/public/css/index.styl @@ -163,3 +163,19 @@ a.label background-color: #428bca .badge-success background-color: #47a447 + +.white, .white a + color: #fff !important + +.collapse-toolbar + position:absolute + right:0px + top:0px + width:30px + height:25px + background-color:#222 + z-index:999 + .glyphicon + color:white + padding-left:7px + padding-top:5px diff --git a/public/css/npcs.styl b/public/css/npcs.styl index 48493536b3..c0c6aff155 100644 --- a/public/css/npcs.styl +++ b/public/css/npcs.styl @@ -4,15 +4,14 @@ .npc_matt margin-bottom: 20px +.toolbar-bailey-container + width:55px + position:relative .npc_bailey float:left .npc_bailey_head - //height: 30px !important - height: 50px !important position: absolute - //top: 117px // 147 (header-height) - 30 (bailey height) - top: 97px - right: 50px + top: 4px cursor: pointer // Tour (Justin) diff --git a/views/index.jade b/views/index.jade index aedb605b44..85f6c5d642 100644 --- a/views/index.jade +++ b/views/index.jade @@ -20,19 +20,15 @@ html(ng-app="habitrpg", ng-controller="RootCtrl", ng-class='{"applying-action":a body(ng-cloak, ng-controller='GroupsCtrl') + include ./shared/header/menu include ./shared/modals/index include ./shared/header/header - include ./shared/tasks/lists include ./main/index include ./options/index #notification-area(ng-controller='NotificationCtrl') #wrap.container-fluid - //if they hide the header, we still need user-menu visible - div(ng-if='user.preferences.hideHeader') - include ./shared/header/menu - .row .col-md-12.exp-chart(ng-show='charts.exp') #main(ui-view) diff --git a/views/shared/header/header.jade b/views/shared/header/header.jade index d62920ab4c..6481d1a5e6 100644 --- a/views/shared/header/header.jade +++ b/views/shared/header/header.jade @@ -1,7 +1,5 @@ .header-wrap(ng-controller='HeaderCtrl') a.label.label-default.undo-button(x-bind='click:undo', ng-show='_undo')=env.t('undo') - div(ng-if='!user.preferences.hideHeader') - include menu header.site-header(ng-hide='user.preferences.hideHeader', role='banner', data-partysize='{{party.members.length>1 ? truarr(party.members.length) : 0}}') // avatar @@ -38,6 +36,3 @@ span(ng-controller='PartyCtrl') .herobox-wrap(ng-repeat='profile in partyMinusSelf') include avatar - - .npc_bailey.npc_bailey_head(ng-show='user.flags.newStuff', tooltip=env.t('psst'), tooltip-placement='top', ng-click='openModal("newStuff")') - diff --git a/views/shared/header/menu.jade b/views/shared/header/menu.jade index eea952c974..8b5ecbb338 100644 --- a/views/shared/header/menu.jade +++ b/views/shared/header/menu.jade @@ -1,41 +1,130 @@ -.user-menu(ng-controller='AuthCtrl') - ul.nav.site-nav(ng-show='authenticated()') - li.flyout - h1.task-action-btn.tile.solid.user-reporter {{user.profile.name}} - ul.flyout-content.nav.stacked - li - a.task-action-btn.tile.solid - span(ng-show='$state.includes("options")', ui-sref='tasks') - span.glyphicon.glyphicon-ok +a.collapse-toolbar(popover='Expand Toolbar',popover-placement='left',popover-trigger='mouseenter',ng-if='user.preferences.toolbarCollapsed',ng-click='set({"preferences.toolbarCollapsed":false})') + span.glyphicon.glyphicon-chevron-down + +nav.navbar.navbar-inverse(ng-controller='AuthCtrl',style='min-height:0px;margin-bottom:0px;border:0;border-radius:0px',ng-if='!user.preferences.toolbarCollapsed') + + ul.nav.navbar-nav.pull-right + li + a(popover='Collapse Toolbar',popover-placement='left',popover-trigger='mouseenter',,ng-if='!user.preferences.toolbarCollapsed',ng-click='set({"preferences.toolbarCollapsed":true})') + span.glyphicon.glyphicon-chevron-up.white + + .navbar-header + button.navbar-toggle(type='button', ng-click='isNavbarCollapsed = !isNavbarCollapsed', ng-init='isNavbarCollapsed = true') + span.sr-only Toggle navigation + span.icon-bar + span.icon-bar + span.icon-bar + .collapse.navbar-collapse(collapse="isNavbarCollapsed") + ul.nav.navbar-nav + + li(ui-sref='tasks') + a=env.t('tasks') + li.dropdown + a.dropdown-toggle + | Profile + span.caret + ul.dropdown-menu + li + a(ui-sref='options.profile.avatar') Avatar + li + a(ui-sref='options.profile.stats') Stats + li + a(ui-sref='options.profile.profile') Profile + li.dropdown + a.dropdown-toggle + | Social + span.caret + ul.dropdown-menu + li + a(ui-sref='options.social.tavern') Tavern + li + a(ui-sref='options.social.party') Party + li + a(ui-sref='options.social.guilds') Guilds + li + a(ui-sref='options.social.challenges') Challenges + li + a(ui-sref='options.social.hall') Hall + li.dropdown + a.dropdown-toggle + | Market + span.caret + ul.dropdown-menu + li + a(ui-sref='options.inventory.drops') Market + li + a(ui-sref='options.inventory.pets') Pets + li + a(ui-sref='options.inventory.mounts') Mounts + li + a(ui-sref='options.inventory.equipment') Equipment + li.dropdown + a.dropdown-toggle + | Settings + span.caret + ul.dropdown-menu + li + a(ui-sref='options.settings.settings') Settings + li + a(ui-sref='options.settings.api') API + li + a(ui-sref='options.settings.export') Export + li + a(ui-sref='options.settings.subscription') Subscription + li + a(ng-click='logout()') + span.glyphicon.glyphicon-share-alt |   - =env.t('tasks') - span(ng-show='$state.includes("tasks")', ui-sref='options') - span.glyphicon.glyphicon-wrench + =env.t('logout') + li.dropdown + a.dropdown-toggle + | Help + span.caret + ul.dropdown-menu + li + a(href="http://habitrpg.wikia.com/wiki/FAQ", target='_blank') + span.glyphicon.glyphicon-book |   - =env.t('options') - li - a.task-action-btn.tile.solid(href="http://habitrpg.wikia.com/wiki/FAQ", target='_blank') - span.glyphicon.glyphicon-book - |   - =env.t('FAQ') - li - a.task-action-btn.tile.solid(href="https://vimeo.com/57654086", target='_blank') - span.glyphicon.glyphicon-film - //|   Tutorials is too long to stay in the menu if we add a space - =env.t('tutorials') - li - a.task-action-btn.tile.solid(ng-click='User.sync()') - span.glyphicon.glyphicon-refresh - |   - =env.t('sync') - li - a.task-action-btn.tile.solid(ng-click='logout()') - span.glyphicon.glyphicon-share-alt - |   - =env.t('logout') - // party invitation notification - a(ng-show='user.party.invitation', x-bind='click:gotoPartyChat') - span.glyphicon.glyphicon-user - // party chat notification - a(ng-show='newChatMessages(_party.chat,user.party.lastMessageSeen)', x-bind='click:gotoPartyChat') - span.glyphicon.glyphicon-comment(tooltip=env.t('partyNotification')) + =env.t('FAQ') + li + a(href="https://vimeo.com/57654086", target='_blank') + span.glyphicon.glyphicon-film + //|   Tutorials is too long to stay in the menu if we add a space + =env.t('tutorials') + li + a(ng-click='User.sync()',popover=env.t('sync'),popover-placement='bottom',popover-trigger='mouseenter') + span.glyphicon.glyphicon-refresh.white + //-|   + //-=env.t('sync') + + li(style='border-right:1px solid #999;height:50px;display:block;') + span   + + li + a.pull-right.gem-wallet(style='padding-top:8px;padding-bottom:0px;',ng-click='openModal("buyGems",{track:"Gems > Wallet"})', popover-trigger='mouseenter', popover-title=env.t('gems'), popover=env.t('gemsWhatFor'), popover-placement='bottom',popover-append-to-body='true') + //span.task-action-btn.tile.flush.bright.add-gems-btn + + span.task-action-btn.tile.flush.neutral + .Pet_Currency_Gem2x.Gems + | {{user.balance * 4 | number:0}} + li + button.btn.btn-primary(style='margin-top:8px;margin-bottom:0px',ng-if='!user.purchased.plan.customerId',ui-sref='options.settings.subscription',popover-trigger='mouseenter',popover-placement='bottom',popover-title='Subscriptions',popover='Disable ads, buy gems with gold, monthly mystery item, retain progress history, double daily drop-caps, supports the devs. Click for more info.',popover-append-to-body='true') Subscribe + button.btn.btn-default(style='margin-top:8px;margin-bottom:0px',ng-if='user.purchased.plan.customerId',ui-sref='options.settings.subscription',popover-trigger='mouseenter',popover-placement='bottom',popover='Click to manage subscription',popover-append-to-body='true') Subscribed + + li(ng-if='user.flags.newStuff') + div.toolbar-bailey-container + |  + .npc_bailey.npc_bailey_head(popover=env.t('psst'), popover-trigger='mouseenter', popover-placement='bottom', popover-placement='bottom', ng-click='openModal("newStuff")') + + // Invitations + li(ng-if='user.invitations.party.id') + a(ui-sref='options.social.party') + span.glyphicon.glyphicon-user.white(popover='Invited to {{user.invitations.party.name}}',popover-placement='bottom',popover-trigger='mouseenter',popover-append-to-body='true') + li(ng-repeat='guild in user.invitations.guilds') + a(ui-sref='options.social.guilds') + span.glyphicon.glyphicon-user.white(popover='Invited to {{guid.name}}',popover-placement='bottom',popover-trigger='mouseenter',popover-append-to-body='true') + // Chat notifs + li(ng-repeat='(k,v) in user.newMessages', ng-if='v.value') + a(ng-click='k==party._id ? $state.go("options.social.party") : $state.go("options.social.guilds.detail",{gid:k})') + span.glyphicon.glyphicon-comment.white(popover='New message in "{{v.name}}"',popover-placement='bottom',popover-trigger='mouseenter',popover-append-to-body='true') + + From c95c6a4c3b3fb3de1f5edff7c866f20ecc75b959 Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Wed, 12 Feb 2014 21:24:50 -0700 Subject: [PATCH 09/34] chore(modals): remove mathUpdates modal (no longer in use). reference this commit for any future emergency updates --- public/js/controllers/notificationCtrl.js | 6 ------ views/shared/modals/new-stuff.jade | 14 -------------- 2 files changed, 20 deletions(-) diff --git a/public/js/controllers/notificationCtrl.js b/public/js/controllers/notificationCtrl.js index 1650a36f25..82c42af8a7 100644 --- a/public/js/controllers/notificationCtrl.js +++ b/public/js/controllers/notificationCtrl.js @@ -115,12 +115,6 @@ habitrpg.controller('NotificationCtrl', } }); - // Math updates modal - $rootScope.$watch('!user.flags.mathUpdates', function(after, before){ - if (after == before || after != true) return; - $rootScope.openModal('mathUpdates'); - }); - // Completed quest modal $rootScope.$watch('user.party.quest.completed', function(after, before){ if (after == before || after != true) return; diff --git a/views/shared/modals/new-stuff.jade b/views/shared/modals/new-stuff.jade index ebdf889759..ddab4fbd92 100644 --- a/views/shared/modals/new-stuff.jade +++ b/views/shared/modals/new-stuff.jade @@ -1,17 +1,3 @@ -//-div(modal='!user.flags.mathUpdates') -script(type='text/ng-template', id='modals/mathUpdates.html') - .modal-header - h4 Math Updates - .modal-body - .npc_tyler.pull-left - p Hey all, Tyler here. Sorry for the rocky numbers (Exp, GP, etc) with the Class System roll-out! We're tweaking the math today, and things should be mostly finalized by tomorrow. Follow our progress here, and please do chime in! - br - p We've also changed classes to unlock at lvl 10 instead of 5, to prevent overwhelming our new users. And since users have expressed confusion, we'll be improving UI and clarifification. Stay tuned. - br - p iOS users, iTunes is on vacation until 12/28. Until we can push the updated app, you'll need to sync periodically to get the corrected numbers (app has old math, server saves the correct numbers). Android goes out ASAP. More info on Trello. - .modal-footer - button.btn.btn-default(ng-click='User.set({"flags.mathUpdates":true}); $close()') Dismiss - script(type='text/ng-template', id='modals/newStuff.html') .modal-header h4 New Stuff! From 2750548d359c9253a02b708be007bc439419958e Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Wed, 12 Feb 2014 21:37:14 -0700 Subject: [PATCH 10/34] chore(bailey): bailey for chat notifs & toolbar --- views/shared/modals/new-stuff.jade | 65 +++++++++++++++++++----------- 1 file changed, 41 insertions(+), 24 deletions(-) diff --git a/views/shared/modals/new-stuff.jade b/views/shared/modals/new-stuff.jade index ddab4fbd92..af699aac98 100644 --- a/views/shared/modals/new-stuff.jade +++ b/views/shared/modals/new-stuff.jade @@ -12,38 +12,54 @@ script(type='text/ng-template', id='modals/newStuff.html') h3.popover-title a(target='_blank', href='https://twitter.com/Mihakuu') Bailey .popover-content + + table.table.table-striped tr td - h5 February Mystery Item - p - .pull-right.inventory_present - | We're excited to announce a new feature a s a big thank-you to the awesome people who subscribe to HabitRPG! Every month, all subscribers will now receive a limited-edition mystery item! The mystery item will be a stats-free costume piece (like the Absurd Party Robes) that will only be available to the people who are subscribers each month. The February 2014 item will be revealed on the 23rd to everyone, but all people who are subscribers during the month of February will receive it. Subscribe now, get excited, and thank you so much for helping to support HabitRPG! We love you. + h5 Chat & Invite Notifications + p Chat & group-invitation notifications are back! Miss them? They currently work for all chat updates in parties & guilds. Any devs willing to jump into @tagging in Tavern, see here. tr td - h5 Critical Hammer Of Bug-Crushing - p - .pull-right.weapon_special_critical - | Some of you may have noticed that we periodically have some bugs that are nastier than the norm - the dreaded critical bugs. These monstrous apparitions have been snapping at the heels of many a player. For updates on what we're currently working on to improve site stability, read this link - and then jump in to help! Not only will programming assistance reward you with the usual contributor levels, but if you actually manage to fix a bug marked "critical," you will now receive the Critical Hammer of Bug-Crushing as your reward! - tr - td - - h5 Rainbow Hair Colors - p - .pull-right.customize-option.hair_bangs_1_rainbow - | Want to spruce up your avatar? Rainbow hair colors are now available! Dye your luscious locks purple, green, or even rainbow-striped, and passersby will look at you with envy. - tr - td - h5 Stability Update - p We've stabilized the site a lot (we're still working out kinks, but we're way better now). Follow the progress here, but here are some workarounds for now: - ul - li Click slower. VersionError is caused by clicking things off too fast (we're working on a fix). - li If you see an error, refresh before proceeding. - + h5 Toolbar + p In order to make room for these notifs, we added a toolbar above the header. You can collapse the toolbar (far-right icon), but take care as Bailey notifs are inside the toolbar! p - small.muted By Lemoness, mariahm, crystalphoenix, aiseant, zoebeagle, cole, lefnire + small.muted 02/12/2014 + hr + h5 02/07/2014 + table.table.table-striped + tr + td + h5 February Mystery Item + p + .pull-right.inventory_present + | We're excited to announce a new feature a s a big thank-you to the awesome people who subscribe to HabitRPG! Every month, all subscribers will now receive a limited-edition mystery item! The mystery item will be a stats-free costume piece (like the Absurd Party Robes) that will only be available to the people who are subscribers each month. The February 2014 item will be revealed on the 23rd to everyone, but all people who are subscribers during the month of February will receive it. Subscribe now, get excited, and thank you so much for helping to support HabitRPG! We love you. + tr + td + h5 Critical Hammer Of Bug-Crushing + p + .pull-right.weapon_special_critical + | Some of you may have noticed that we periodically have some bugs that are nastier than the norm - the dreaded critical bugs. These monstrous apparitions have been snapping at the heels of many a player. For updates on what we're currently working on to improve site stability, read this link - and then jump in to help! Not only will programming assistance reward you with the usual contributor levels, but if you actually manage to fix a bug marked "critical," you will now receive the Critical Hammer of Bug-Crushing as your reward! + tr + td + + h5 Rainbow Hair Colors + p + .pull-right.customize-option.hair_bangs_1_rainbow + | Want to spruce up your avatar? Rainbow hair colors are now available! Dye your luscious locks purple, green, or even rainbow-striped, and passersby will look at you with envy. + tr + td + h5 Stability Update + p We've stabilized the site a lot (we're still working out kinks, but we're way better now). Follow the progress here, but here are some workarounds for now: + ul + li Click slower. VersionError is caused by clicking things off too fast (we're working on a fix). + li If you see an error, refresh before proceeding. + + p + small.muted By Lemoness, mariahm, crystalphoenix, aiseant, zoebeagle, cole, lefnire + hr h5 02/01/2014 table.table.table-striped @@ -54,6 +70,7 @@ script(type='text/ng-template', id='modals/newStuff.html') p small.muted by @baconsaur & @DanielTheBard + hr h5 01/30/2014 table.table.table-striped tr From f6abfc67b31808c0e2d325c235747260855338c9 Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Wed, 12 Feb 2014 21:44:27 -0700 Subject: [PATCH 11/34] feat(tracking): gems > toolbar separately from wallet --- views/shared/header/menu.jade | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/views/shared/header/menu.jade b/views/shared/header/menu.jade index 8b5ecbb338..1b0d1f00a9 100644 --- a/views/shared/header/menu.jade +++ b/views/shared/header/menu.jade @@ -101,7 +101,7 @@ nav.navbar.navbar-inverse(ng-controller='AuthCtrl',style='min-height:0px;margin- span   li - a.pull-right.gem-wallet(style='padding-top:8px;padding-bottom:0px;',ng-click='openModal("buyGems",{track:"Gems > Wallet"})', popover-trigger='mouseenter', popover-title=env.t('gems'), popover=env.t('gemsWhatFor'), popover-placement='bottom',popover-append-to-body='true') + a.pull-right.gem-wallet(style='padding-top:8px;padding-bottom:0px;',ng-click='openModal("buyGems",{track:"Gems > Toolbar"})', popover-trigger='mouseenter', popover-title=env.t('gems'), popover=env.t('gemsWhatFor'), popover-placement='bottom',popover-append-to-body='true') //span.task-action-btn.tile.flush.bright.add-gems-btn + span.task-action-btn.tile.flush.neutral .Pet_Currency_Gem2x.Gems From 5501d57e107c0bc7085847b0c808f027360fa405 Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Wed, 12 Feb 2014 21:51:35 -0700 Subject: [PATCH 12/34] fix(toolbar): tweaks --- public/js/services/groupServices.js | 2 +- views/shared/header/menu.jade | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/public/js/services/groupServices.js b/public/js/services/groupServices.js index eb0060c24c..db33d73de9 100644 --- a/public/js/services/groupServices.js +++ b/public/js/services/groupServices.js @@ -47,7 +47,7 @@ angular.module('groupServices', ['ngResource']). // On enter, set chat message to "seen" seenMessage: function(gid){ $http.post('/api/v2/groups/'+gid+'/chat/seen'); - User.user.newMessages[gid] = false; + if (User.user.newMessages) User.user.newMessages[gid] = false; }, Group: Group diff --git a/views/shared/header/menu.jade b/views/shared/header/menu.jade index 1b0d1f00a9..64aed67d5a 100644 --- a/views/shared/header/menu.jade +++ b/views/shared/header/menu.jade @@ -97,8 +97,9 @@ nav.navbar.navbar-inverse(ng-controller='AuthCtrl',style='min-height:0px;margin- //-|   //-=env.t('sync') - li(style='border-right:1px solid #999;height:50px;display:block;') - span   + // Separator + li + a(style='border-right:1px solid #999;cursor:default;padding-left:0px;padding-right:0px')   li a.pull-right.gem-wallet(style='padding-top:8px;padding-bottom:0px;',ng-click='openModal("buyGems",{track:"Gems > Toolbar"})', popover-trigger='mouseenter', popover-title=env.t('gems'), popover=env.t('gemsWhatFor'), popover-placement='bottom',popover-append-to-body='true') From 7456f00dc6122ad293652b7a32fb4ce671f75241 Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Wed, 12 Feb 2014 22:17:26 -0700 Subject: [PATCH 13/34] feat(toolbar): try with icons instead of text, test against prod / beta & get a vote. --- views/shared/header/menu.jade | 39 ++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/views/shared/header/menu.jade b/views/shared/header/menu.jade index 64aed67d5a..db2bfb1c40 100644 --- a/views/shared/header/menu.jade +++ b/views/shared/header/menu.jade @@ -17,11 +17,12 @@ nav.navbar.navbar-inverse(ng-controller='AuthCtrl',style='min-height:0px;margin- .collapse.navbar-collapse(collapse="isNavbarCollapsed") ul.nav.navbar-nav - li(ui-sref='tasks') - a=env.t('tasks') + li + a(ui-sref='tasks',popover=env.t('tasks'),popover-placement='right',popover-trigger='mouseenter') + span.glyphicon.glyphicon-check.white li.dropdown - a.dropdown-toggle - | Profile + a.dropdown-toggle(popover='Profile',popover-placement='right',popover-trigger='mouseenter') + span.glyphicon.glyphicon-user.white span.caret ul.dropdown-menu li @@ -30,9 +31,14 @@ nav.navbar.navbar-inverse(ng-controller='AuthCtrl',style='min-height:0px;margin- a(ui-sref='options.profile.stats') Stats li a(ui-sref='options.profile.profile') Profile + li + a(ng-click='logout()') + span.glyphicon.glyphicon-share-alt + |   + =env.t('logout') li.dropdown - a.dropdown-toggle - | Social + a.dropdown-toggle(popover='Social',popover-placement='right',popover-trigger='mouseenter') + span.glyphicon.glyphicon-heart.white span.caret ul.dropdown-menu li @@ -46,8 +52,8 @@ nav.navbar.navbar-inverse(ng-controller='AuthCtrl',style='min-height:0px;margin- li a(ui-sref='options.social.hall') Hall li.dropdown - a.dropdown-toggle - | Market + a.dropdown-toggle(popover='Market',popover-placement='right',popover-trigger='mouseenter') + span.glyphicon.glyphicon-gift.white span.caret ul.dropdown-menu li @@ -59,8 +65,8 @@ nav.navbar.navbar-inverse(ng-controller='AuthCtrl',style='min-height:0px;margin- li a(ui-sref='options.inventory.equipment') Equipment li.dropdown - a.dropdown-toggle - | Settings + a.dropdown-toggle(popover='Settings',popover-placement='right',popover-trigger='mouseenter') + span.glyphicon.glyphicon-wrench.white span.caret ul.dropdown-menu li @@ -71,14 +77,9 @@ nav.navbar.navbar-inverse(ng-controller='AuthCtrl',style='min-height:0px;margin- a(ui-sref='options.settings.export') Export li a(ui-sref='options.settings.subscription') Subscription - li - a(ng-click='logout()') - span.glyphicon.glyphicon-share-alt - |   - =env.t('logout') li.dropdown - a.dropdown-toggle - | Help + a.dropdown-toggle(popover='Help',popover-placement='right',popover-trigger='mouseenter') + span.glyphicon.glyphicon-question-sign.white span.caret ul.dropdown-menu li @@ -92,7 +93,7 @@ nav.navbar.navbar-inverse(ng-controller='AuthCtrl',style='min-height:0px;margin- //|   Tutorials is too long to stay in the menu if we add a space =env.t('tutorials') li - a(ng-click='User.sync()',popover=env.t('sync'),popover-placement='bottom',popover-trigger='mouseenter') + a(ng-click='User.sync()',popover=env.t('sync'),popover-placement='right',popover-trigger='mouseenter') span.glyphicon.glyphicon-refresh.white //-|   //-=env.t('sync') @@ -114,7 +115,7 @@ nav.navbar.navbar-inverse(ng-controller='AuthCtrl',style='min-height:0px;margin- li(ng-if='user.flags.newStuff') div.toolbar-bailey-container |  - .npc_bailey.npc_bailey_head(popover=env.t('psst'), popover-trigger='mouseenter', popover-placement='bottom', popover-placement='bottom', ng-click='openModal("newStuff")') + .npc_bailey.npc_bailey_head(popover=env.t('psst'), popover-trigger='mouseenter', popover-placement='right', ng-click='openModal("newStuff")') // Invitations li(ng-if='user.invitations.party.id') From c8faffcc7289090990c3a17ab8c07a00069f5ce4 Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Wed, 12 Feb 2014 22:31:32 -0700 Subject: [PATCH 14/34] fix(css): temp fix for bailey height --- public/css/npcs.styl | 1 + 1 file changed, 1 insertion(+) diff --git a/public/css/npcs.styl b/public/css/npcs.styl index c0c6aff155..4f55489d5c 100644 --- a/public/css/npcs.styl +++ b/public/css/npcs.styl @@ -12,6 +12,7 @@ .npc_bailey_head position: absolute top: 4px + height:45px !important cursor: pointer // Tour (Justin) From 8ba12ef39287754bab130bb7635703809abf5f4e Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Thu, 13 Feb 2014 11:54:45 -0700 Subject: [PATCH 15/34] chore(contribs_plan): add migration so contribl.lvl >= 7 gets free plan4life --- migrations/contribs_plan.js | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 migrations/contribs_plan.js diff --git a/migrations/contribs_plan.js b/migrations/contribs_plan.js new file mode 100644 index 0000000000..a08bd93f76 --- /dev/null +++ b/migrations/contribs_plan.js @@ -0,0 +1,23 @@ +// Give contrib.level 7+ free subscription for life +db.users.update( + + { + 'contributor.level':{$gte:7}, + 'purchased.plan.customerId':null + }, + + { + $set: { + 'purchased.plan':{ + planId: 'basic', + customerId: 'habitrpg', + dateCreated: new Date, + dateUpdated: new Date, + gemsBought: 0 + } + } + }, + + {multi:true} + +) \ No newline at end of file From fd6eb8724eae38d02849ffccb09f1f9c7d8e490d Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Thu, 13 Feb 2014 17:57:00 -0700 Subject: [PATCH 16/34] feat(valentine): valentine event --- public/js/controllers/rootCtrl.js | 6 +++++ src/controllers/user.js | 2 +- src/models/user.js | 7 ++++-- views/options/inventory/inventory.jade | 6 +++++ views/shared/modals/index.jade | 3 ++- views/shared/modals/limited.jade | 30 +++++++++++++++++++++++++ views/shared/profiles/achievements.jade | 6 +++++ views/shared/tasks/lists.jade | 18 +++++++++++++-- 8 files changed, 72 insertions(+), 6 deletions(-) create mode 100644 views/shared/modals/limited.jade diff --git a/public/js/controllers/rootCtrl.js b/public/js/controllers/rootCtrl.js index d9d56efe9e..508afbdf33 100644 --- a/public/js/controllers/rootCtrl.js +++ b/public/js/controllers/rootCtrl.js @@ -26,6 +26,7 @@ habitrpg.controller("RootCtrl", ['$scope', '$rootScope', '$location', 'User', '$ $rootScope.Shared = Shared; $rootScope.Content = Content; $rootScope.env = window.env; + $rootScope.Math = Math; // Angular UI Router $rootScope.$state = $state; @@ -198,6 +199,11 @@ habitrpg.controller("RootCtrl", ['$scope', '$rootScope', '$location', 'User', '$ */ $scope.castStart = function(spell) { if (User.user.stats.mp < spell.mana) return Notification.text(window.env.t('notEnoughMana')); + + // Temporary for valentine's day, remove after event + if (spell.key == 'valentine' && User.user.stats.gp < spell.value) + return Notification.text('Not enough gold.'); + $rootScope.applyingAction = true; $scope.spell = spell; if (spell.target == 'self') { diff --git a/src/controllers/user.js b/src/controllers/user.js index 5556a25093..caaab30546 100644 --- a/src/controllers/user.js +++ b/src/controllers/user.js @@ -409,7 +409,7 @@ api.cast = function(req, res, next) { case 'user': async.waterfall([ function(cb){ - Group.findOne({type: 'party', members: {'$in': [user._id]}}).populate('members', 'profile.name stats achievements').exec(cb); + Group.findOne({type: 'party', members: {'$in': [user._id]}}).populate('members', 'profile.name stats achievements items.special').exec(cb); }, function(group, cb) { // Solo player? let's just create a faux group for simpler code diff --git a/src/models/user.js b/src/models/user.js index 2614606e91..93800629bf 100644 --- a/src/models/user.js +++ b/src/models/user.js @@ -42,7 +42,8 @@ var UserSchema = new Schema({ rebirths: Number, rebirthLevel: Number, perfect: Number, - habitBirthday: Boolean + habitBirthday: Boolean, + valentine: Number }, auth: { facebook: Schema.Types.Mixed, @@ -136,7 +137,9 @@ var UserSchema = new Schema({ }, special:{ - snowball: {type: Number, 'default': 0} + snowball: {type: Number, 'default': 0}, + valentine: Number, + valentineReceived: Array // array of strings, by sender name }, // -------------- Animals ------------------- diff --git a/views/options/inventory/inventory.jade b/views/options/inventory/inventory.jade index 86171c082d..94264834df 100644 --- a/views/options/inventory/inventory.jade +++ b/views/options/inventory/inventory.jade @@ -68,6 +68,12 @@ script(type='text/ng-template', id='partials/options.inventory.drops.html') button.customize-option(popover='{{Content.special.snowball.notes}}', popover-title='{{Content.special.snowball.text}}', popover-trigger='mouseenter', popover-placement='right', ng-click='castStart(Content.special.snowball)', class='inventory_special_snowball') .badge.badge-info.stack-count {{user.items.special.snowball}} + li.customize-menu(ng-if='user.items.special.valentineReceived[0]') + menu.pets-menu(label=env.t('valentineCard')) + div + button.customize-option(popover="Valentine's Day Card from {{User.user.items.special.valentineReceived[0]}}", popover-trigger='mouseenter', popover-placement='right', ng-click='openModal("valentine")', class='inventory_special_valentine') + .badge.badge-info.stack-count {{user.items.special.valentineReceived.length}} + li.customize-menu(ng-if='user.purchased.plan.customerId') menu.pets-menu(label=env.t('subscriberItem')) div diff --git a/views/shared/modals/index.jade b/views/shared/modals/index.jade index a8c0626e99..c16838f72e 100644 --- a/views/shared/modals/index.jade +++ b/views/shared/modals/index.jade @@ -8,4 +8,5 @@ include ./settings include ./drops include ./classes include ./quests -include ./rebirth \ No newline at end of file +include ./rebirth +include ./limited \ No newline at end of file diff --git a/views/shared/modals/limited.jade b/views/shared/modals/limited.jade new file mode 100644 index 0000000000..8d2d31ce90 --- /dev/null +++ b/views/shared/modals/limited.jade @@ -0,0 +1,30 @@ +//Valentine +script(id='modals/valentine.html', type='text/ng-template') + .modal-header + h4 + .inventory_special_valentine.pull-right + =env.t('valentineCard') + .modal-body + .bg-info(style='padding:10px') + p To: {{user.profile.name}}, From: {{user.items.special.valentineReceived[0]}} + hr + div(ng-switch='Math.floor(Math.random()*3)') + ul.list-unstyled(ng-switch-when='0') + li "Roses are red + li My Dailies are blue + li I'm happy that I'm + li In a Party with you!" + ul.list-unstyled(ng-switch-when='1') + li "Roses are red + li Violets are nice + li Let's get together + li And fight against Vice!" + ul.list-unstyled(ng-switch-default) + li "Roses are red + li This poem style is old + li I hope that you like this + li Cuz it cost ten gold." + p + small For enduring such a saccharine poem, you both receive the "Adoring Friends" badge! + .modal-footer + button.btn.btn-default(ng-click='user.ops.readValentine({});$close()')=env.t('ok') \ No newline at end of file diff --git a/views/shared/profiles/achievements.jade b/views/shared/profiles/achievements.jade index a7261a8c37..d18e0c739f 100644 --- a/views/shared/profiles/achievements.jade +++ b/views/shared/profiles/achievements.jade @@ -133,3 +133,9 @@ div(ng-if='profile.achievements.habitBirthday') =env.t('habitBirthdayText') hr +div(ng-if='profile.achievements.valentine') + .achievement.achievement-valentine + h5=env.t('adoringFriends') + small + =env.t('adoringFriendsText', {cards: "{{profile.achievements.valentine}}"}) + hr diff --git a/views/shared/tasks/lists.jade b/views/shared/tasks/lists.jade index be5f5d1d0f..dc9010d279 100644 --- a/views/shared/tasks/lists.jade +++ b/views/shared/tasks/lists.jade @@ -58,8 +58,9 @@ script(id='templates/habitrpg-tasks.html', type="text/ng-template") span(bo-class='{"shop_{{item.key}} shop-sprite item-img": true}') p.task-text {{item.text}} - // Winter Event - ul.items.rewards(ng-if='main && list.type=="reward" && (user.items.special.snowball>0 || user.stats.buffs.snowball)') + // Events + ul.items.rewards(ng-if='main && list.type=="reward"') + li.task.reward-item(ng-if='user.items.special.snowball>0',popover-trigger='mouseenter', popover-placement='top', popover='{{Content.spells.special.snowball.notes}}') .task-meta-controls span.task-notes @@ -71,6 +72,7 @@ script(id='templates/habitrpg-tasks.html', type="text/ng-template") span.shop_snowball(style='display:inline-block;vertical-align:top;') // main content p.task-text {{Content.spells.special.snowball.text}} + li.task.reward-item(ng-if='user.stats.buffs.snowball',popover-trigger='mouseenter', popover-placement='top', popover='{{Content.spells.special.salt.notes}}') .task-meta-controls span.task-notes @@ -84,6 +86,18 @@ script(id='templates/habitrpg-tasks.html', type="text/ng-template") span.shop_salt.shop-sprite.item-img p.task-text {{Content.spells.special.salt.text}} + li.task.reward-item(popover-trigger='mouseenter', popover-placement='top', popover='{{Content.spells.special.valentine.notes}}') + .task-meta-controls + span.task-notes + span.glyphicon.glyphicon-comment + //left-hand size commands + .task-controls + a.money.btn-buy.item-btn(ng-click='castStart(Content.spells.special.valentine)') + span.reward-cost {{Content.spells.special.valentine.value}} + span.shop_gold + span.inventory_special_valentine.shop-sprite.item-img + p.task-text {{Content.spells.special.valentine.text}} + // Spells ul.items(ng-if='main && list.type=="reward" && user.stats.class && !user.preferences.disableClasses') li.task.reward-item(ng-repeat='(k,spell) in Content.spells[user.stats.class]', ng-if='user.stats.lvl >= spell.lvl',popover-trigger='mouseenter', popover-placement='top', popover='{{spell.notes}}') From 677c83c592b48ce4bfd1b1e8797461d15ed3b752 Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Thu, 13 Feb 2014 18:45:36 -0700 Subject: [PATCH 17/34] chore(bailey): valentine --- views/shared/modals/new-stuff.jade | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/views/shared/modals/new-stuff.jade b/views/shared/modals/new-stuff.jade index af699aac98..4e9d44abe9 100644 --- a/views/shared/modals/new-stuff.jade +++ b/views/shared/modals/new-stuff.jade @@ -13,21 +13,26 @@ script(type='text/ng-template', id='modals/newStuff.html') a(target='_blank', href='https://twitter.com/Mihakuu') Bailey .popover-content - - table.table.table-striped - tr - td - h5 Chat & Invite Notifications - p Chat & group-invitation notifications are back! Miss them? They currently work for all chat updates in parties & guilds. Any devs willing to jump into @tagging in Tavern, see here. - tr - td - h5 Toolbar - p In order to make room for these notifs, we added a toolbar above the header. You can collapse the toolbar (far-right icon), but take care as Bailey notifs are inside the toolbar! + h5 Happy Valentine's Day! + p Help motivate all of the lovely people in your life by sending them a caring valentine. Valentines can be purchased for 10 gold from the Item Store. For spreading love and joy throughout the community, both the giver AND the receiver get a coveted "adoring friends" badge. Hooray! p - small.muted 02/12/2014 - + small.muted By Lemoness and zoebeagle + hr + p + small.muted 02/13/2014 hr + h5 02/12/2014 + table.table.table-striped + tr + td + h5 Chat & Invite Notifications + p Chat & group-invitation notifications are back! Miss them? They currently work for all chat updates in parties & guilds. Any devs willing to jump into @tagging in Tavern, see here. + tr + td + h5 Toolbar + p In order to make room for these notifs, we added a toolbar above the header. You can collapse the toolbar (far-right icon), but take care as Bailey notifs are inside the toolbar! + hr h5 02/07/2014 table.table.table-striped tr From 4454204f47f80e64119f7896bf246259173d115b Mon Sep 17 00:00:00 2001 From: Sabe Jones Date: Thu, 13 Feb 2014 20:39:22 -0600 Subject: [PATCH 18/34] fix(toolbar): Tweak icon popovers Changed "Profile" toolbar icon popover to "User" and "Market" icon popover to "Inventory". Straightens out weird paths, so you don't go "Market > Market" or "Profile > Profile". --- views/shared/header/menu.jade | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/views/shared/header/menu.jade b/views/shared/header/menu.jade index db2bfb1c40..fc0244b7da 100644 --- a/views/shared/header/menu.jade +++ b/views/shared/header/menu.jade @@ -21,7 +21,7 @@ nav.navbar.navbar-inverse(ng-controller='AuthCtrl',style='min-height:0px;margin- a(ui-sref='tasks',popover=env.t('tasks'),popover-placement='right',popover-trigger='mouseenter') span.glyphicon.glyphicon-check.white li.dropdown - a.dropdown-toggle(popover='Profile',popover-placement='right',popover-trigger='mouseenter') + a.dropdown-toggle(popover='User',popover-placement='right',popover-trigger='mouseenter') span.glyphicon.glyphicon-user.white span.caret ul.dropdown-menu @@ -52,7 +52,7 @@ nav.navbar.navbar-inverse(ng-controller='AuthCtrl',style='min-height:0px;margin- li a(ui-sref='options.social.hall') Hall li.dropdown - a.dropdown-toggle(popover='Market',popover-placement='right',popover-trigger='mouseenter') + a.dropdown-toggle(popover='Inventory',popover-placement='right',popover-trigger='mouseenter') span.glyphicon.glyphicon-gift.white span.caret ul.dropdown-menu From 844dc93316477f1856918ebf61981e791733bc7d Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Thu, 13 Feb 2014 21:59:00 -0700 Subject: [PATCH 19/34] chore(jquery): use updated jquery directory location --- public/manifest.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/manifest.json b/public/manifest.json index ce7e2b6e8c..85e39cd970 100644 --- a/public/manifest.json +++ b/public/manifest.json @@ -1,7 +1,7 @@ { "app": { "js": [ - "bower_components/jquery/jquery.js", + "bower_components/jquery/dist/jquery.min.js", "bower_components/jquery.cookie/jquery.cookie.js", "bower_components/bootstrap-growl/jquery.bootstrap-growl.js", "bower_components/bootstrap-tour/build/js/bootstrap-tour.js", @@ -72,7 +72,7 @@ }, "static": { "js": [ - "bower_components/jquery/jquery.js", + "bower_components/jquery/dist/jquery.min.js", "bower_components/habitrpg-shared/dist/habitrpg-shared.js", "bower_components/angular/angular.js", "bower_components/angular-ui/build/angular-ui.js", From a33eabf20bdf856a8f7e80a8716c889086b21ff3 Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Thu, 13 Feb 2014 22:50:13 -0700 Subject: [PATCH 20/34] chore(bower): angular upgrade => 1.2.12 --- bower.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bower.json b/bower.json index 4af780151c..a6de245fda 100644 --- a/bower.json +++ b/bower.json @@ -17,9 +17,9 @@ "jquery": "~2.1.0", "jquery.cookie": "~1.4.0", "jquery-ui": "~1.10.3", - "angular": "~1.2.11", - "angular-sanitize": "~1.2.11", - "angular-resource": "~1.2.11", + "angular": "~1.2.12", + "angular-sanitize": "~1.2.12", + "angular-resource": "~1.2.12", "angular-ui-utils": "~0.1.0", "angular-ui-select2": "https://github.com/angular-ui/ui-select2.git#4469fd7a32eba2e28d5e3dd319b49e1ad090b167", "angular-bootstrap": "~0.10.0", @@ -42,6 +42,6 @@ "jquery-colorbox": "~1.4.36" }, "devDependencies": { - "angular-mocks": "~1.2.11" + "angular-mocks": "~1.2.12" } } From e241429cc3d2eca18d2f5a9726f6caa6270a1b02 Mon Sep 17 00:00:00 2001 From: Sabe Jones Date: Fri, 14 Feb 2014 08:14:02 -0600 Subject: [PATCH 21/34] fix(toolbar): Tweak Settings drop-down "Site" was the best I could come up with for all the miscellany in Settings > Settings. --- views/shared/header/menu.jade | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/views/shared/header/menu.jade b/views/shared/header/menu.jade index fc0244b7da..060cfd1f41 100644 --- a/views/shared/header/menu.jade +++ b/views/shared/header/menu.jade @@ -70,7 +70,7 @@ nav.navbar.navbar-inverse(ng-controller='AuthCtrl',style='min-height:0px;margin- span.caret ul.dropdown-menu li - a(ui-sref='options.settings.settings') Settings + a(ui-sref='options.settings.settings') Site li a(ui-sref='options.settings.api') API li From 850c4fda9ab93367454071343b3be1dce064ed63 Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Fri, 14 Feb 2014 10:33:10 -0700 Subject: [PATCH 22/34] fix(tags): span(type='submit') is invalid. But since you can't theme input-groups with input.input-group-addon, let's just make this an ng-click. fixes #2818 --- views/main/filters.jade | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/views/main/filters.jade b/views/main/filters.jade index 923d61e2a6..e356e552e5 100644 --- a/views/main/filters.jade +++ b/views/main/filters.jade @@ -21,7 +21,7 @@ form.form-inline(ng-show='_editing', ng-submit='createTag(_newTag)') .input-group input.form-control.input-sm(type='text', ng-model='_newTag', placeholder=env.t('newTag')) - span.input-group-addon(type='submit') + span.input-group-addon(ng-click='createTag(_newTag)') =env.t('add') //
  • li From 8f19f225f104960b3cf27e229a5571e014be697c Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Fri, 14 Feb 2014 18:35:21 +0100 Subject: [PATCH 23/34] fix(misc): some styles & translations --- Gruntfile.js | 8 ++++++- bower.json | 3 +++ views/options/profile.jade | 6 ++--- views/options/social/create-group.jade | 2 +- views/shared/header/avatar.jade | 1 + views/shared/header/menu.jade | 32 +++++++++++++------------- 6 files changed, 31 insertions(+), 21 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index 05979dbbe5..d778230751 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -4,6 +4,8 @@ module.exports = function(grunt) { // Project configuration. grunt.initConfig({ + pkg: grunt.file.readJSON('package.json'), + git_changelog: { minimal: { options: { @@ -81,7 +83,11 @@ module.exports = function(grunt) { } }, - nodemon: { dev: {} }, + nodemon: { + dev: { + script: '<%= pkg.main %>' + } + }, watch: { dev: { diff --git a/bower.json b/bower.json index a6de245fda..9bfab6d8d3 100644 --- a/bower.json +++ b/bower.json @@ -43,5 +43,8 @@ }, "devDependencies": { "angular-mocks": "~1.2.12" + }, + "resolutions": { + "angular": ">=1.2.0" } } diff --git a/views/options/profile.jade b/views/options/profile.jade index c9dc5b4575..18c0d72ef8 100644 --- a/views/options/profile.jade +++ b/views/options/profile.jade @@ -3,7 +3,7 @@ script(id='partials/options.profile.avatar.html', type='text/ng-template') .col-md-4 h3=env.t('bodyBody') small - | 2 / + | 2 / = ' ' + env.t('locked') h5=env.t('bodySize') @@ -27,7 +27,7 @@ script(id='partials/options.profile.avatar.html', type='text/ng-template') .col-md-4 h3=env.t('bodyHead') small - | 2 / + | 2 / = ' ' + env.t('locked') menu(type='list') // For special events code, see commit dfa27b3 @@ -86,7 +86,7 @@ script(id='partials/options.profile.avatar.html', type='text/ng-template') .col-md-4 h3=env.t('bodySkin') small - | 2 / + | 2 / = ' ' + env.t('locked') // skin li.customize-menu diff --git a/views/options/social/create-group.jade b/views/options/social/create-group.jade index 53c8879a02..bd2563cd76 100644 --- a/views/options/social/create-group.jade +++ b/views/options/social/create-group.jade @@ -5,7 +5,7 @@ label.control-label(for='new-group-name') | {{text}}  =env.t('name') - input.form-control#new-group-name.input-medium.option-content(required, type='text', placeholder='{{text}} Name', ng-model='newGroup.name') + input.form-control#new-group-name.input-medium.option-content(required, type='text', placeholder=('{{text}} ' + env.t('name')), ng-model='newGroup.name') .form-group label(for='new-group-description')=env.t('description') textarea.form-control#new-group-description.option-content(cols='3', placeholder=env.t('description'), ng-model='newGroup.description') diff --git a/views/shared/header/avatar.jade b/views/shared/header/avatar.jade index abc1c2fff8..971560d5af 100644 --- a/views/shared/header/avatar.jade +++ b/views/shared/header/avatar.jade @@ -48,4 +48,5 @@ figure.herobox(ng-click='spell ? castEnd(profile, "user", $event) : clickMember( |  =env.t('lvl') | {{profile.stats.lvl}} + |  span.glyphicon.glyphicon-plus-sign(ng-show='profile.achievements.rebirths', tooltip=env.t('reborn', {reLevel: "{{profile.achievements.rebirthLevel}}"})) diff --git a/views/shared/header/menu.jade b/views/shared/header/menu.jade index 060cfd1f41..ff9cbbc285 100644 --- a/views/shared/header/menu.jade +++ b/views/shared/header/menu.jade @@ -26,11 +26,11 @@ nav.navbar.navbar-inverse(ng-controller='AuthCtrl',style='min-height:0px;margin- span.caret ul.dropdown-menu li - a(ui-sref='options.profile.avatar') Avatar + a(ui-sref='options.profile.avatar')=env.t('avatar') li - a(ui-sref='options.profile.stats') Stats + a(ui-sref='options.profile.stats')=env.t('stats') li - a(ui-sref='options.profile.profile') Profile + a(ui-sref='options.profile.profile')=env.t('profile') li a(ng-click='logout()') span.glyphicon.glyphicon-share-alt @@ -42,41 +42,41 @@ nav.navbar.navbar-inverse(ng-controller='AuthCtrl',style='min-height:0px;margin- span.caret ul.dropdown-menu li - a(ui-sref='options.social.tavern') Tavern + a(ui-sref='options.social.tavern')=env.t('tavern') li - a(ui-sref='options.social.party') Party + a(ui-sref='options.social.party')=env.t('party') li - a(ui-sref='options.social.guilds') Guilds + a(ui-sref='options.social.guilds')=env.t('guilds') li - a(ui-sref='options.social.challenges') Challenges + a(ui-sref='options.social.challenges')=env.t('challenges') li - a(ui-sref='options.social.hall') Hall + a(ui-sref='options.social.hall')=env.t('hall') li.dropdown a.dropdown-toggle(popover='Inventory',popover-placement='right',popover-trigger='mouseenter') span.glyphicon.glyphicon-gift.white span.caret ul.dropdown-menu li - a(ui-sref='options.inventory.drops') Market + a(ui-sref='options.inventory.drops')=env.t('market') li - a(ui-sref='options.inventory.pets') Pets + a(ui-sref='options.inventory.pets')=env.t('mounts') li - a(ui-sref='options.inventory.mounts') Mounts + a(ui-sref='options.inventory.mounts')=env.t('mounts') li - a(ui-sref='options.inventory.equipment') Equipment + a(ui-sref='options.inventory.equipment')=env.t('equipment') li.dropdown a.dropdown-toggle(popover='Settings',popover-placement='right',popover-trigger='mouseenter') span.glyphicon.glyphicon-wrench.white span.caret ul.dropdown-menu li - a(ui-sref='options.settings.settings') Site + a(ui-sref='options.settings.settings')=env.t('site') li - a(ui-sref='options.settings.api') API + a(ui-sref='options.settings.api')=env.t('API') li - a(ui-sref='options.settings.export') Export + a(ui-sref='options.settings.export')=env.t('export') li - a(ui-sref='options.settings.subscription') Subscription + a(ui-sref='options.settings.subscription')=env.t('subscription') li.dropdown a.dropdown-toggle(popover='Help',popover-placement='right',popover-trigger='mouseenter') span.glyphicon.glyphicon-question-sign.white From e0193e36c3784242dcb93c3febfd5a7b98ab98a1 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Fri, 14 Feb 2014 18:43:18 +0100 Subject: [PATCH 24/34] chore(dependencies): update jquery parh --- bower.json | 3 --- public/manifest.json | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/bower.json b/bower.json index 9bfab6d8d3..a6de245fda 100644 --- a/bower.json +++ b/bower.json @@ -43,8 +43,5 @@ }, "devDependencies": { "angular-mocks": "~1.2.12" - }, - "resolutions": { - "angular": ">=1.2.0" } } diff --git a/public/manifest.json b/public/manifest.json index 85e39cd970..47ad0ed181 100644 --- a/public/manifest.json +++ b/public/manifest.json @@ -1,7 +1,7 @@ { "app": { "js": [ - "bower_components/jquery/dist/jquery.min.js", + "bower_components/jquery/query.min.js", "bower_components/jquery.cookie/jquery.cookie.js", "bower_components/bootstrap-growl/jquery.bootstrap-growl.js", "bower_components/bootstrap-tour/build/js/bootstrap-tour.js", From 00bece28d4dea85fb17907dc244b082ce403666f Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Fri, 14 Feb 2014 18:46:32 +0100 Subject: [PATCH 25/34] chore(dependencies): update jquery path --- public/manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/manifest.json b/public/manifest.json index 47ad0ed181..b9cedef609 100644 --- a/public/manifest.json +++ b/public/manifest.json @@ -1,7 +1,7 @@ { "app": { "js": [ - "bower_components/jquery/query.min.js", + "bower_components/jquery/jquery.min.js", "bower_components/jquery.cookie/jquery.cookie.js", "bower_components/bootstrap-growl/jquery.bootstrap-growl.js", "bower_components/bootstrap-tour/build/js/bootstrap-tour.js", From 33b326b59685ea6e50f9950094d009460ce80094 Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Fri, 14 Feb 2014 19:44:12 -0700 Subject: [PATCH 26/34] fix(challenges): better handling of deleted challenges. If !chal, break the task.challenge. Move the function into userController#score so we have access to next, etc. fixes #1883 --- src/controllers/user.js | 22 +++++++++++++++++++--- src/models/user.js | 16 ---------------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/controllers/user.js b/src/controllers/user.js index caaab30546..bd3011619e 100644 --- a/src/controllers/user.js +++ b/src/controllers/user.js @@ -89,10 +89,26 @@ api.score = function(req, res, next) { delta: delta, _tmp: user._tmp }, saved.toJSON().stats)); - }); - // if it's a challenge task, sync the score - user.syncScoreToChallenge(task, delta); + // If it's a challenge task, sync the score. Do it in the background, we've already sent down a response + // and the user doesn't care what happens back there + if (!task.challenge || !task.challenge.id || task.challenge.broken) return; + if (task.type == 'reward') return; // we don't want to update the reward GP cost + Challenge.findById(task.challenge.id, 'habits dailys todos rewards', function(err, chal){ + if (err) return next(err); + if (!chal) { + task.challenge.broken = 'CHALLENGE_DELETED'; + user.markModified('tasks'); + return user.save(); + } + var t = chal.tasks[task.id]; + if (!t) return chal.syncToUser(user); // this task was removed from the challenge, notify user + t.value += delta; + if (t.type == 'habit' || t.type == 'daily') + t.history.push({value: t.value, date: +new Date}); + chal.save(); + }); + }); }; /** diff --git a/src/models/user.js b/src/models/user.js index 93800629bf..9c1c5ba0cc 100644 --- a/src/models/user.js +++ b/src/models/user.js @@ -373,22 +373,6 @@ UserSchema.pre('save', function(next) { next(); }); -UserSchema.methods.syncScoreToChallenge = function(task, delta){ - if (!task.challenge || !task.challenge.id || task.challenge.broken) return; - if (task.type == 'reward') return; // we don't want to update the reward GP cost - var self = this; - Challenge.findById(task.challenge.id, function(err, chal){ - if (err) throw err; - var t = chal.tasks[task.id]; - if (!t) return chal.syncToUser(self); // this task was removed from the challenge, notify user - t.value += delta; - if (t.type == 'habit' || t.type == 'daily') { - t.history.push({value: t.value, date: +new Date}); - } - chal.save(); - }); -} - UserSchema.methods.unlink = function(options, cb) { var cid = options.cid, keep = options.keep, tid = options.tid; var self = this; From 191b789d760a7bdc7d1b53727f6127b677c78c94 Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Fri, 14 Feb 2014 20:04:59 -0700 Subject: [PATCH 27/34] fix(bower): updated jquery directory --- public/manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/manifest.json b/public/manifest.json index b9cedef609..85e39cd970 100644 --- a/public/manifest.json +++ b/public/manifest.json @@ -1,7 +1,7 @@ { "app": { "js": [ - "bower_components/jquery/jquery.min.js", + "bower_components/jquery/dist/jquery.min.js", "bower_components/jquery.cookie/jquery.cookie.js", "bower_components/bootstrap-growl/jquery.bootstrap-growl.js", "bower_components/bootstrap-tour/build/js/bootstrap-tour.js", From 78fcdd20c9ab676f9353751659e91aa6bc53980a Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Fri, 14 Feb 2014 20:37:16 -0700 Subject: [PATCH 28/34] chore(tests): tests to go along with #1883 challenges fix --- src/controllers/user.js | 1 - test/api.mocha.js | 27 +++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/controllers/user.js b/src/controllers/user.js index bd3011619e..b8979639c4 100644 --- a/src/controllers/user.js +++ b/src/controllers/user.js @@ -98,7 +98,6 @@ api.score = function(req, res, next) { if (err) return next(err); if (!chal) { task.challenge.broken = 'CHALLENGE_DELETED'; - user.markModified('tasks'); return user.save(); } var t = chal.tasks[task.id]; diff --git a/test/api.mocha.js b/test/api.mocha.js index 9b69fd461e..3f4f20d6f2 100644 --- a/test/api.mocha.js +++ b/test/api.mocha.js @@ -253,6 +253,33 @@ describe('API', function () { }); }); + it('Challenge deleted, breaks task link', function (done) { + var itThis = this; + request.del(baseURL + "/challenges/" + challenge._id).end(function (res) { + User.findById(user._id, function(err,user){ + var len = user.dailys.length- 1, + daily = user.dailys[user.dailys.length-1]; + expect(daily.challenge.broken).to.be('CHALLENGE_DELETED'); + + // Now let's handle if challenge was deleted, but didn't get to update all the users (an error) + var unset = {$unset:{}}; + unset['$unset']['dailys.' + len + '.challenge.broken'] = 1; + User.findByIdAndUpdate(user._id,unset,function(err,user){ + expect(err).to.not.be.ok(); + expect(user.dailys[len].challenge.broken).to.not.be.ok(); + request.post(baseURL + "/user/tasks/" + daily.id + "/up").end(function (res) { + setTimeout(function(){ + User.findById(user._id,function(err,user){ + expect(user.dailys[len].challenge.broken).to.be('CHALLENGE_DELETED'); + done() + }) + }, 100); // we need to wait for challenge to update user, it's a background job for perf reasons + }) + }) + }) + }) + }); + it('Admin creates a challenge', function (done) { User.findByIdAndUpdate(_id, {$set:{'contributor.admin':true}}, function (err,_user) { expect(err).to.not.be.ok(); From a624ea702d60cb4ad66cce454166a9f0c38b2986 Mon Sep 17 00:00:00 2001 From: deilann Date: Sat, 15 Feb 2014 06:48:29 -0800 Subject: [PATCH 29/34] fix inventory dropdown for pets --- views/shared/header/menu.jade | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/views/shared/header/menu.jade b/views/shared/header/menu.jade index ff9cbbc285..c1b0ddbf81 100644 --- a/views/shared/header/menu.jade +++ b/views/shared/header/menu.jade @@ -59,7 +59,7 @@ nav.navbar.navbar-inverse(ng-controller='AuthCtrl',style='min-height:0px;margin- li a(ui-sref='options.inventory.drops')=env.t('market') li - a(ui-sref='options.inventory.pets')=env.t('mounts') + a(ui-sref='options.inventory.pets')=env.t('pets') li a(ui-sref='options.inventory.mounts')=env.t('mounts') li From 94944f2cacf3ed09bc6783dce72169d5ec9de981 Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Sat, 15 Feb 2014 14:27:40 -0700 Subject: [PATCH 30/34] fix(quests): temp workaround for #2853 `Cannot read property 'collect' of undefined` --- src/models/group.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/models/group.js b/src/models/group.js index 0ecc16221e..5d80c0baf4 100644 --- a/src/models/group.js +++ b/src/models/group.js @@ -175,13 +175,13 @@ GroupSchema.methods.finishQuest = function(quest, cb) { } // FIXME this is a temporary measure, we need to remove quests from users when they traverse parties -function isOnQuest(user,group){ - return group && user.party.quest.key && user.party.quest.key == group.quest.key; +function isOnQuest(user,progress,group){ + return group && progress && user.party.quest.key && user.party.quest.key == group.quest.key; } GroupSchema.statics.collectQuest = function(user, progress, cb) { this.findOne({type: 'party', members: {'$in': [user._id]}},function(err, group){ - if (!isOnQuest(user,group)) return cb(null); + if (!isOnQuest(user,progress,group)) return cb(null); var quest = shared.content.quests[group.quest.key]; _.each(progress.collect,function(v,k){ @@ -215,7 +215,7 @@ GroupSchema.statics.collectQuest = function(user, progress, cb) { GroupSchema.statics.bossQuest = function(user, progress, cb) { this.findOne({type: 'party', members: {'$in': [user._id]}},function(err, group){ - if (!isOnQuest(user,group)) return cb(null); + if (!isOnQuest(user,progress,group)) return cb(null); var quest = shared.content.quests[group.quest.key]; if (!progress || !quest) return cb(null); // FIXME why is this ever happening, progress should be defined at this point var down = progress.down * quest.boss.str; // multiply by boss strength From 4018ec885b09c67f1b0ce080dd1011b699dc02ed Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Sun, 16 Feb 2014 14:51:48 +0100 Subject: [PATCH 31/34] fix(header): use strings and a small css fix --- views/options/social/index.jade | 4 ++-- views/shared/header/menu.jade | 32 ++++++++++++-------------------- 2 files changed, 14 insertions(+), 22 deletions(-) diff --git a/views/options/social/index.jade b/views/options/social/index.jade index a47ca1331a..cc2d7971c1 100644 --- a/views/options/social/index.jade +++ b/views/options/social/index.jade @@ -12,7 +12,7 @@ script(type='text/ng-template', id='partials/options.social.party.html') include ./group div(ng-hide='group._id') div(ng-show='user.invitations.party.id') - h2=env.t('invitedTo') + ' {{user.invitations.party.name}}' + h2=env.t('invitedTo', {name: '{{user.invitations.party.name}}'}) a.btn.btn-success(data-type='party', ng-click='join(user.invitations.party)')=env.t('accept') a.btn.btn-danger(ng-click='reject()')=env.t('reject') div(ng-hide='user.invitations.party.id') @@ -25,7 +25,7 @@ script(type='text/ng-template', id='partials/options.social.party.html') script(type='text/ng-template', id='partials/options.social.guilds.public.html') div(ng-repeat='invitation in user.invitations.guilds') - h3=env.t('invitedTo') + ' {{invitation.name}}' + h3=env.t('invitedTo', {name: '{{invitation.name}}'}) a.btn.btn-success(data-type='guild', ng-click='join(invitation)')=env.t('accept') a.btn.btn-danger(ng-click='reject(invitation)')=env.t('reject') // Public Groups diff --git a/views/shared/header/menu.jade b/views/shared/header/menu.jade index c1b0ddbf81..6e0bb09ac1 100644 --- a/views/shared/header/menu.jade +++ b/views/shared/header/menu.jade @@ -1,11 +1,11 @@ -a.collapse-toolbar(popover='Expand Toolbar',popover-placement='left',popover-trigger='mouseenter',ng-if='user.preferences.toolbarCollapsed',ng-click='set({"preferences.toolbarCollapsed":false})') +a.collapse-toolbar(popover=env.t('expandToolbar'),popover-placement='left',popover-trigger='mouseenter',ng-if='user.preferences.toolbarCollapsed',ng-click='set({"preferences.toolbarCollapsed":false})') span.glyphicon.glyphicon-chevron-down nav.navbar.navbar-inverse(ng-controller='AuthCtrl',style='min-height:0px;margin-bottom:0px;border:0;border-radius:0px',ng-if='!user.preferences.toolbarCollapsed') ul.nav.navbar-nav.pull-right li - a(popover='Collapse Toolbar',popover-placement='left',popover-trigger='mouseenter',,ng-if='!user.preferences.toolbarCollapsed',ng-click='set({"preferences.toolbarCollapsed":true})') + a(popover=env.t('collapseToolbar'),popover-placement='left',popover-trigger='mouseenter',,ng-if='!user.preferences.toolbarCollapsed',ng-click='set({"preferences.toolbarCollapsed":true})') span.glyphicon.glyphicon-chevron-up.white .navbar-header @@ -16,7 +16,6 @@ nav.navbar.navbar-inverse(ng-controller='AuthCtrl',style='min-height:0px;margin- span.icon-bar .collapse.navbar-collapse(collapse="isNavbarCollapsed") ul.nav.navbar-nav - li a(ui-sref='tasks',popover=env.t('tasks'),popover-placement='right',popover-trigger='mouseenter') span.glyphicon.glyphicon-check.white @@ -37,7 +36,7 @@ nav.navbar.navbar-inverse(ng-controller='AuthCtrl',style='min-height:0px;margin- |   =env.t('logout') li.dropdown - a.dropdown-toggle(popover='Social',popover-placement='right',popover-trigger='mouseenter') + a.dropdown-toggle(popover=env.t('social'),popover-placement='right',popover-trigger='mouseenter') span.glyphicon.glyphicon-heart.white span.caret ul.dropdown-menu @@ -52,7 +51,7 @@ nav.navbar.navbar-inverse(ng-controller='AuthCtrl',style='min-height:0px;margin- li a(ui-sref='options.social.hall')=env.t('hall') li.dropdown - a.dropdown-toggle(popover='Inventory',popover-placement='right',popover-trigger='mouseenter') + a.dropdown-toggle(popover=env.t('inventory'), popover-placement='right',popover-trigger='mouseenter') span.glyphicon.glyphicon-gift.white span.caret ul.dropdown-menu @@ -65,7 +64,7 @@ nav.navbar.navbar-inverse(ng-controller='AuthCtrl',style='min-height:0px;margin- li a(ui-sref='options.inventory.equipment')=env.t('equipment') li.dropdown - a.dropdown-toggle(popover='Settings',popover-placement='right',popover-trigger='mouseenter') + a.dropdown-toggle(popover=env.t('settings'),popover-placement='right',popover-trigger='mouseenter') span.glyphicon.glyphicon-wrench.white span.caret ul.dropdown-menu @@ -78,30 +77,23 @@ nav.navbar.navbar-inverse(ng-controller='AuthCtrl',style='min-height:0px;margin- li a(ui-sref='options.settings.subscription')=env.t('subscription') li.dropdown - a.dropdown-toggle(popover='Help',popover-placement='right',popover-trigger='mouseenter') + a.dropdown-toggle(popover=env.t('help'),popover-placement='right',popover-trigger='mouseenter') span.glyphicon.glyphicon-question-sign.white span.caret ul.dropdown-menu li a(href="http://habitrpg.wikia.com/wiki/FAQ", target='_blank') span.glyphicon.glyphicon-book - |   + |  =env.t('FAQ') li a(href="https://vimeo.com/57654086", target='_blank') span.glyphicon.glyphicon-film - //|   Tutorials is too long to stay in the menu if we add a space + |  =env.t('tutorials') li a(ng-click='User.sync()',popover=env.t('sync'),popover-placement='right',popover-trigger='mouseenter') span.glyphicon.glyphicon-refresh.white - //-|   - //-=env.t('sync') - - // Separator - li - a(style='border-right:1px solid #999;cursor:default;padding-left:0px;padding-right:0px')   - li a.pull-right.gem-wallet(style='padding-top:8px;padding-bottom:0px;',ng-click='openModal("buyGems",{track:"Gems > Toolbar"})', popover-trigger='mouseenter', popover-title=env.t('gems'), popover=env.t('gemsWhatFor'), popover-placement='bottom',popover-append-to-body='true') //span.task-action-btn.tile.flush.bright.add-gems-btn + @@ -109,8 +101,8 @@ nav.navbar.navbar-inverse(ng-controller='AuthCtrl',style='min-height:0px;margin- .Pet_Currency_Gem2x.Gems | {{user.balance * 4 | number:0}} li - button.btn.btn-primary(style='margin-top:8px;margin-bottom:0px',ng-if='!user.purchased.plan.customerId',ui-sref='options.settings.subscription',popover-trigger='mouseenter',popover-placement='bottom',popover-title='Subscriptions',popover='Disable ads, buy gems with gold, monthly mystery item, retain progress history, double daily drop-caps, supports the devs. Click for more info.',popover-append-to-body='true') Subscribe - button.btn.btn-default(style='margin-top:8px;margin-bottom:0px',ng-if='user.purchased.plan.customerId',ui-sref='options.settings.subscription',popover-trigger='mouseenter',popover-placement='bottom',popover='Click to manage subscription',popover-append-to-body='true') Subscribed + button.btn.btn-primary.navbar-btn(ng-if='!user.purchased.plan.customerId',ui-sref='options.settings.subscription',popover-trigger='mouseenter',popover-placement='bottom',popover-title=env.t('subscriptions'),popover=env.t('subDescription'),popover-append-to-body='true')=env.t('subscribe') + button.btn.btn-default.navbar-btn(ng-if='user.purchased.plan.customerId',ui-sref='options.settings.subscription',popover-trigger='mouseenter',popover-placement='bottom',popover=env.t('manageSub'),popover-append-to-body='true')=env.t('subscribed') li(ng-if='user.flags.newStuff') div.toolbar-bailey-container @@ -120,10 +112,10 @@ nav.navbar.navbar-inverse(ng-controller='AuthCtrl',style='min-height:0px;margin- // Invitations li(ng-if='user.invitations.party.id') a(ui-sref='options.social.party') - span.glyphicon.glyphicon-user.white(popover='Invited to {{user.invitations.party.name}}',popover-placement='bottom',popover-trigger='mouseenter',popover-append-to-body='true') + span.glyphicon.glyphicon-user.white(popover=env.t('invitedTo', {name: '{{user.invitations.party.name}}'}),popover-placement='bottom',popover-trigger='mouseenter',popover-append-to-body='true') li(ng-repeat='guild in user.invitations.guilds') a(ui-sref='options.social.guilds') - span.glyphicon.glyphicon-user.white(popover='Invited to {{guid.name}}',popover-placement='bottom',popover-trigger='mouseenter',popover-append-to-body='true') + span.glyphicon.glyphicon-user.white(popover=env.t('invitedTo', {name: '{{guild.name}}'}),popover-placement='bottom',popover-trigger='mouseenter',popover-append-to-body='true') // Chat notifs li(ng-repeat='(k,v) in user.newMessages', ng-if='v.value') a(ng-click='k==party._id ? $state.go("options.social.party") : $state.go("options.social.guilds.detail",{gid:k})') From 705d8a3b1a2d29eca62459f6101969b820ff31ac Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Sun, 16 Feb 2014 19:58:53 +0100 Subject: [PATCH 32/34] fix(css): fix chooseClass modal herobox padding --- public/css/classes.styl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/public/css/classes.styl b/public/css/classes.styl index 9c1cb75242..7360d0e756 100644 --- a/public/css/classes.styl +++ b/public/css/classes.styl @@ -1,6 +1,8 @@ .select-class .herobox width: 115px + padding-right: 0px + padding-left: 0px .character-sprites width: 0px height: 0px From 3c62388a67ea4e193e9c02cbe47392171d0d4200 Mon Sep 17 00:00:00 2001 From: Denis Date: Mon, 17 Feb 2014 16:48:08 +0200 Subject: [PATCH 33/34] chore(docs): fix outdated links for code contributors --- CONTRIBUTING.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 56e37cfe5f..463face2ad 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -14,5 +14,4 @@ HabitRPG uses [Trello](https://trello.com/b/EpoYEYod/habitrpg) to track feature # Contributing Code -* See [Contributing to HabitRPG](http://habitrpg.wikia.com/wiki/Contributing_to_HabitRPG) -* See [Tips](http://habitrpg.wikia.com/wiki/Tips) +* See [Contributing to HabitRPG](http://habitrpg.wikia.com/wiki/Contributing_to_HabitRPG#Coders_.28Web_.26_Mobile.29) From 9ba3362642973d618860553ef239f3c4d893382b Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Mon, 17 Feb 2014 22:43:09 +0100 Subject: [PATCH 34/34] fix(css): remove padding for heroboxes in modals, fix #2872 --- public/css/classes.styl | 2 -- public/css/index.styl | 4 ++++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/public/css/classes.styl b/public/css/classes.styl index 7360d0e756..9c1cb75242 100644 --- a/public/css/classes.styl +++ b/public/css/classes.styl @@ -1,8 +1,6 @@ .select-class .herobox width: 115px - padding-right: 0px - padding-left: 0px .character-sprites width: 0px height: 0px diff --git a/public/css/index.styl b/public/css/index.styl index 7ecb15ca2b..c10b3b12c9 100644 --- a/public/css/index.styl +++ b/public/css/index.styl @@ -118,6 +118,10 @@ html, body float: left padding: 15px + &.herobox + padding-right: 0px + padding-left: 0px + .death-modal // a .modal-body margin: 10px