diff --git a/common/locales/en/challenge.json b/common/locales/en/challenge.json
index abce3c33a6..edffd599a4 100644
--- a/common/locales/en/challenge.json
+++ b/common/locales/en/challenge.json
@@ -43,8 +43,8 @@
"exportChallengeCSV": "Export to CSV",
"selectGroup": "Please select group",
"challengeCreated": "Challenge created",
- "sureDelCha": "Delete challenge, are you sure?",
- "sureDelChaTavern": "Delete challenge, are you sure? Your gems will not be refunded.",
+ "sureDelCha": "Are you sure you want to delete this challenge?",
+ "sureDelChaTavern": "Are you sure you want to delete this challenge? Your gems will not be refunded.",
"removeTasks": "Remove Tasks",
"keepTasks": "Keep Tasks",
"closeCha": "Close challenge and...",
diff --git a/karma.conf.js b/karma.conf.js
index 3cc261a9eb..3c1d0e59ee 100644
--- a/karma.conf.js
+++ b/karma.conf.js
@@ -35,44 +35,18 @@ module.exports = function(config) {
'website/public/bower_components/js-emoji/emoji.js',
'common/dist/scripts/habitrpg-shared.js',
- "test/spec/mocks/translations.js",
- "test/spec/mocks/sandbox.js",
-
"website/public/js/env.js",
"website/public/js/app.js",
"common/script/public/config.js",
- "website/public/js/services/sharedServices.js",
- "website/public/js/services/notificationServices.js",
"common/script/public/userServices.js",
"common/script/public/directives.js",
- "website/public/js/services/analyticsServices.js",
- "website/public/js/services/groupServices.js",
- "website/public/js/services/chatServices.js",
- "website/public/js/services/memberServices.js",
- "website/public/js/services/guideServices.js",
- "website/public/js/services/challengeServices.js",
- "website/public/js/services/taskServices.js",
- "website/public/js/services/paymentServices.js",
- "website/public/js/services/questServices.js",
- "website/public/js/services/statServices.js",
- "website/public/js/filters/money.js",
- "website/public/js/filters/roundLargeNumbers.js",
- "website/public/js/filters/taskOrdering.js",
+ "website/public/js/services/**/*.js",
+ "website/public/js/filters/**/*.js",
+ "website/public/js/directives/**/*.directive.js",
+ "website/public/js/controllers/**/*.js",
- "website/public/js/directives/focus-me.directive.js",
- "website/public/js/directives/from-now.directive.js",
- "website/public/js/directives/habitrpg-tasks.directive.js",
- "website/public/js/directives/hrpg-sort-checklist.directive.js",
- "website/public/js/directives/hrpg-sort-tags.directive.js",
- "website/public/js/directives/hrpg-sort-tasks.directive.js",
- "website/public/js/directives/popover-html-popup.directive.js",
- "website/public/js/directives/popover-html.directive.js",
- "website/public/js/directives/task-focus.directive.js",
- "website/public/js/directives/when-scrolled.directive.js",
-
- "website/public/js/controllers/*.js",
'test/spec/mocks/**/*.js',
'test/spec/specHelper.js',
'test/spec/**/*.js'
diff --git a/test/api/get_user.coffee b/test/api/get_user.coffee
new file mode 100644
index 0000000000..530fa398a9
--- /dev/null
+++ b/test/api/get_user.coffee
@@ -0,0 +1,25 @@
+'use strict'
+
+require('../../website/src/server')
+
+describe 'User', ->
+
+ before (done) ->
+ registerNewUser done, true
+
+ describe 'GET /user', ->
+ it 'removes password from user object', (done) ->
+ request.get(baseURL + '/user')
+ .end (err, res) ->
+ expectCode res, 200
+ localAuth = res.body.auth.local
+ expect(localAuth.hashed_password).to.not.exist
+ expect(localAuth.salt).to.not.exist
+ done()
+
+ it 'removes apiToken from user object', (done) ->
+ request.get(baseURL + '/user')
+ .end (err, res) ->
+ expectCode res, 200
+ expect(res.body.apiToken).to.not.exist
+ done()
diff --git a/test/spec/directives/close-menu.directive.js b/test/spec/directives/close-menu.directive.js
new file mode 100644
index 0000000000..3c50b16cc6
--- /dev/null
+++ b/test/spec/directives/close-menu.directive.js
@@ -0,0 +1,25 @@
+'use strict';
+
+describe('closeMenu Directive', function() {
+ var menuElement, scope;
+
+ beforeEach(module('habitrpg'));
+
+ beforeEach(inject(function($rootScope, $compile) {
+ scope = $rootScope.$new();
+
+ var element = '';
+
+ menuElement = $compile(element)(scope);
+ scope.$digest();
+ }));
+
+ it('closes a connected menu when element is clicked', function() {
+ scope._expandedMenu = 'mobile';
+ menuElement.appendTo(document.body);
+
+ menuElement.triggerHandler('click');
+
+ expect(scope._expandedMenu).to.eql(null)
+ });
+});
diff --git a/test/spec/directives/expand-menu.directive.js b/test/spec/directives/expand-menu.directive.js
new file mode 100644
index 0000000000..f73de77c5b
--- /dev/null
+++ b/test/spec/directives/expand-menu.directive.js
@@ -0,0 +1,34 @@
+'use strict';
+
+describe('expandMenu Directive', function() {
+ var menuElement, scope;
+
+ beforeEach(module('habitrpg'));
+
+ beforeEach(inject(function($rootScope, $compile) {
+ scope = $rootScope.$new();
+
+ var element = '';
+
+ menuElement = $compile(element)(scope);
+ scope.$digest();
+ }));
+
+ it('expands a connected menu when element is clicked', function() {
+ expect(scope._expandedMenu).to.not.exist;
+ menuElement.appendTo(document.body);
+
+ menuElement.triggerHandler('click');
+
+ expect(scope._expandedMenu).to.eql('mobile')
+ });
+
+ it('closes a connected menu when it is already open', function() {
+ scope._expandedMenu = 'mobile';
+ menuElement.appendTo(document.body);
+
+ menuElement.triggerHandler('click');
+
+ expect(scope._expandedMenu).to.eql(null)
+ });
+});
diff --git a/website/public/js/controllers/menuCtrl.js b/website/public/js/controllers/menuCtrl.js
index f9f8f9e69c..5549c527dd 100644
--- a/website/public/js/controllers/menuCtrl.js
+++ b/website/public/js/controllers/menuCtrl.js
@@ -9,10 +9,6 @@ angular.module('habitrpg')
window.location.href = '/logout';
};
- $scope.expandMenu = function(menu) {
- $scope._expandedMenu = ($scope._expandedMenu == menu) ? null : menu;
- };
-
function selectNotificationValue(mysteryValue, invitationValue, cardValue, unallocatedValue, messageValue, noneValue) {
var user = $scope.user;
if (user.purchased && user.purchased.plan && user.purchased.plan.mysteryItems && user.purchased.plan.mysteryItems.length) {
diff --git a/website/public/js/directives/close-menu.directive.js b/website/public/js/directives/close-menu.directive.js
new file mode 100644
index 0000000000..c932cfcd41
--- /dev/null
+++ b/website/public/js/directives/close-menu.directive.js
@@ -0,0 +1,20 @@
+'use strict';
+
+(function(){
+
+ angular
+ .module('habitrpg')
+ .directive('closeMenu', closeMenu);
+
+ function closeMenu() {
+ return {
+ restrict: 'A',
+ link: function($scope, element, attrs) {
+ element.on('click', function(event) {
+ $scope._expandedMenu = null;
+ $scope.$apply()
+ });
+ }
+ }
+ }
+}());
diff --git a/website/public/js/directives/expand-menu.directive.js b/website/public/js/directives/expand-menu.directive.js
new file mode 100644
index 0000000000..246c649a70
--- /dev/null
+++ b/website/public/js/directives/expand-menu.directive.js
@@ -0,0 +1,20 @@
+'use strict';
+
+(function(){
+
+ angular
+ .module('habitrpg')
+ .directive('expandMenu', expandMenu);
+
+ function expandMenu() {
+ return {
+ restrict: 'A',
+ link: function($scope, element, attrs) {
+ element.on('click', function(event) {
+ $scope._expandedMenu = ($scope._expandedMenu === attrs.menu) ? null : attrs.menu;
+ $scope.$apply()
+ });
+ }
+ }
+ }
+}());
diff --git a/website/public/js/directives/focus-me.directive.js b/website/public/js/directives/focus-me.directive.js
index da0bd20681..0fdec0e390 100644
--- a/website/public/js/directives/focus-me.directive.js
+++ b/website/public/js/directives/focus-me.directive.js
@@ -12,9 +12,9 @@
function focusMe($timeout, $parse) {
return {
- link: function(scope, element, attrs) {
+ link: function($scope, element, attrs) {
var model = $parse(attrs.focusMe);
- scope.$watch(model, function(value) {
+ $scope.$watch(model, function(value) {
$timeout(function() {
element[0].focus();
});
diff --git a/website/public/js/directives/from-now.directive.js b/website/public/js/directives/from-now.directive.js
index 83ddae3b61..54236c92ee 100644
--- a/website/public/js/directives/from-now.directive.js
+++ b/website/public/js/directives/from-now.directive.js
@@ -11,18 +11,18 @@
];
function fromNow($interval, $timeout) {
- return function(scope, element, attr){
+ return function($scope, element, attr){
var interval, timeout;
var updateText = function(){
- element.text(moment(scope.message.timestamp).fromNow());
+ element.text(moment($scope.message.timestamp).fromNow());
};
var setupInterval = function() {
if(interval) $interval.cancel(interval);
if(timeout) $timeout.cancel(timeout);
- var diff = moment().diff(scope.message.timestamp, 'minute');
+ var diff = moment().diff($scope.message.timestamp, 'minute');
if(diff < 60) {
// Update every minute
@@ -37,7 +37,7 @@
updateText();
setupInterval();
- scope.$on('$destroy', function() {
+ $scope.$on('$destroy', function() {
if(interval) $interval.cancel(interval);
if(timeout) $timeout.cancel(timeout);
});
diff --git a/website/public/js/directives/habitrpg-tasks.directive.js b/website/public/js/directives/habitrpg-tasks.directive.js
index 9708c58f9e..a185cf4f6b 100644
--- a/website/public/js/directives/habitrpg-tasks.directive.js
+++ b/website/public/js/directives/habitrpg-tasks.directive.js
@@ -19,10 +19,10 @@
// main: '@', // true if it's the user's main list
// obj: '='
//},
- link: function(scope, element, attrs) {
+ link: function($scope, element, attrs) {
// $scope.obj needs to come from controllers, so we can pass by ref
- scope.main = attrs.main;
- scope.modal = attrs.modal;
+ $scope.main = attrs.main;
+ $scope.modal = attrs.modal;
var dailiesView;
if(User.user.preferences.dailyDueDefaultView) {
dailiesView = "remaining";
diff --git a/website/public/js/directives/popover-html-popup.directive.js b/website/public/js/directives/popover-html-popup.directive.js
index d4f76a1267..0c378a6872 100644
--- a/website/public/js/directives/popover-html-popup.directive.js
+++ b/website/public/js/directives/popover-html-popup.directive.js
@@ -15,9 +15,9 @@
restrict: 'EA',
replace: true,
scope: { title: '@', content: '@', placement: '@', animation: '&', isOpen: '&' },
- link: function(scope, element, attrs) {
- scope.$watch('content', function(value, oldValue) {
- scope.unsafeContent = $sce.trustAsHtml(scope.content);
+ link: function($scope, element, attrs) {
+ $scope.$watch('content', function(value, oldValue) {
+ $scope.unsafeContent = $sce.trustAsHtml($scope.content);
});
},
templateUrl: 'template/popover/popover-html.html'
diff --git a/website/public/js/directives/task-focus.directive.js b/website/public/js/directives/task-focus.directive.js
index ae6a30c84b..00faf89259 100644
--- a/website/public/js/directives/task-focus.directive.js
+++ b/website/public/js/directives/task-focus.directive.js
@@ -13,8 +13,8 @@
*/
function taskFocus($timeout) {
- return function(scope, elem, attrs) {
- scope.$watch(attrs.taskFocus, function(newVal) {
+ return function($scope, elem, attrs) {
+ $scope.$watch(attrs.taskFocus, function(newVal) {
if (newVal) {
$timeout(function() {
elem[0].focus();
diff --git a/website/public/js/directives/when-scrolled.directive.js b/website/public/js/directives/when-scrolled.directive.js
index 5fa0cbb998..86bd5fa7fb 100644
--- a/website/public/js/directives/when-scrolled.directive.js
+++ b/website/public/js/directives/when-scrolled.directive.js
@@ -6,12 +6,12 @@
.directive('whenScrolled', whenScrolled);
function whenScrolled() {
- return function(scope, elm, attr) {
+ return function($scope, elm, attr) {
var raw = elm[0];
elm.bind('scroll', function() {
if (raw.scrollTop + raw.offsetHeight >= raw.scrollHeight) {
- scope.$apply(attr.whenScrolled);
+ $scope.$apply(attr.whenScrolled);
}
});
};
diff --git a/website/public/manifest.json b/website/public/manifest.json
index aac57bbc00..73fe262ee3 100644
--- a/website/public/manifest.json
+++ b/website/public/manifest.json
@@ -58,6 +58,8 @@
"js/filters/roundLargeNumbers.js",
"js/filters/taskOrdering.js",
+ "js/directives/close-menu.directive.js",
+ "js/directives/expand-menu.directive.js",
"js/directives/focus-me.directive.js",
"js/directives/from-now.directive.js",
"js/directives/habitrpg-tasks.directive.js",
diff --git a/website/src/controllers/user.js b/website/src/controllers/user.js
index 89ea68ef7b..4e261ec3d8 100644
--- a/website/src/controllers/user.js
+++ b/website/src/controllers/user.js
@@ -204,9 +204,9 @@ api.getUser = function(req, res, next) {
user.stats.maxHealth = shared.maxHealth;
user.stats.maxMP = res.locals.user._statsComputed.maxMP;
delete user.apiToken;
- if (user.auth) {
- delete user.auth.hashed_password;
- delete user.auth.salt;
+ if (user.auth && user.auth.local) {
+ delete user.auth.local.hashed_password;
+ delete user.auth.local.salt;
}
return res.json(200, user);
};
diff --git a/website/views/shared/header/menu.jade b/website/views/shared/header/menu.jade
index 251ef447af..12a3ac5298 100644
--- a/website/views/shared/header/menu.jade
+++ b/website/views/shared/header/menu.jade
@@ -2,9 +2,9 @@ nav.toolbar(ng-controller='MenuCtrl')
.toolbar-container
ul.toolbar-mobile-nav
li.toolbar-mobile
- a(ng-click='expandMenu("mobile")', ng-class='{active: _expandedMenu=="mobile"}')
+ a(data-expand-menu, menu="mobile", ng-class='{active: _expandedMenu=="mobile"}')
span.glyphicon.glyphicon-align-justify
- div(ng-if='_expandedMenu=="mobile"', ng-click='expandMenu(null)')
+ div(ng-show='_expandedMenu=="mobile"', data-close-menu)
h4=env.t('menu')
div
ul.toolbar-submenu
@@ -71,18 +71,18 @@ nav.toolbar(ng-controller='MenuCtrl')
li.toolbar-subscribe-button
button(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')
li.toolbar-controls-button
- a(ng-click='expandMenu(null)')=env.t('close')
+ a(data-close-menu)=env.t('close')
ul.toolbar-nav
li.toolbar-button
- a(ui-sref='tasks')
+ a(ui-sref='tasks', data-close-menu)
span=env.t('tasks')
li.toolbar-button-dropdown
- a(ui-sref='options.profile.avatar')
+ a(ui-sref='options.profile.avatar', data-close-menu)
span=env.t('user')
- a(ng-click='expandMenu("avatar")', ng-class='{active: _expandedMenu == "avatar"}')
+ a(ng-class='{active: _expandedMenu == "avatar"}', data-expand-menu, menu='avatar')
span ☰
- div(ng-if='_expandedMenu == "avatar"')
- ul.toolbar-submenu(ng-click='expandMenu(null)')
+ div(ng-show='_expandedMenu == "avatar"', data-close-menu)
+ ul.toolbar-submenu
li
a(ui-sref='options.profile.avatar')=env.t('avatar')
li
@@ -94,12 +94,12 @@ nav.toolbar(ng-controller='MenuCtrl')
li.toolbar-button-dropdown
a(ui-sref='options.social.inbox', ng-if='user.inbox.newMessages')
span.badge.badge-danger {{user.inbox.newMessages}}
- a(ui-sref='options.social.tavern')
+ a(ui-sref='options.social.tavern', data-close-menu)
span=env.t('social')
- a(ng-click='expandMenu("social")', ng-class='{active: _expandedMenu == "social"}')
+ a(ng-class='{active: _expandedMenu == "social"}', data-expand-menu, menu='social')
span ☰
- div(ng-if='_expandedMenu == "social"')
- ul.toolbar-submenu(ng-click='expandMenu(null)')
+ div(ng-show='_expandedMenu == "social"', data-close-menu)
+ ul.toolbar-submenu
li
a(ui-sref='options.social.inbox')
span.badge.badge-danger(ng-if='user.inbox.newMessages') {{user.inbox.newMessages}}
@@ -115,12 +115,12 @@ nav.toolbar(ng-controller='MenuCtrl')
li
a(ui-sref='options.social.hall.heroes')=env.t('hall')
li.toolbar-button-dropdown
- a(ui-sref='options.inventory.drops')
+ a(ui-sref='options.inventory.drops', data-close-menu)
span=env.t('inventory')
- a(ng-click='expandMenu("inventory")', ng-class='{active: _expandedMenu == "inventory"}')
+ a(ng-class='{active: _expandedMenu == "inventory"}' data-expand-menu, menu='inventory')
span ☰
- div(ng-if='_expandedMenu == "inventory"')
- ul.toolbar-submenu(ng-click='expandMenu(null)')
+ div(ng-show='_expandedMenu == "inventory"', data-close-menu)
+ ul.toolbar-submenu
li
a(ui-sref='options.inventory.drops')=env.t('market')
li
@@ -136,12 +136,12 @@ nav.toolbar(ng-controller='MenuCtrl')
li
a(ui-sref='options.inventory.seasonalshop')=env.t('seasonalShop')
li.toolbar-button-dropdown
- a(target="_blank" ng-href='http://data.habitrpg.com?uuid={{user._id}}')
+ a(target="_blank" ng-href='http://data.habitrpg.com?uuid={{user._id}}', data-close-menu)
span=env.t('data')
- a(ng-click='expandMenu("data")', ng-class='{active: _expandedMenu == "data"}')
+ a(ng-class='{active: _expandedMenu == "data"}', data-expand-menu, menu='data')
span ☰
- div(ng-if='_expandedMenu == "data"')
- ul.toolbar-submenu(ng-click='expandMenu(null)')
+ div(ng-show='_expandedMenu == "data"', data-close-menu)
+ ul.toolbar-submenu
li
a(target="_blank" ng-href='http://data.habitrpg.com?uuid={{user._id}}')=env.t('dataTool')
li
@@ -150,10 +150,10 @@ nav.toolbar(ng-controller='MenuCtrl')
a(target="_blank" href='http://habitica.wikia.com/wiki/')
span.glyphicon.glyphicon-question-sign
span=env.t('help')
- a(ng-click='expandMenu("help")', ng-class='{active: _expandedMenu == "help"}')
+ a(ng-class='{active: _expandedMenu == "help"}', data-expand-menu, menu='help')
span ☰
- div(ng-if='_expandedMenu == "help"')
- ul.toolbar-submenu(ng-click='expandMenu(null)')
+ div(ng-show='_expandedMenu == "help"', data-close-menu)
+ ul.toolbar-submenu
li
a(target="_blank" href='http://habitica.wikia.com/wiki/')=env.t('overview')
li
@@ -171,9 +171,9 @@ nav.toolbar(ng-controller='MenuCtrl')
button.highlight(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')
ul.toolbar-options
li.toolbar-notifs
- a(ng-click='expandMenu("notifs")')
+ a(data-expand-menu, menu='notifs')
span.glyphicon(ng-class='iconClasses()')
- div(ng-if='_expandedMenu=="notifs"')
+ div(ng-show='_expandedMenu=="notifs"', data-close-menu)
h4=env.t('notifications')
div
ul.toolbar-notifs-notifs
@@ -183,7 +183,7 @@ nav.toolbar(ng-controller='MenuCtrl')
span.glyphicon.glyphicon-gift
span=env.t('newSubscriberItem')
li(ng-if='user.invitations.party.id')
- a(ui-sref='options.social.party', ng-click='expandMenu(null)')
+ a(ui-sref='options.social.party')
span.glyphicon.glyphicon-user
span=env.t('invitedTo', {name: '{{user.invitations.party.name}}'})
li(ng-if='user.flags.cardReceived')
@@ -193,11 +193,11 @@ nav.toolbar(ng-controller='MenuCtrl')
a(ng-click='clearCards()', popover=env.t('clear'),popover-placement='right',popover-trigger='mouseenter',popover-append-to-body='true')
span.glyphicon.glyphicon-remove-circle
li(ng-repeat='guild in user.invitations.guilds')
- a(ui-sref='options.social.guilds.public', ng-click='expandMenu(null)')
+ a(ui-sref='options.social.guilds.public')
span.glyphicon.glyphicon-user
span=env.t('invitedTo', {name: '{{guild.name}}'})
li(ng-if='user.flags.classSelected && !user.preferences.disableClasses && user.stats.points')
- a(ui-sref='options.profile.stats', ng-click='expandMenu(null)')
+ a(ui-sref='options.profile.stats')
span.glyphicon.glyphicon-plus-sign
span=env.t('haveUnallocated', {points: '{{user.stats.points}}'})
li(ng-repeat='(k,v) in user.newMessages', ng-if='v.value')
@@ -209,35 +209,35 @@ nav.toolbar(ng-controller='MenuCtrl')
ul.toolbar-controls
li.toolbar-controls-button
- a(ng-click='expandMenu(null)')=env.t('close')
+ a(data-close-menu)=env.t('close')
li.toolbar-audio
- a(ng-click='expandMenu("audio")')
+ a(data-expand-menu, menu="audio")
span.glyphicon(ng-class="{'glyphicon-volume-off':user.preferences.sound=='off', 'glyphicon-volume-up':user.preferences.sound!='off'}")
- div(ng-if='_expandedMenu=="audio"',style='min-width:150px')
+ div(ng-show='_expandedMenu=="audio"',style='min-width:150px', data-close-menu)
h4=env.t('audioTheme')
div
- ul.toolbar-submenu(ng-click='expandMenu(null)')
+ ul.toolbar-submenu
// Using [{k,v}] instead of {k:v,k:v} to maintain order ('off' at top)
for theme in ['off','danielTheBard', 'wattsTheme', 'gokulTheme']
li
a(ng-class="{'bg-primary':user.preferences.sound=='#{theme}'}", ng-click="set({'preferences.sound':'#{theme}'})")=env.t('audioTheme_'+theme)
ul.toolbar-controls
li.toolbar-controls-button
- a(ng-click='expandMenu(null)')=env.t('close')
+ a(data-close-menu)=env.t('close')
li.toolbar-sync
a(ng-click='User.sync()', popover=env.t('sync'),popover-placement='bottom',popover-trigger='mouseenter')
span.glyphicon.glyphicon-refresh
li.toolbar-settings
- a(ng-click='expandMenu("settings")')
+ a(data-expand-menu, menu="settings")
span.glyphicon.glyphicon-cog
- div(ng-if='_expandedMenu=="settings"')
+ div(ng-show='_expandedMenu=="settings"', data-close-menu)
h4=env.t('settings')
div
- ul.toolbar-submenu(ng-click='expandMenu(null)')
+ ul.toolbar-submenu
li
a(ng-click='logout()')=env.t('logout')
- ul.toolbar-submenu(ng-click='expandMenu(null)')
+ ul.toolbar-submenu
li
a(ui-sref='options.settings.settings')=env.t('site')
li
@@ -250,14 +250,14 @@ nav.toolbar(ng-controller='MenuCtrl')
a(ui-sref='options.settings.subscription')=env.t('subscription')
li
a(ui-sref='options.settings.notifications')=env.t('notifications')
- ul.toolbar-submenu(ng-click='expandMenu(null)')
+ ul.toolbar-submenu
li
a(href="http://habitica.wikia.com/wiki/FAQ", target='_blank')=env.t('FAQ')
li
a(href="https://vimeo.com/57654086", target='_blank')=env.t('tutorials')
ul.toolbar-controls
li.toolbar-controls-button
- a(ng-click='expandMenu(null)')=env.t('close')
+ a(data-close-menu)=env.t('close')
ul.toolbar-wallet
li.toolbar-gems(popover-trigger='mouseenter', popover-title=env.t('gemsPopoverTitle'), popover=env.t('gemsWhatFor'), popover-placement='bottom',popover-append-to-body='true')
a.gem-wallet(ng-click='openModal("buyGems",{track:"Gems > Toolbar"})')