Merge branch 'develop' of https://github.com/HabitRPG/habitrpg into createparty
@@ -1,8 +1,3 @@
|
||||
{
|
||||
"directory": "public/bower_components",
|
||||
"storage": {
|
||||
"packages": ".bower-cache",
|
||||
"registry": ".bower-registry"
|
||||
},
|
||||
"tmp": ".bower-tmp"
|
||||
"directory": "public/bower_components"
|
||||
}
|
||||
@@ -12,6 +12,8 @@ newrelic_agent.log
|
||||
.bower-tmp
|
||||
.bower-registry
|
||||
.bower-cache
|
||||
|
||||
*.log
|
||||
src/*/*.map
|
||||
src/*/*/*.map
|
||||
test/*.js
|
||||
|
||||
@@ -6,4 +6,6 @@ Gruntfile.js
|
||||
CHANGELOG.md
|
||||
.idea*
|
||||
.git*
|
||||
*.log
|
||||
newrelic_agent.log
|
||||
.bower-cache*
|
||||
|
||||
@@ -4,6 +4,8 @@ module.exports = function(grunt) {
|
||||
|
||||
// Project configuration.
|
||||
grunt.initConfig({
|
||||
pkg: grunt.file.readJSON('package.json'),
|
||||
|
||||
git_changelog: {
|
||||
minimal: {
|
||||
options: {
|
||||
@@ -56,7 +58,10 @@ 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/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/'}
|
||||
]
|
||||
}
|
||||
},
|
||||
@@ -69,16 +74,18 @@ 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/habitrpg-shared/img/sprites/backer-only/*.gif',
|
||||
'build/bower_components/habitrpg-shared/img/sprites/npc_ian.gif',
|
||||
'build/bower_components/bootstrap/dist/fonts/*'
|
||||
],
|
||||
dest: 'make-sure-i-do-not-exist'
|
||||
dest: 'build/*.css'
|
||||
}
|
||||
},
|
||||
|
||||
nodemon: {
|
||||
nodemon: {
|
||||
dev: {
|
||||
ignoredFiles: ['public/*', 'Gruntfile.js', 'CHANGELOG.md', 'views/*', 'build/*', '.idea*', '.git*']
|
||||
script: '<%= pkg.main %>'
|
||||
}
|
||||
},
|
||||
|
||||
@@ -106,27 +113,35 @@ 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.
|
||||
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' ]);
|
||||
|
||||
|
||||
@@ -14,20 +14,21 @@
|
||||
"tests"
|
||||
],
|
||||
"dependencies": {
|
||||
"jquery": "~2.0.3",
|
||||
"jquery": "~2.1.0",
|
||||
"jquery.cookie": "~1.4.0",
|
||||
"jquery-ui": "~1.10.3",
|
||||
"angular": "~1.2.1",
|
||||
"angular-sanitize": "~1.2.1",
|
||||
"angular-resource": "~1.2.1",
|
||||
"angular-ui": "~0.4.0",
|
||||
"angular-bootstrap": "~0.5.0",
|
||||
"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",
|
||||
"angular-ui-router": "ca3b4777a603df8f86cfd653c8f6c38b2ae05d89",
|
||||
"angular-loading-bar": "~0.0.5",
|
||||
"angular-loading-bar": "~0.3.0",
|
||||
"angular-bindonce": "~0.2.1",
|
||||
"bootstrap": "v2.3.2",
|
||||
"bootstrap-datepicker": "~1.2.0",
|
||||
"bootstrap-growl": "~1.1.0",
|
||||
"bootstrap": "~3.1.0",
|
||||
"bootstrap-growl": "git://github.com/ifightcrime/bootstrap-growl.git#master",
|
||||
"bootstrap-tour": "~0.8.1",
|
||||
"habitrpg-shared": "git://github.com/HabitRPG/habitrpg-shared.git#develop",
|
||||
"BrowserQuest": "https://github.com/mozilla/BrowserQuest.git",
|
||||
"github-buttons": "git://github.com/mdo/github-buttons.git",
|
||||
@@ -35,15 +36,12 @@
|
||||
"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": "*",
|
||||
"bootstrap-tour": "~0.8.0",
|
||||
"angular-ui-utils": "~0.1.0",
|
||||
"swagger-ui": "https://github.com/wordnik/swagger-ui.git#105c516f5f055b140e935e9cfe0c36f841921dff",
|
||||
"ngInfiniteScroll": "~1.0.0",
|
||||
"angular-ui-select2": "https://github.com/angular-ui/ui-select2.git#4469fd7a32eba2e28d5e3dd319b49e1ad090b167"
|
||||
"jquery-colorbox": "~1.4.36"
|
||||
},
|
||||
"devDependencies": {
|
||||
"angular-mocks": "~1.2.1"
|
||||
"angular-mocks": "~1.2.12"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,8 +11,12 @@
|
||||
"SMTP_USER":"user@domain.com",
|
||||
"SMTP_PASS":"password",
|
||||
"SMTP_SERVICE":"Gmail",
|
||||
"SMTP_HOST":"smtp.gmail.com",
|
||||
"SMTP_PORT": 587,
|
||||
"SMTP_TLS": true,
|
||||
"STRIPE_API_KEY":"aaaabbbbccccddddeeeeffff00001111",
|
||||
"STRIPE_PUB_KEY":"22223333444455556666777788889999",
|
||||
"PAYPAL_MERCHANT":"paypal-merchant@gmail.com",
|
||||
"NEW_RELIC_LICENSE_KEY":"NEW_RELIC_LICENSE_KEY"
|
||||
"NEW_RELIC_LICENSE_KEY":"NEW_RELIC_LICENSE_KEY",
|
||||
"GA_ID": "GA_ID"
|
||||
}
|
||||
|
||||
@@ -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}
|
||||
|
||||
)
|
||||
@@ -1 +1 @@
|
||||
db.users.update({_id:''},{$set:{'purchased.ads':true},$inc:{balance:5}});
|
||||
db.users.update({_id:''},{$inc:{balance:5}});
|
||||
@@ -40,12 +40,16 @@
|
||||
"pretty-data": "git://github.com/vkiryukhin/pretty-data#master",
|
||||
"js2xmlparser": "~0.1.2",
|
||||
"mongoose": "~3.8.1",
|
||||
"domain-middleware": "~0.1.0",
|
||||
"swagger-node-express": "git://github.com/lefnire/swagger-node-express#habitrpg",
|
||||
"passport": "~0.1.18",
|
||||
"passport-facebook": "~1.0.2",
|
||||
"newrelic": "~1.3.0",
|
||||
"connect-ratelimit": "0.0.6"
|
||||
"connect-ratelimit": "0.0.6",
|
||||
"winston": "~0.7.2",
|
||||
"winston-mail": "~0.2.7",
|
||||
"winston-newrelic": "~0.1.4",
|
||||
"domain-middleware": "~0.1.0",
|
||||
"universal-analytics": "~0.3.2"
|
||||
},
|
||||
"private": true,
|
||||
"subdomain": "habitrpg",
|
||||
|
||||
@@ -16,6 +16,27 @@
|
||||
.wide-popover
|
||||
max-width: 400px
|
||||
|
||||
// Small alerts
|
||||
alert-sm-mixin()
|
||||
padding-top: 8px
|
||||
padding-bottom: 8px
|
||||
|
||||
.alert-sm
|
||||
alert-sm-mixin()
|
||||
|
||||
#notification-area
|
||||
position: fixed
|
||||
top: 0
|
||||
right: 0px
|
||||
z-index: 1061
|
||||
|
||||
.alert
|
||||
alert-sm-mixin()
|
||||
|
||||
.notification-icon
|
||||
transform: scale(0.8)
|
||||
|
||||
|
||||
// variables
|
||||
|
||||
gpColor = #FBEFC0
|
||||
@@ -78,30 +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
|
||||
|
||||
.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
|
||||
|
||||
.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
|
||||
|
||||
|
||||
.undo-button
|
||||
z-index: 3000
|
||||
position:absolute
|
||||
|
||||
@@ -9,6 +9,16 @@ Seeing as the sprites might change drastically in the
|
||||
future re: pets and whatnot, this is just temporary.
|
||||
---------------------------------------------------- */
|
||||
|
||||
.profile-modal-header
|
||||
width:560px
|
||||
margin: 0px auto
|
||||
|
||||
.avatar-level
|
||||
position absolute
|
||||
bottom 0px
|
||||
right 0px
|
||||
padding 2px 3px 2px 3px
|
||||
|
||||
// basic herobox styles
|
||||
.herobox
|
||||
height: 10.5em // higher to acct for the name area
|
||||
@@ -40,7 +50,7 @@ future re: pets and whatnot, this is just temporary.
|
||||
// always visible on the user's own avatar
|
||||
.herobox:after
|
||||
opacity: 0
|
||||
.herobox.isUser:after
|
||||
.herobox.isUser:not(.hasMount):after
|
||||
opacity: 1
|
||||
// make it a bit special
|
||||
background darken($better, 15%)
|
||||
@@ -52,21 +62,17 @@ future re: pets and whatnot, this is just temporary.
|
||||
.active
|
||||
border 1px solid black
|
||||
|
||||
// vertically center avatar sprite
|
||||
// depending on if they have a pet
|
||||
.herobox.hasPet
|
||||
padding-top: 2em
|
||||
.herobox:not(.hasPet)
|
||||
padding-top: 1.75em
|
||||
|
||||
// if it is the user's avatar, check if
|
||||
// they have a pet and pad accordingly
|
||||
.herobox.hasPet.isUser
|
||||
padding-top: 3.25em
|
||||
|
||||
// if not user's avatar, remove lines for party unity
|
||||
.herobox:not(.isUser)
|
||||
outline: 0
|
||||
outline: 0
|
||||
|
||||
// vertically center avatar sprite depending on if they have a pet
|
||||
.herobox.hasPet
|
||||
padding-top: 1.75em
|
||||
.herobox:not(.hasPet)
|
||||
padding-top: 2em
|
||||
.herobox.hasMount
|
||||
padding-top:0em
|
||||
|
||||
// expose hero info on hover, taking
|
||||
// into account the extra pet space
|
||||
@@ -74,13 +80,6 @@ future re: pets and whatnot, this is just temporary.
|
||||
background: desaturate(lighten($better, 30%), 10%)
|
||||
&:after
|
||||
opacity: 1
|
||||
/* .herobox.hasPet
|
||||
&:hover, &:focus
|
||||
padding-top: 3.25em
|
||||
.herobox:not(.hasPet)
|
||||
&:hover, &:focus
|
||||
padding-top: 2.5em */
|
||||
|
||||
|
||||
// positioning the sprites, etc
|
||||
.herobox
|
||||
@@ -93,4 +92,4 @@ future re: pets and whatnot, this is just temporary.
|
||||
position: absolute
|
||||
|
||||
.herobox.isLeader
|
||||
background: $better
|
||||
background: $better
|
||||
@@ -10,12 +10,4 @@ ul.challenge-accordion-header-specs
|
||||
margin-bottom: 10px
|
||||
|
||||
#challenges-filters h3
|
||||
margin-top: 0px;
|
||||
|
||||
// for things like challenges, member profiles, etc
|
||||
@media (min-width: 767px)
|
||||
.wide-modal
|
||||
/* new custom width */
|
||||
width: 1020px;
|
||||
/* must be half of the width, minus scrollbar on the left (30px) */
|
||||
margin-left: -480px;
|
||||
margin-top: 0px;
|
||||
@@ -22,15 +22,18 @@ menu
|
||||
line-height: 2
|
||||
|
||||
.customize-option
|
||||
border: 0px solid grey;
|
||||
background-color: hsl(0, 0%, 93%);
|
||||
border: 0px solid grey
|
||||
background-color: hsl(0, 0%, 93%)
|
||||
margin-bottom: 10px
|
||||
|
||||
cursor: pointer;
|
||||
-webkit-transition: background-color 0.5s ease-out
|
||||
-moz-transition: background-color 0.5s ease-out
|
||||
transition: background-color 0.5s ease-out
|
||||
|
||||
&.hair
|
||||
width: 40px !important
|
||||
height: 40px !important
|
||||
|
||||
.customize-option:active
|
||||
background-color: rgb(255, 242, 204);
|
||||
-webkit-transition: none
|
||||
|
||||
@@ -1,36 +1,25 @@
|
||||
/* Filters */
|
||||
.filters
|
||||
padding-left: 19px
|
||||
padding-right: 19px
|
||||
|
||||
.filters .nav
|
||||
margin-bottom: 0
|
||||
|
||||
.filter-description
|
||||
margin-top: 7px
|
||||
margin-right: 7px
|
||||
|
||||
/* Filters applied to tasks */
|
||||
.task.filtered-out
|
||||
display: none
|
||||
|
||||
.tag-label:hover
|
||||
background-color: #3a87ad
|
||||
cursor: pointer
|
||||
|
||||
.tag-editing
|
||||
padding 2px 0 0 2px
|
||||
|
||||
.tag-editing .tag-editing-pill
|
||||
height:auto
|
||||
margin-top: 5px
|
||||
margin-bottom: 5px
|
||||
|
||||
.tag-list
|
||||
overflow-y: auto
|
||||
white-space: nowrap
|
||||
|
||||
.nav-pills
|
||||
height: 43px
|
||||
|
||||
li
|
||||
display: inline-block
|
||||
float: none
|
||||
.filter-description
|
||||
margin-top: 7px
|
||||
margin-right: 7px
|
||||
padding-left: 7px
|
||||
|
||||
markdown
|
||||
display: inline-block
|
||||
|
||||
.glyphicon-bullhorn
|
||||
margin-right: 5px
|
||||
|
||||
.input-group
|
||||
float: left
|
||||
width: 1px // Trick for proper alignment
|
||||
margin-left: 3px
|
||||
margin-right: 3px
|
||||
margin-top: 5px
|
||||
|
||||
.form-control
|
||||
width: auto
|
||||
@@ -1,83 +1,9 @@
|
||||
/* Sticky footer styles
|
||||
-------------------------------------------------- */
|
||||
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
/* The html and body elements cannot have any padding or margin. */
|
||||
}
|
||||
|
||||
/* Wrapper for page content to push down footer */
|
||||
#wrap {
|
||||
min-height: 100%;
|
||||
height: auto !important;
|
||||
height: 100%;
|
||||
/* Negative indent footer by it's height */
|
||||
margin: 0 auto -60px;
|
||||
}
|
||||
|
||||
/* Set the fixed height of the footer here */
|
||||
#push,
|
||||
#footer {
|
||||
height: 60px;
|
||||
}
|
||||
#footer {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
/* Lastly, apply responsive CSS fixes as necessary */
|
||||
@media (max-width: 767px) {
|
||||
#footer {
|
||||
margin-left: -20px;
|
||||
margin-right: -20px;
|
||||
padding-left: 20px;
|
||||
padding-right: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Custom page CSS
|
||||
-------------------------------------------------- */
|
||||
/* Not required for template or sticky footer method. */
|
||||
|
||||
#wrap > .container {
|
||||
padding-top: 60px;
|
||||
}
|
||||
.container .credit {
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
code {
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* HabitRPG Custom CSS
|
||||
-------------------------------------------------- */
|
||||
|
||||
.footer {
|
||||
/*padding: 70px 0;*/
|
||||
border-top: 1px solid #e5e5e5;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.footer li {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.footer h4 {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.footer td {
|
||||
align: left !important;
|
||||
}
|
||||
|
||||
.frontpage-play-button
|
||||
//box-shadow: 0 0 40px #494141;
|
||||
display:inline
|
||||
font-size: 20px
|
||||
width:100px
|
||||
height:50px
|
||||
.footer
|
||||
padding-top: 20px
|
||||
margin-top: 40px
|
||||
padding-bottom: 20px
|
||||
border-top: 1px solid #e5e5e5
|
||||
background-color: #f5f5f5
|
||||
@@ -1,6 +1,3 @@
|
||||
.full-width
|
||||
width 100%
|
||||
|
||||
.border-right
|
||||
border-right 1px solid #ddd
|
||||
|
||||
@@ -8,21 +5,27 @@
|
||||
color #fff
|
||||
background-color #51a351
|
||||
|
||||
.tavern-pane
|
||||
position relative
|
||||
height 250px
|
||||
|
||||
.chat-form
|
||||
position: relative
|
||||
z-index: 10
|
||||
margin-bottom: 10px
|
||||
|
||||
.chat-message .chat-plus-one
|
||||
opacity: 0
|
||||
.chat-message:hover .chat-plus-one
|
||||
opacity: 1
|
||||
textarea
|
||||
margin-bottom: 5px
|
||||
|
||||
.chat-message
|
||||
markdown, span.time
|
||||
padding: 0 3px
|
||||
|
||||
.chat-plus-one
|
||||
opacity: 0
|
||||
background-color: #eee
|
||||
padding: 3px 3px 0px 3px
|
||||
|
||||
&:hover .chat-plus-one
|
||||
opacity: 1
|
||||
color: #999
|
||||
|
||||
.tavern-chat, .party-chat
|
||||
|
||||
|
||||
li
|
||||
padding-top:15px
|
||||
padding-bottom:15px
|
||||
@@ -78,6 +81,11 @@
|
||||
padding-top:0px
|
||||
padding-bottom:0px
|
||||
|
||||
.panel-tiers
|
||||
div
|
||||
display: none
|
||||
margin-top: 10px
|
||||
|
||||
// Name tags
|
||||
.label-contributor-1, .label-contributor-2
|
||||
background-color: #333;
|
||||
@@ -108,33 +116,33 @@
|
||||
padding: 0px 5px
|
||||
|
||||
// Autocomplete [TODO] make this nicer
|
||||
.list-at-user {
|
||||
width: 100%;
|
||||
max-width: 120px;
|
||||
position: absolute;
|
||||
background: white;
|
||||
border: 1px solid #a4a4a4;
|
||||
z-index: 10;
|
||||
}
|
||||
.list-at-user
|
||||
width: 100%
|
||||
max-width: 120px
|
||||
position: absolute
|
||||
background: white
|
||||
border: 1px solid #a4a4a4
|
||||
z-index: 10
|
||||
|
||||
.list-at-user li {
|
||||
line-height:14px;
|
||||
border-bottom: 1px solid #a4a4a4;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
.list-at-user li:hover {
|
||||
cursor: pointer;
|
||||
background: #b9dff4;
|
||||
}
|
||||
.list-at-user li
|
||||
line-height:14px
|
||||
border-bottom: 1px solid #a4a4a4
|
||||
list-style-type: none
|
||||
|
||||
.list-at-user li span {
|
||||
margin: 2px;
|
||||
font-size: 11.844px;
|
||||
margin-left: 5px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.list-cur {
|
||||
background: #b9dff4;
|
||||
}
|
||||
.list-at-user li:hover
|
||||
cursor: pointer
|
||||
background: #b9dff4
|
||||
|
||||
|
||||
.list-at-user li span
|
||||
margin: 2px
|
||||
font-size: 11.844px
|
||||
margin-left: 5px
|
||||
display: inline-block
|
||||
|
||||
|
||||
.list-cur
|
||||
background: #b9dff4
|
||||
|
||||
|
||||
@@ -3,9 +3,6 @@
|
||||
|
||||
// Vendor Includes - include first so we can override
|
||||
// Import only styles that do not have urls to images! Include them directly in the page!
|
||||
@import "../bower_components/bootstrap-datepicker/css/datepicker.css"
|
||||
@import "../bower_components/angular-ui/build/angular-ui.min.css"
|
||||
@import "../bower_components/bootstrap/docs/assets/css/bootstrap-responsive.css"
|
||||
@import "../bower_components/bootstrap-tour/build/css/bootstrap-tour.min.css"
|
||||
@import "../bower_components/angular-loading-bar/build/loading-bar.css"
|
||||
@import "../bower_components/js-emoji/emoji.css"
|
||||
@@ -19,7 +16,6 @@
|
||||
@import "./inventory.styl"
|
||||
@import "./alerts.styl"
|
||||
@import "./helpers.styl"
|
||||
@import "./responsive.styl"
|
||||
@import "./header.styl"
|
||||
@import "./filters.styl"
|
||||
@import "./scrollbars.styl"
|
||||
@@ -29,10 +25,7 @@
|
||||
@import "./classes.styl"
|
||||
@import "./quests.styl"
|
||||
@import "./shared.styl"
|
||||
|
||||
// fix exploding to very wide for some reason
|
||||
.datepicker
|
||||
width: 210px
|
||||
@import "./footer.styl"
|
||||
|
||||
html,body,p,h1,ul,li,table,tr,th,td
|
||||
margin: 0
|
||||
@@ -42,54 +35,27 @@ html,body,p,h1,ul,li,table,tr,th,td
|
||||
-webkit-box-sizing: border-box
|
||||
-moz-box-sizing: border-box
|
||||
box-sizing: border-box
|
||||
|
||||
* { font-family: "Lato", sans-serif }
|
||||
font-family: "Lato", sans-serif
|
||||
|
||||
hr
|
||||
border-top: 0
|
||||
border-bottom: 1px solid #ddd
|
||||
border-color: rgba(0,0,0,0.1)
|
||||
|
||||
|
||||
/* Footer
|
||||
-------------------------------------------------- */
|
||||
|
||||
/* Bootstrap website boilerplate */
|
||||
.footer {
|
||||
padding: 70px 0;
|
||||
border-top: 1px solid #e5e5e5;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
.footer p {
|
||||
margin-bottom: 0;
|
||||
color: #777;
|
||||
}
|
||||
.footer-links {
|
||||
margin: 10px 0;
|
||||
}
|
||||
.footer-links li {
|
||||
display: inline;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
/* Bootstrap overrides */
|
||||
div.tooltip-inner {
|
||||
max-width: 300px;
|
||||
}
|
||||
|
||||
/* Customizations to make footer sticky */
|
||||
/*html, body {height: 100%;}*/
|
||||
#wrap
|
||||
min-height: 100%
|
||||
z-index:-1
|
||||
#main
|
||||
padding-bottom: 250px; /* don't know why this works, sticky footers are weird */
|
||||
|
||||
@media (max-width: 600px) {
|
||||
#wrap {
|
||||
html, body
|
||||
height: 100%
|
||||
|
||||
#wrap
|
||||
z-index:-1
|
||||
padding: 0 15px // Required by Bootstrap 3 when using .container-fluid
|
||||
min-height: 100%
|
||||
height: auto !important
|
||||
|
||||
@media (max-width: 600px)
|
||||
#wrap
|
||||
margin-top: 0
|
||||
}
|
||||
}
|
||||
|
||||
/* Gems
|
||||
-------------------------------------------------- */
|
||||
@@ -108,17 +74,17 @@ div.tooltip-inner {
|
||||
position: relative;
|
||||
|
||||
.gem-cost::before
|
||||
content: "";
|
||||
display: block;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border: 6px solid #D4D4D4;
|
||||
border-color: transparent #D4D4D4 transparent transparent;
|
||||
position: absolute;
|
||||
right: 100%;
|
||||
margin-right: 0;
|
||||
top: 50%;
|
||||
margin-top: -6px;
|
||||
content: ""
|
||||
display: block
|
||||
width: 0
|
||||
height: 0
|
||||
border: 6px solid #D4D4D4
|
||||
border-color: transparent #D4D4D4 transparent transparent
|
||||
position: absolute
|
||||
right: 100%
|
||||
margin-right: 0
|
||||
top: 50%
|
||||
margin-top: -6px
|
||||
|
||||
.gem-cost::after
|
||||
content: "";
|
||||
@@ -135,68 +101,81 @@ div.tooltip-inner {
|
||||
|
||||
/* Misc
|
||||
-------------------------------------------------- */
|
||||
//move
|
||||
|
||||
.modal
|
||||
whitespace: normal
|
||||
.new-stuff-modal // a .modal-body
|
||||
h5
|
||||
font-weight: 700
|
||||
|
||||
.notification-character
|
||||
float:left
|
||||
.modal-fixed-height
|
||||
overflow-y: auto
|
||||
max-height: 400px // Taken from Bootstrap 2.3.2 css, may need to change
|
||||
|
||||
.notification-message
|
||||
display: inline-block;
|
||||
padding-right: 1em
|
||||
line-height: 3
|
||||
|
||||
.notification-action
|
||||
vertical-align: baseline
|
||||
#reset-modal
|
||||
z-index:1500
|
||||
#notification-area
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0px;
|
||||
z-index: 1061;
|
||||
// notification-character used only by death modal's figure, move
|
||||
|
||||
.modal-body
|
||||
margin: 10px
|
||||
figure
|
||||
float: left
|
||||
padding: 15px
|
||||
|
||||
|
||||
// TODO this is supposed to go in avatar.styl, but stylus is breaking if I even touch that file
|
||||
.profile-modal-header
|
||||
width:560px
|
||||
margin: 0px auto
|
||||
|
||||
.avatar-level
|
||||
position absolute
|
||||
bottom 0px
|
||||
right 0px
|
||||
padding 1px 3px 1px 3px
|
||||
.death-modal // a .modal-body
|
||||
margin: 10px
|
||||
|
||||
a
|
||||
cursor: pointer
|
||||
|
||||
#modalMember p
|
||||
word-wrap: break-word
|
||||
a span.glyphicon
|
||||
color: #333 // Takes base color from bootstrap
|
||||
|
||||
a.label
|
||||
color: #fff
|
||||
|
||||
.label .glyphicon
|
||||
color: #fff
|
||||
|
||||
.muted
|
||||
color: #999
|
||||
|
||||
.btn
|
||||
margin-right: 5px
|
||||
|
||||
.vertical-align
|
||||
vertical-align: middle
|
||||
.inline-block
|
||||
display: inline-block
|
||||
|
||||
// Buttons in groups should not have a 5px margin between them; suppress margin for buttons in groups.
|
||||
.btn-group .btn
|
||||
margin-right: 0px
|
||||
|
||||
.modal-indented-list
|
||||
margin-left: 10px;
|
||||
padding-left: 10px;
|
||||
|
||||
.inline-modal
|
||||
position: relative
|
||||
top: auto;
|
||||
left: auto
|
||||
right: auto
|
||||
margin: 0 auto 20px
|
||||
z-index: 1
|
||||
max-width: 100%
|
||||
|
||||
.buy-gems
|
||||
.nav-tabs
|
||||
margin-top: 0.5em
|
||||
.gem-wallet
|
||||
padding-top: 2px
|
||||
|
||||
// Add badges' classes
|
||||
.badge-info
|
||||
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
|
||||
|
||||
@@ -15,29 +15,12 @@
|
||||
.modal-header .gem-wallet
|
||||
padding-top: 0px
|
||||
|
||||
.equipment-title
|
||||
display: inline-block
|
||||
vertical-align: middle
|
||||
|
||||
// pets (this will all change when pet system is overhauled)
|
||||
.pet-grid
|
||||
padding-top: 1.5em
|
||||
border-top: rgba(0,0,0,0.1)
|
||||
table
|
||||
width: 100%
|
||||
td
|
||||
padding: 0.5em
|
||||
//width: 25%
|
||||
&.active-pet
|
||||
background-color: $bad
|
||||
outline: 1px solid rgba(0,0,0,0.1)
|
||||
outline-offset: -1px
|
||||
&:hover, &:focus
|
||||
background-color: darken($better, 10%)
|
||||
> div
|
||||
margin:auto
|
||||
margin-bottom:.5em
|
||||
p
|
||||
text-align:center
|
||||
width:6.5em
|
||||
height:2.5em
|
||||
.stable .static-popover
|
||||
max-width: 550px
|
||||
|
||||
menu.pets div
|
||||
display: inline-block
|
||||
@@ -57,12 +40,13 @@ menu.pets div
|
||||
// display:block
|
||||
|
||||
.food-tray
|
||||
position:fixed
|
||||
right:0px
|
||||
bottom:0px
|
||||
width:30%
|
||||
position: fixed
|
||||
right: 15px
|
||||
bottom: 0px
|
||||
width: 30%
|
||||
height: 50%
|
||||
overflow-y: scroll
|
||||
overflow-y: auto
|
||||
z-index: 1
|
||||
|
||||
.inventory-list
|
||||
p
|
||||
|
||||
@@ -4,15 +4,15 @@
|
||||
.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
|
||||
height:45px !important
|
||||
cursor: pointer
|
||||
|
||||
// Tour (Justin)
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
// widths
|
||||
.full
|
||||
width: 100%;
|
||||
.half
|
||||
width: 50%;
|
||||
.third
|
||||
width: 33.3333%;
|
||||
.two-thirds
|
||||
width: 66.6666%;
|
||||
.quarter
|
||||
width: 25%;
|
||||
.three-quarters
|
||||
width: 75%;
|
||||
.fifth
|
||||
width: 20%;
|
||||
.two-fifths
|
||||
width: 40%;
|
||||
.three-fifths
|
||||
width: 60%;
|
||||
.four-fifths
|
||||
width: 80%;
|
||||
.sixth
|
||||
width: 16.6667%;
|
||||
.eighth
|
||||
width: 12.5%;
|
||||
.tenth
|
||||
width: 10%;
|
||||
.twelfth
|
||||
width: 8.3333%;
|
||||
|
||||
.grid
|
||||
padding: 0 1.5em 1.5em 0
|
||||
letter-spacing: -4px
|
||||
|
||||
.module
|
||||
display: inline-block
|
||||
letter-spacing: normal
|
||||
vertical-align: top
|
||||
width: 25%
|
||||
padding: 0 0 1.5em 1.5em
|
||||
-moz-box-sizing: border-box
|
||||
box-sizing: border-box
|
||||
|
||||
// at 960px when 4 columns really starts to break
|
||||
@media (max-width: 60em)
|
||||
.module
|
||||
width: 50%
|
||||
.task-column
|
||||
max-height: 18em
|
||||
overflow-y: scroll
|
||||
|
||||
// at 600px when 2col starts breaking
|
||||
@media (max-width: 37.5em)
|
||||
.grid
|
||||
padding-right: 0
|
||||
.module
|
||||
width: 100%
|
||||
padding-left: 0
|
||||
.task-column
|
||||
max-height: none
|
||||
overflow: visible
|
||||
@@ -13,4 +13,14 @@
|
||||
.dashed-underline
|
||||
border-bottom:1px dashed #000
|
||||
text-decoration:none
|
||||
cursor pointer
|
||||
cursor pointer
|
||||
|
||||
// Required by angular-ui-bootstrap
|
||||
.nav, .pagination, .carousel, .panel-title a
|
||||
cursor: pointer
|
||||
|
||||
.nav-tabs
|
||||
margin-bottom: 15px
|
||||
|
||||
img
|
||||
max-width: 100%
|
||||
@@ -1,21 +0,0 @@
|
||||
.jumbotron {
|
||||
background-color: #1b1b1b;
|
||||
background-image: -moz-linear-gradient(top, #222222, #111111);
|
||||
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#222222), to(#111111));
|
||||
background-image: -webkit-linear-gradient(top, #222222, #111111);
|
||||
background-image: -o-linear-gradient(top, #222222, #111111);
|
||||
background-image: linear-gradient(to bottom, #222222, #111111);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #252525;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff111111', GradientType=0);
|
||||
background:none;
|
||||
color:black;
|
||||
|
||||
}
|
||||
body {
|
||||
padding-top:0px;
|
||||
}
|
||||
|
||||
a {
|
||||
cursor: pointer;
|
||||
}
|
||||
@@ -3,10 +3,38 @@
|
||||
// Vendor Includes - include first so we can override
|
||||
// Import only styles that do not have urls to images! Include them directly in the page!
|
||||
@import "../bower_components/angular-loading-bar/build/loading-bar.css"
|
||||
|
||||
@import "./static-pages.css"
|
||||
@import "./shared.styl"
|
||||
@import "./footer"
|
||||
|
||||
body
|
||||
margin-top: 60px
|
||||
|
||||
#aboutPage
|
||||
iframe
|
||||
margin-bottom: 20px
|
||||
|
||||
.muted i, i.muted
|
||||
opacity:0.5
|
||||
opacity:0.5
|
||||
|
||||
#header-play-button
|
||||
margin-right: 15px
|
||||
|
||||
#tagline
|
||||
margin:10px 0 20px 0
|
||||
font-size:40px
|
||||
|
||||
.marketing
|
||||
text-align: center
|
||||
|
||||
#frontpage-play-button
|
||||
//box-shadow: 0 0 40px #494141;
|
||||
display:inline
|
||||
font-size: 20px
|
||||
width:100px
|
||||
height:50px
|
||||
|
||||
#about-page
|
||||
img
|
||||
box-shadow 0px 0px 10px 5px #888
|
||||
margin 10px
|
||||
max-width 500px
|
||||
@@ -23,6 +23,8 @@ for $stage in $stages
|
||||
.completed
|
||||
background-color: $completed
|
||||
color: #999
|
||||
.glyphicon
|
||||
color: #333
|
||||
.task-checker label
|
||||
background-color: darken($completed, 30%)
|
||||
.task-action-btn
|
||||
@@ -31,11 +33,20 @@ for $stage in $stages
|
||||
.reward
|
||||
background-color: white
|
||||
|
||||
|
||||
|
||||
// 2. Columns & Tasks
|
||||
// ===================
|
||||
|
||||
.tasks-lists
|
||||
|
||||
.row
|
||||
margin-left: -5px
|
||||
margin-right: -5px
|
||||
|
||||
.col-md-3
|
||||
padding-left: 10px // Override Bootstrap 15px padding
|
||||
padding-right: 10px // Override Bootstrap 15px padding
|
||||
margin-bottom: 15px
|
||||
|
||||
// main columns
|
||||
// ------------
|
||||
.task-column
|
||||
@@ -47,7 +58,13 @@ for $stage in $stages
|
||||
.task-column_title
|
||||
margin: 0 0 0.5em
|
||||
padding: 0
|
||||
font-weight: 300
|
||||
|
||||
// 50% width columns with scrollbars for tablets
|
||||
@media (min-width: 768px) and (max-width: 970px)
|
||||
.task-column
|
||||
max-height: 18.6em
|
||||
overflow-y: scroll
|
||||
|
||||
// add new task form
|
||||
// -----------------
|
||||
@@ -112,6 +129,9 @@ for $stage in $stages
|
||||
&:last-child
|
||||
margin-bottom: 0
|
||||
|
||||
label
|
||||
font-weight: 400
|
||||
|
||||
// task content
|
||||
.task-text
|
||||
display: block
|
||||
@@ -124,19 +144,14 @@ for $stage in $stages
|
||||
height:1.5em
|
||||
background-size:1.5em
|
||||
|
||||
// task due date (for to-dos)
|
||||
.task-date
|
||||
font-size: 70%
|
||||
|
||||
.habit-wide .task-text
|
||||
padding-left: 7em
|
||||
|
||||
// when a task is being dragged
|
||||
.task.ui-sortable-helper {
|
||||
.task.ui-sortable-helper
|
||||
box-shadow: 0 0 3px rgba(0,0,0,0.15), 0 0 5px rgba(0,0,0,0.1)
|
||||
transform: scale(1.05)
|
||||
outline: 1px solid rgba(0,0,0,0.2)
|
||||
}
|
||||
|
||||
// primary task commands
|
||||
// ----------------------
|
||||
@@ -270,13 +285,23 @@ for $stage in $stages
|
||||
// -----------------------
|
||||
.task-meta-controls
|
||||
float: right
|
||||
margin: 0.75em 0.5em 0 0.25em
|
||||
margin: 0.75em 0.5em 0 0.5em
|
||||
height: 1em
|
||||
opacity: 0.25
|
||||
a > i
|
||||
margin-left: 0.125em
|
||||
.task-notes
|
||||
margin-left: 0.125em
|
||||
|
||||
a
|
||||
text-decoration: none
|
||||
|
||||
// improve alignment of task icons
|
||||
.glyphicon-signal
|
||||
margin-left: 0.25em
|
||||
.glyphicon-remove, .glyphicon-ok, a.badge
|
||||
margin-right: 0.25em
|
||||
.glyphicon-tags
|
||||
margin-left: 0.1em
|
||||
margin-right: 0.4em
|
||||
a.badge
|
||||
position: relative; top:-2px
|
||||
|
||||
.task:hover .task-meta-controls
|
||||
opacity: 1
|
||||
@@ -296,7 +321,6 @@ form
|
||||
[class$="-options"]
|
||||
padding: 1em 1em 0
|
||||
color: #333
|
||||
z-index: 0
|
||||
position: relative
|
||||
//background-color:
|
||||
|
||||
@@ -360,6 +384,9 @@ form
|
||||
text-align: center
|
||||
margin: 0
|
||||
|
||||
&.task-attributes
|
||||
text-align: left
|
||||
|
||||
.task-action-btn.tile
|
||||
border: 0
|
||||
font-size: 1.15em
|
||||
@@ -393,6 +420,9 @@ form
|
||||
&:first-child
|
||||
border-right: 0
|
||||
|
||||
.task-options
|
||||
.task-action-btn.tile
|
||||
margin: 3px
|
||||
|
||||
// todos ui
|
||||
// --------
|
||||
|
||||
@@ -1,23 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
window.env = window.env || {}; //FIX tests
|
||||
|
||||
if(window.env.language && window.env.language.momentLang && window.env.language.momentLangCode){
|
||||
var head = document.getElementsByTagName('head')[0];
|
||||
var script = document.createElement('script');
|
||||
script.type = 'text/javascript';
|
||||
script.text = window.env.language.momentLang;
|
||||
head.appendChild(script);
|
||||
moment.lang(window.env.language.momentLangCode);
|
||||
}
|
||||
|
||||
window.env.t = function(stringName, vars){
|
||||
var string = window.env.translations[stringName];
|
||||
if(!string) return window._.template(window.env.translations.stringNotFound, {string: stringName});
|
||||
|
||||
return vars === undefined ? string : window._.template(string, vars);
|
||||
}
|
||||
|
||||
window.habitrpg = angular.module('habitrpg',
|
||||
['ngResource', 'ngSanitize', 'userServices', 'groupServices', 'memberServices', 'challengeServices',
|
||||
'authServices', 'notificationServices', 'guideServices', 'authCtrl',
|
||||
@@ -132,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);
|
||||
});
|
||||
}]
|
||||
})
|
||||
|
||||
@@ -218,24 +204,40 @@ window.habitrpg = angular.module('habitrpg',
|
||||
}
|
||||
|
||||
// Handle errors
|
||||
var interceptor = ['$rootScope', '$q', function ($rootScope, $q) {
|
||||
$httpProvider.responseInterceptors.push(['$rootScope', '$q', function ($rootScope, $q) {
|
||||
function success(response) {
|
||||
return response;
|
||||
}
|
||||
function error(response) {
|
||||
//var status = response.status;
|
||||
response.data = (response.data.err) ? response.data.err : response.data;
|
||||
if (response.status == 0) response.data = 'Server currently unreachable.';
|
||||
if (response.status == 500) response.data += ' (see Chrome console for more details).';
|
||||
debugger;
|
||||
// Offline
|
||||
if (response.status == 0 ||
|
||||
// don't know why we're getting 404 here, should be 0
|
||||
(response.status == 404 && _.isEmpty(response.data))) {
|
||||
$rootScope.$broadcast('responseText', window.env.t('serverUnreach'));
|
||||
|
||||
var error = response.status == 0 ? response.data : ('Error ' + response.status + ': ' + response.data);
|
||||
$rootScope.$broadcast('responseError', error);
|
||||
console.log(arguments);
|
||||
return $q.reject(response);
|
||||
// Needs refresh
|
||||
} else if (response.needRefresh) {
|
||||
$rootScope.$broadcast('responseError', "The site has been updated and the page needs to refresh. The last action has not been recorded, please refresh and try again.");
|
||||
|
||||
// 400 range?
|
||||
} else if (response < 500) {
|
||||
$rootScope.$broadcast('responseText', response.data.err || response.data);
|
||||
|
||||
// Error
|
||||
} else {
|
||||
var error = '<strong>Please reload</strong>, ' +
|
||||
'"'+window.env.t('error')+' '+(response.data.err || response.data || 'something went wrong')+'" ' +
|
||||
window.env.t('seeConsole');
|
||||
$rootScope.$broadcast('responseError', error);
|
||||
console.error(response);
|
||||
}
|
||||
|
||||
//return $q.reject(response); // this completely halts the chain, meaning we can't queue offline actions
|
||||
return response;
|
||||
}
|
||||
return function (promise) {
|
||||
return promise.then(success, error);
|
||||
}
|
||||
}];
|
||||
$httpProvider.responseInterceptors.push(interceptor);
|
||||
}]);
|
||||
}])
|
||||
|
||||
@@ -5,15 +5,15 @@
|
||||
*/
|
||||
|
||||
angular.module('authCtrl', [])
|
||||
.controller("AuthCtrl", ['$scope', '$rootScope', 'User', '$http', '$location', '$window','API_URL',
|
||||
function($scope, $rootScope, User, $http, $location, $window, API_URL) {
|
||||
.controller("AuthCtrl", ['$scope', '$rootScope', 'User', '$http', '$location', '$window','API_URL', '$modal',
|
||||
function($scope, $rootScope, User, $http, $location, $window, API_URL, $modal) {
|
||||
var runAuth;
|
||||
var showedFacebookMessage;
|
||||
|
||||
$scope.useUUID = false;
|
||||
$scope.toggleUUID = function() {
|
||||
if (showedFacebookMessage === false) {
|
||||
alert("Until we add Facebook, use your UUID and API Token to log in (found at https://habitrpg.com > Options > Settings).");
|
||||
alert(window.env.t('untilNoFace'));
|
||||
showedFacebookMessage = true;
|
||||
}
|
||||
$scope.useUUID = !$scope.useUUID;
|
||||
@@ -27,10 +27,19 @@ angular.module('authCtrl', [])
|
||||
runAuth = function(id, token) {
|
||||
User.authenticate(id, token, function(err) {
|
||||
$window.location.href = '/';
|
||||
//$rootScope.modals.login = false;
|
||||
});
|
||||
};
|
||||
|
||||
function errorAlert(data, status, headers, config) {
|
||||
if (status === 0) {
|
||||
$window.alert(window.env.t('noReachServer'));
|
||||
} else if (!!data && !!data.err) {
|
||||
$window.alert(data.err);
|
||||
} else {
|
||||
$window.alert(window.env.t('errorUpCase') + ' ' + status);
|
||||
}
|
||||
};
|
||||
|
||||
$scope.register = function() {
|
||||
/*TODO highlight invalid inputs
|
||||
we have this as a workaround for https://github.com/HabitRPG/habitrpg-mobile/issues/64
|
||||
@@ -40,27 +49,9 @@ angular.module('authCtrl', [])
|
||||
}
|
||||
$http.post(API_URL + "/api/v2/register", $scope.registerVals).success(function(data, status, headers, config) {
|
||||
runAuth(data.id, data.apiToken);
|
||||
}).error(function(data, status, headers, config) {
|
||||
if (status === 0) {
|
||||
$window.alert("Server not currently reachable, try again later");
|
||||
} else if (!!data && !!data.err) {
|
||||
$window.alert(data.err);
|
||||
} else {
|
||||
$window.alert("ERROR: " + status);
|
||||
}
|
||||
});
|
||||
}).error(errorAlert);
|
||||
};
|
||||
|
||||
function errorAlert(data, status, headers, config) {
|
||||
if (status === 0) {
|
||||
$window.alert("Server not currently reachable, try again later");
|
||||
} else if (!!data && !!data.err) {
|
||||
$window.alert(data.err);
|
||||
} else {
|
||||
$window.alert("ERROR: " + status);
|
||||
}
|
||||
}
|
||||
|
||||
$scope.auth = function() {
|
||||
var data = {
|
||||
username: $scope.loginUsername || $('#login-tab input[name="username"]').val(),
|
||||
@@ -77,17 +68,21 @@ angular.module('authCtrl', [])
|
||||
};
|
||||
|
||||
$scope.playButtonClick = function(){
|
||||
window.ga && ga('send', 'event', 'button', 'click', 'Play');
|
||||
if (User.authenticated()) {
|
||||
window.location.href = '/#/tasks';
|
||||
} else {
|
||||
$('#login-modal').modal('show');
|
||||
$modal.open({
|
||||
templateUrl: 'modals/login.html'
|
||||
// Using controller: 'AuthCtrl' it causes problems
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
$scope.passwordReset = function(email){
|
||||
$http.post(API_URL + '/api/v2/user/reset-password', {email:email})
|
||||
.success(function(){
|
||||
alert('New password sent.');
|
||||
alert(window.env.t('newPassSent'));
|
||||
})
|
||||
.error(function(data){
|
||||
alert(data.err);
|
||||
|
||||
@@ -44,11 +44,11 @@ habitrpg.controller("ChallengesCtrl", ['$rootScope','$scope', 'Shared', 'User',
|
||||
* Save
|
||||
*/
|
||||
$scope.save = function(challenge) {
|
||||
if (!challenge.group) return alert('Please select group');
|
||||
if (!challenge.group) return alert(window.env.t('selectGroup'));
|
||||
var isNew = !challenge._id;
|
||||
challenge.$save(function(_challenge){
|
||||
if (isNew) {
|
||||
Notification.text('Challenge Created');
|
||||
Notification.text(window.env.t('challengeCreated'));
|
||||
$state.go('options.social.challenges.detail', {cid: _challenge._id});
|
||||
$scope.discard();
|
||||
$scope.challenges = Challenges.Challenge.query();
|
||||
@@ -85,14 +85,14 @@ habitrpg.controller("ChallengesCtrl", ['$rootScope','$scope', 'Shared', 'User',
|
||||
$scope.closingChal = undefined;
|
||||
}
|
||||
$scope["delete"] = function(challenge) {
|
||||
if (!confirm("Delete challenge, are you sure?")) return;
|
||||
if (!confirm(window.env.t('sureDelCha'))) return;
|
||||
challenge.$delete(function(){
|
||||
$scope.popoverEl.popover('destroy');
|
||||
backToChallenges();
|
||||
});
|
||||
};
|
||||
$scope.selectWinner = function(challenge) {
|
||||
if (!confirm("Are you sure?")) return;
|
||||
if (!confirm(window.env.t('youSure'))) return;
|
||||
challenge.$close({uid:challenge.winner}, function(){
|
||||
$scope.popoverEl.popover('destroy');
|
||||
backToChallenges();
|
||||
@@ -106,7 +106,7 @@ habitrpg.controller("ChallengesCtrl", ['$rootScope','$scope', 'Shared', 'User',
|
||||
html: true,
|
||||
placement: 'right',
|
||||
trigger: 'manual',
|
||||
title: 'Close challenge and...',
|
||||
title: window.env.t('closeCha'),
|
||||
content: html
|
||||
}).popover('show');
|
||||
|
||||
@@ -140,7 +140,7 @@ habitrpg.controller("ChallengesCtrl", ['$rootScope','$scope', 'Shared', 'User',
|
||||
};
|
||||
|
||||
$scope.removeTask = function(list, $index) {
|
||||
if (!confirm("Are you sure you want to delete this task?")) return;
|
||||
if (!confirm(window.env.t('sureDelete'))) return;
|
||||
//TODO persist
|
||||
// User.log({op: "delTask", data: task});
|
||||
list.splice($index, 1);
|
||||
@@ -185,13 +185,13 @@ habitrpg.controller("ChallengesCtrl", ['$rootScope','$scope', 'Shared', 'User',
|
||||
$scope.selectedChal = chal;
|
||||
$scope.popoverEl = $($event.target);
|
||||
var html = $compile(
|
||||
'<a ng-controller="ChallengesCtrl" ng-click="leave(\'remove-all\')">Remove Tasks</a><br/>\n<a ng-click="leave(\'keep-all\')">Keep Tasks</a><br/>\n<a ng-click="leave(\'cancel\')">Cancel</a><br/>'
|
||||
'<a ng-controller="ChallengesCtrl" ng-click="leave(\'remove-all\')">' + window.env.t('removeTasks') + '</a><br/>\n<a ng-click="leave(\'keep-all\')">' + window.env.t('keepTasks') + '</a><br/>\n<a ng-click="leave(\'cancel\')">' + window.env.t('cancel') + '</a><br/>'
|
||||
)($scope);
|
||||
$scope.popoverEl.popover('destroy').popover({
|
||||
html: true,
|
||||
placement: 'top',
|
||||
trigger: 'manual',
|
||||
title: 'Leave challenge and...',
|
||||
title: window.env.t('leaveCha'),
|
||||
content: html
|
||||
}).popover('show');
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"use strict";
|
||||
|
||||
habitrpg.controller("FooterCtrl", ['$scope', '$rootScope', 'User', '$http', 'Notification', 'API_URL',
|
||||
(typeof habitrpg !== 'undefined' ? habitrpg : habitrpgStatic)
|
||||
.controller("FooterCtrl", ['$scope', '$rootScope', 'User', '$http', 'Notification', 'API_URL',
|
||||
function($scope, $rootScope, User, $http, Notification, API_URL) {
|
||||
|
||||
/**
|
||||
@@ -13,17 +14,14 @@ habitrpg.controller("FooterCtrl", ['$scope', '$rootScope', 'User', '$http', 'Not
|
||||
// Stripe
|
||||
$.getScript('//checkout.stripe.com/v2/checkout.js');
|
||||
|
||||
// Amazon Affiliate
|
||||
// if ($rootScope.authenticated() && !User.user.purchased.ads) {
|
||||
// $.getScript('//wms.assoc-amazon.com/20070822/US/js/link-enhancer-common.js?tag=ha0d2-20').fail(function() {
|
||||
// $('body').append('<img src="//wms.assoc-amazon.com/20070822/US/img/noscript.gif?tag=ha0d2-20" alt="" />');
|
||||
// });
|
||||
// }
|
||||
|
||||
// Google Analytics, only in production
|
||||
if (window.env.NODE_ENV === 'production') {
|
||||
window._gaq = [["_setAccount", "UA-33510635-1"], ["_setDomainName", "habitrpg.com"], ["_trackPageview"]];
|
||||
$.getScript(("https:" === document.location.protocol ? "https://ssl" : "http://www") + ".google-analytics.com/ga.js");
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
ga('create', window.env.GA_ID, 'habitrpg.com');
|
||||
ga('send', 'pageview');
|
||||
}
|
||||
|
||||
// Scripts only for desktop
|
||||
@@ -44,27 +42,30 @@ habitrpg.controller("FooterCtrl", ['$scope', '$rootScope', 'User', '$http', 'Not
|
||||
/**
|
||||
* Debug functions. Note that the server route for gems is only available if process.env.DEBUG=true
|
||||
*/
|
||||
$scope.addMissedDay = function(){
|
||||
if (!confirm("Are you sure you want to reset the day?")) return;
|
||||
var dayBefore = moment(User.user.lastCron).subtract('days', 1).toDate();
|
||||
User.set({'lastCron': dayBefore});
|
||||
Notification.text('-1 day, remember to refresh');
|
||||
}
|
||||
$scope.addTenGems = function(){
|
||||
$http.post(API_URL + '/api/v2/user/addTenGems').success(function(){
|
||||
User.log({});
|
||||
})
|
||||
}
|
||||
$scope.addLevelsAndGold = function(){
|
||||
User.set({
|
||||
'stats.exp': User.user.stats.exp + 10000,
|
||||
'stats.gp': User.user.stats.gp + 10000,
|
||||
'stats.mp': User.user.stats.mp + 10000
|
||||
});
|
||||
}
|
||||
$scope.addOneLevel = function(){
|
||||
User.set({
|
||||
'stats.exp': User.user.stats.exp + (Math.round(((Math.pow(User.user.stats.lvl, 2) * 0.25) + (10 * User.user.stats.lvl) + 139.75) / 10) * 10)
|
||||
});
|
||||
if (window.env.NODE_ENV === 'development') {
|
||||
$scope.addMissedDay = function(){
|
||||
if (!confirm("Are you sure you want to reset the day?")) return;
|
||||
var dayBefore = moment(User.user.lastCron).subtract('days', 1).toDate();
|
||||
User.set({'lastCron': dayBefore});
|
||||
Notification.text('-1 day, remember to refresh');
|
||||
}
|
||||
$scope.addTenGems = function(){
|
||||
$http.post(API_URL + '/api/v2/user/addTenGems').success(function(){
|
||||
User.log({});
|
||||
})
|
||||
}
|
||||
$scope.addLevelsAndGold = function(){
|
||||
User.set({
|
||||
'stats.exp': User.user.stats.exp + 10000,
|
||||
'stats.gp': User.user.stats.gp + 10000,
|
||||
'stats.mp': User.user.stats.mp + 10000
|
||||
});
|
||||
}
|
||||
$scope.addOneLevel = function(){
|
||||
User.set({
|
||||
'stats.exp': User.user.stats.exp + (Math.round(((Math.pow(User.user.stats.lvl, 2) * 0.25) + (10 * User.user.stats.lvl) + 139.75) / 10) * 10)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}])
|
||||
@@ -29,12 +29,12 @@ habitrpg.controller("GroupsCtrl", ['$scope', '$rootScope', 'Shared', 'Groups', '
|
||||
// We need the member information up top here, but then we pass it down to the modal controller
|
||||
// down below. Better way of handling this?
|
||||
Members.selectMember(uid);
|
||||
$rootScope.modals.member = true;
|
||||
$rootScope.openModal('member', {controller:'MemberModalCtrl'});
|
||||
}
|
||||
}
|
||||
|
||||
$scope.removeMember = function(group, member, isMember){
|
||||
var yes = confirm("Do you really want to remove this member from the party?")
|
||||
var yes = confirm(window.env.t('sureKick'))
|
||||
if(yes){
|
||||
Groups.Group.removeMember({gid: group._id, uuid: member._id }, undefined, function(){
|
||||
if(isMember){
|
||||
@@ -99,8 +99,8 @@ habitrpg.controller("GroupsCtrl", ['$scope', '$rootScope', 'Shared', 'Groups', '
|
||||
$scope.$watch('group.chat',$scope.chatChanged);
|
||||
|
||||
$scope.caretChanged = function(newCaretPos) {
|
||||
var relativeelement = $('.-options');
|
||||
var textarea = $('.chat-textarea');
|
||||
var relativeelement = $('.chat-form div:first');
|
||||
var textarea = $('.chat-form textarea');
|
||||
var userlist = $('.list-at-user');
|
||||
var offset = {
|
||||
x: textarea.offset().left - relativeelement.offset().left,
|
||||
@@ -180,7 +180,7 @@ habitrpg.controller("GroupsCtrl", ['$scope', '$rootScope', 'Shared', 'Groups', '
|
||||
|
||||
$scope.likeChatMessage = function(group,message) {
|
||||
if (message.uuid == User.user._id)
|
||||
return Notification.text("Can't like your own message. Don't be that person.");
|
||||
return Notification.text(window.env.t('foreverAlone'));
|
||||
if (!message.likes) message.likes = {};
|
||||
if (message.likes[User.user._id]) {
|
||||
delete message.likes[User.user._id];
|
||||
@@ -198,10 +198,10 @@ habitrpg.controller("GroupsCtrl", ['$scope', '$rootScope', 'Shared', 'Groups', '
|
||||
|
||||
// List of Ordering options for the party members list
|
||||
$scope.partyOrderChoices = {
|
||||
'level': 'Sort by Level',
|
||||
'random': 'Sort randomly',
|
||||
'pets': 'Sort by number of pets',
|
||||
'party_date_joined': 'Sort by Party date joined',
|
||||
'level': window.env.t('sortLevel'),
|
||||
'random': window.env.t('sortRandom'),
|
||||
'pets': window.env.t('sortPets'),
|
||||
'party_date_joined': window.env.t('sortJoined'),
|
||||
};
|
||||
|
||||
}])
|
||||
@@ -219,9 +219,9 @@ habitrpg.controller("GroupsCtrl", ['$scope', '$rootScope', 'Shared', 'Groups', '
|
||||
}
|
||||
$scope.newGroup = newGroup()
|
||||
$scope.create = function(group){
|
||||
if (User.user.balance < 1) return $rootScope.modals.buyGems = true;
|
||||
if (User.user.balance < 1) return $rootScope.openModal('buyGems', {track:"Gems > Create Group"});
|
||||
|
||||
if (confirm("Create Guild for 4 Gems?")) {
|
||||
if (confirm(window.env.t('confirmGuild'))) {
|
||||
group.$save(function(saved){
|
||||
User.user.balance--;
|
||||
$scope.groups.guilds.push(saved);
|
||||
@@ -284,14 +284,14 @@ habitrpg.controller("GroupsCtrl", ['$scope', '$rootScope', 'Shared', 'Groups', '
|
||||
}), '_id');
|
||||
if (_.intersection(challenges, User.user.challenges).length > 0) {
|
||||
html = $compile(
|
||||
'<a ng-controller="GroupsCtrl" ng-click="leave(\'remove-all\')">Remove Tasks</a><br/>\n<a ng-click="leave(\'keep-all\')">Keep Tasks</a><br/>\n<a ng-click="leave(\'cancel\')">Cancel</a><br/>'
|
||||
'<a ng-controller="GroupsCtrl" ng-click="leave(\'remove-all\')">' + window.env.t('removeTasks') + '</a><br/>\n<a ng-click="leave(\'keep-all\')">' + window.env.t('keepTasks') + '</a><br/>\n<a ng-click="leave(\'cancel\')">' + window.env.t('cancel') + '</a><br/>'
|
||||
)($scope);
|
||||
title = "Leave group challenges and...";
|
||||
title = window.env.t('leaveGroupCha');
|
||||
} else {
|
||||
html = $compile(
|
||||
'<a ng-controller="GroupsCtrl" ng-click="leave(\'keep-all\')">Confirm</a><br/>\n<a ng-click="leave(\'cancel\')">Cancel</a><br/>'
|
||||
'<a ng-controller="GroupsCtrl" ng-click="leave(\'keep-all\')">' + window.env.t('confirm') + '</a><br/>\n<a ng-click="leave(\'cancel\')">' + window.env.t('cancel') + '</a><br/>'
|
||||
)($scope);
|
||||
title = "Leave group?"
|
||||
title = window.env.t('leaveGroup')
|
||||
}
|
||||
$scope.popoverEl.popover('destroy').popover({
|
||||
html: true,
|
||||
@@ -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;
|
||||
@@ -358,14 +361,14 @@ habitrpg.controller("GroupsCtrl", ['$scope', '$rootScope', 'Shared', 'Groups', '
|
||||
}), '_id');
|
||||
if (_.intersection(challenges, User.user.challenges).length > 0) {
|
||||
html = $compile(
|
||||
'<a ng-controller="GroupsCtrl" ng-click="leave(\'remove-all\')">Remove Tasks</a><br/>\n<a ng-click="leave(\'keep-all\')">Keep Tasks</a><br/>\n<a ng-click="leave(\'cancel\')">Cancel</a><br/>'
|
||||
'<a ng-controller="GroupsCtrl" ng-click="leave(\'remove-all\')">' + window.env.t('removeTasks') + '</a><br/>\n<a ng-click="leave(\'keep-all\')">' + window.env.t('keepTasks') + '</a><br/>\n<a ng-click="leave(\'cancel\')">' + window.env.t('cancel') + '</a><br/>'
|
||||
)($scope);
|
||||
title = "Leave party challenges and...";
|
||||
title = window.env.t('leavePartyCha');
|
||||
} else {
|
||||
html = $compile(
|
||||
'<a ng-controller="GroupsCtrl" ng-click="leave(\'keep-all\')">Confirm</a><br/>\n<a ng-click="leave(\'cancel\')">Cancel</a><br/>'
|
||||
'<a ng-controller="GroupsCtrl" ng-click="leave(\'keep-all\')">' + window.env.t('confirm') + '</a><br/>\n<a ng-click="leave(\'cancel\')">' + window.env.t('cancel') + '</a><br/>'
|
||||
)($scope);
|
||||
title = "Leave party?";
|
||||
title = window.env.t('leaveParty');
|
||||
}
|
||||
$scope.popoverEl.popover('destroy').popover({
|
||||
html: true,
|
||||
@@ -383,8 +386,8 @@ habitrpg.controller("GroupsCtrl", ['$scope', '$rootScope', 'Shared', 'Groups', '
|
||||
}
|
||||
|
||||
$scope.questAbort = function(){
|
||||
if (!confirm("Are you sure you want to abort this mission? It will abort it for everyone in your party, and you'll lose your quest scroll.")) return;
|
||||
if (!confirm("Are you double sure? Make sure they won't hate you forever!")) return;
|
||||
if (!confirm(window.env.t('sureAbort'))) return;
|
||||
if (!confirm(window.env.t('doubleSureAbort'))) return;
|
||||
$rootScope.party.$questAbort();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,8 @@ habitrpg.controller("InventoryCtrl", ['$rootScope', '$scope', '$window', 'User',
|
||||
|
||||
$scope.selectedEgg = null; // {index: 1, name: "Tiger", value: 5}
|
||||
$scope.selectedPotion = null; // {index: 5, name: "Red", value: 3}
|
||||
$scope.totalPets = _.size(Content.eggs) * _.size(Content.hatchingPotions);
|
||||
$scope.totalPets = _.size(Content.dropEggs) * _.size(Content.hatchingPotions);
|
||||
$scope.totalMounts = _.size(Content.eggs) * _.size(Content.hatchingPotions);
|
||||
|
||||
// count egg, food, hatchingPotion stack totals
|
||||
var countStacks = function(items) { return _.reduce(items,function(m,v){return m+v;},0);}
|
||||
@@ -79,7 +80,7 @@ habitrpg.controller("InventoryCtrl", ['$rootScope', '$scope', '$window', 'User',
|
||||
}
|
||||
|
||||
$scope.hatch = function(egg, potion){
|
||||
if (!$window.confirm('Hatch a ' + potion.key + ' ' + egg.key + '?')) return;
|
||||
if (!$window.confirm(window.env.t('hatchAPot', {potion: potion.key, egg: egg.key}))) return;
|
||||
user.ops.hatch({params:{egg:egg.key, hatchingPotion:potion.key}});
|
||||
$scope.selectedEgg = null;
|
||||
$scope.selectedPotion = null;
|
||||
@@ -87,9 +88,11 @@ habitrpg.controller("InventoryCtrl", ['$rootScope', '$scope', '$window', 'User',
|
||||
|
||||
$scope.purchase = function(type, item){
|
||||
var gems = User.user.balance * 4;
|
||||
if(gems < item.value) return $rootScope.modals.buyGems = true;
|
||||
var string = (type == 'hatchingPotion') ? 'hatching potion' : type; // give hatchingPotion a space
|
||||
var message = "Buy this " + string + " with " + item.value + " of your " + gems + " Gems?"
|
||||
|
||||
if(gems < item.value) return $rootScope.openModal('buyGems');
|
||||
var string = (type == 'hatchingPotions') ? 'hatching potion' : (type == 'eggs') ? 'egg' : (type == 'quests') ? 'quest' : (item.key == 'Saddle') ? 'saddle' : (type == 'special') ? item.key : type; // this is ugly but temporary, once the purchase modal is done this will be removed
|
||||
var message = window.env.t('buyThis', {text: string, price: item.value, gems: gems})
|
||||
|
||||
if($window.confirm(message))
|
||||
User.user.ops.purchase({params:{type:type,key:item.key}});
|
||||
}
|
||||
@@ -102,8 +105,8 @@ habitrpg.controller("InventoryCtrl", ['$rootScope', '$scope', '$window', 'User',
|
||||
if ($scope.selectedFood) {
|
||||
var food = $scope.selectedFood
|
||||
if (food.key == 'Saddle') {
|
||||
if (!$window.confirm('Saddle ' + pet + '?')) return;
|
||||
} else if (!$window.confirm('Feed ' + petDisplayName + ' '+ food.article + food.text + '?')) {
|
||||
if (!$window.confirm(window.env.t('useSaddle', {pet: pet}))) return;
|
||||
} else if (!$window.confirm(window.env.t('feedPet', {name: petDisplayName, article: food.article, text: food.text}))) {
|
||||
return;
|
||||
}
|
||||
User.user.ops.feed({params:{pet: pet, food: food.key}});
|
||||
@@ -123,16 +126,14 @@ habitrpg.controller("InventoryCtrl", ['$rootScope', '$scope', '$window', 'User',
|
||||
var item = Content.quests[quest];
|
||||
var completedPrevious = !item.previous || (User.user.achievements.quests && User.user.achievements.quests[item.previous]);
|
||||
if (!completedPrevious)
|
||||
return alert("You must first complete " + $rootScope.Content.quests[item.previous].text + '.');
|
||||
return alert(window.env.t('mustComplete', {quest: $rootScope.Content.quests[item.previous].text}));
|
||||
if (item.lvl && item.lvl > user.stats.lvl)
|
||||
return alert("You must be level " + item.lvl + '.');
|
||||
return alert(window.env.t('mustLevel', {level: item.lvl}));
|
||||
$rootScope.selectedQuest = item;
|
||||
$rootScope.modals.showQuest = true;
|
||||
$rootScope.openModal('showQuest', {controller:'InventoryCtrl'});
|
||||
}
|
||||
$scope.closeQuest = function(){
|
||||
$rootScope.selectedQuest = undefined;
|
||||
$rootScope.modals.showQuest = false;
|
||||
$rootScope.modals.buyQuest = false;
|
||||
}
|
||||
$scope.questInit = function(){
|
||||
$rootScope.party.$questAccept({key:$scope.selectedQuest.key}, function(){
|
||||
@@ -142,11 +143,13 @@ habitrpg.controller("InventoryCtrl", ['$rootScope', '$scope', '$window', 'User',
|
||||
}
|
||||
$scope.buyQuest = function(quest) {
|
||||
var item = Content.quests[quest];
|
||||
if (item.lvl && item.lvl > user.stats.lvl)
|
||||
return alert(window.env.t('mustLvlQuest', {level: item.lvl}));
|
||||
var completedPrevious = !item.previous || (User.user.achievements.quests && User.user.achievements.quests[item.previous]);
|
||||
if (!completedPrevious)
|
||||
return $scope.purchase("quests", item);
|
||||
$rootScope.selectedQuest = item;
|
||||
$rootScope.modals.buyQuest = true;
|
||||
$rootScope.openModal('buyQuest', {controller:'InventoryCtrl'});
|
||||
}
|
||||
}
|
||||
]);
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
'use strict';
|
||||
|
||||
habitrpg.controller('NotificationCtrl',
|
||||
['$scope', '$rootScope', 'Shared', 'User', 'Guide', 'Notification', function ($scope, $rootScope, Shared, User, Guide, Notification) {
|
||||
['$scope', '$rootScope', 'Shared', 'User', 'Guide', 'Notification',
|
||||
function ($scope, $rootScope, Shared, User, Guide, Notification) {
|
||||
|
||||
$rootScope.$watch('user.stats.hp', function(after, before) {
|
||||
if (after <= 0){
|
||||
$rootScope.openModal('death', {keyboard:false, backdrop:'static'});
|
||||
}
|
||||
if (after == before) return;
|
||||
if (User.user.stats.lvl == 0) return;
|
||||
Notification.hp(after - before, 'hp');
|
||||
@@ -26,7 +30,7 @@ habitrpg.controller('NotificationCtrl',
|
||||
|
||||
if ((money > 0) && !!bonus) {
|
||||
if (bonus < 0.01) bonus = 0.01;
|
||||
Notification.text("+ " + Notification.coins(bonus) + " Streak Bonus!");
|
||||
Notification.text("+ " + Notification.coins(bonus) + ' ' + window.env.t('streakCoins'));
|
||||
delete User.user._tmp.streakBonus;
|
||||
}
|
||||
});
|
||||
@@ -61,31 +65,35 @@ habitrpg.controller('NotificationCtrl',
|
||||
|
||||
$rootScope.$watch('user.achievements.streak', function(after, before){
|
||||
if(before == undefined || after == before || after < before) return;
|
||||
$rootScope.modals.achievements.streak = true;
|
||||
$rootScope.openModal('achievements/streak');
|
||||
});
|
||||
|
||||
$rootScope.$watch('user.achievements.ultimateGear', function(after, before){
|
||||
if (after === before || after !== true) return;
|
||||
$rootScope.modals.achievements.ultimateGear = true;
|
||||
$rootScope.openModal('achievements/ultimateGear');
|
||||
});
|
||||
|
||||
$rootScope.$watch('user.items.pets', function(after, before){
|
||||
if(_.size(after) === _.size(before) ||
|
||||
Shared.countPets(null, after) < 90) return;
|
||||
User.user.achievements.beastMaster = true;
|
||||
$rootScope.modals.achievements.beastMaster = true;
|
||||
$rootScope.openModal('achievements/beastMaster');
|
||||
}, true);
|
||||
|
||||
$rootScope.$watch('user.achievements.rebirths', function(after, before){
|
||||
if(after === before) return;
|
||||
$rootScope.modals.achievements.rebirth = true;
|
||||
$rootScope.openModal('achievements/rebirth');
|
||||
});
|
||||
|
||||
$rootScope.$watch('user.flags.contributor', function(after, before){
|
||||
if (after === before || after !== true) return;
|
||||
$rootScope.openModal('achievements/contributor');
|
||||
});
|
||||
|
||||
/*_.each(['weapon', 'head', 'chest', 'shield'], function(watched){
|
||||
$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);
|
||||
@@ -93,6 +101,13 @@ habitrpg.controller('NotificationCtrl',
|
||||
})
|
||||
});*/
|
||||
|
||||
// Classes modal
|
||||
$rootScope.$watch('!user.flags.classSelected && user.stats.lvl >= 10', function(after, before){
|
||||
if(after){
|
||||
$rootScope.openModal('chooseClass', {controller:'UserCtrl', keyboard:false, backdrop:'static'});
|
||||
}
|
||||
});
|
||||
|
||||
$rootScope.$watch('user.stats.lvl', function(after, before) {
|
||||
if (after == before) return;
|
||||
if (after > before) {
|
||||
@@ -100,8 +115,23 @@ habitrpg.controller('NotificationCtrl',
|
||||
}
|
||||
});
|
||||
|
||||
// Completed quest modal
|
||||
$rootScope.$watch('user.party.quest.completed', function(after, before){
|
||||
if (after == before || after != true) return;
|
||||
$rootScope.openModal('questCompleted', {controller:'InventoryCtrl'});
|
||||
});
|
||||
|
||||
// Quest invitation modal
|
||||
$rootScope.$watch('party.quest.key && !party.quest.active && party.quest.members[user._id] == undefined', function(after, before){
|
||||
if (after == before || after != true) return;
|
||||
$rootScope.openModal('questInvitation');
|
||||
});
|
||||
|
||||
$rootScope.$on('responseError', function(ev, error){
|
||||
Notification.error(error);
|
||||
});
|
||||
$rootScope.$on('responseText', function(ev, error){
|
||||
Notification.text(error);
|
||||
});
|
||||
}
|
||||
]);
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
/* Make user and settings available for everyone through root scope.
|
||||
*/
|
||||
|
||||
habitrpg.controller("RootCtrl", ['$scope', '$rootScope', '$location', 'User', '$http', '$state', '$stateParams', 'Notification', 'Groups', 'Shared', 'Content',
|
||||
function($scope, $rootScope, $location, User, $http, $state, $stateParams, Notification, Groups, Shared, Content) {
|
||||
habitrpg.controller("RootCtrl", ['$scope', '$rootScope', '$location', 'User', '$http', '$state', '$stateParams', 'Notification', 'Groups', 'Shared', 'Content', '$modal', '$timeout',
|
||||
function($scope, $rootScope, $location, User, $http, $state, $stateParams, Notification, Groups, Shared, Content, $modal, $timeout) {
|
||||
var user = User.user;
|
||||
|
||||
var initSticky = _.once(function(){
|
||||
@@ -13,8 +13,11 @@ habitrpg.controller("RootCtrl", ['$scope', '$rootScope', '$location', 'User', '$
|
||||
})
|
||||
$rootScope.$on('userUpdated',initSticky);
|
||||
|
||||
$rootScope.modals = {};
|
||||
$rootScope.modals.achievements = {};
|
||||
$rootScope.$on('$stateChangeSuccess',
|
||||
function(event, toState, toParams, fromState, fromParams){
|
||||
if (!!fromState.name) window.ga && ga('send', 'pageview', {page: '/#/'+toState.name});
|
||||
});
|
||||
|
||||
$rootScope.User = User;
|
||||
$rootScope.user = user;
|
||||
$rootScope.moment = window.moment;
|
||||
@@ -23,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;
|
||||
@@ -66,29 +70,60 @@ habitrpg.controller("RootCtrl", ['$scope', '$rootScope', '$location', 'User', '$
|
||||
$rootScope.set = User.set;
|
||||
$rootScope.authenticated = User.authenticated;
|
||||
|
||||
// Open a modal from a template expression (like ng-click,...)
|
||||
// Otherwise use the proper $modal.open
|
||||
$rootScope.openModal = function(template, options){//controller, scope, keyboard, backdrop){
|
||||
if (!options) options = {};
|
||||
if (options.track) window.ga && ga('send', 'event', 'button', 'click', options.track);
|
||||
return $modal.open({
|
||||
templateUrl: 'modals/' + template + '.html',
|
||||
controller: options.controller, // optional
|
||||
scope: options.scope, // optional
|
||||
keyboard: (options.keyboard === undefined ? true : options.keyboard), // optional
|
||||
backdrop: (options.backdrop === undefined ? true : options.backdrop) // optional
|
||||
});
|
||||
}
|
||||
|
||||
$rootScope.dismissAlert = function() {
|
||||
$rootScope.modals.newStuff = false;
|
||||
$rootScope.set({'flags.newStuff':false});
|
||||
}
|
||||
|
||||
$rootScope.notPorted = function(){
|
||||
alert("This feature is not yet ported from the original site.");
|
||||
alert(window.env.t('notPorted'));
|
||||
}
|
||||
|
||||
$rootScope.dismissErrorOrWarning = function(type, $index){
|
||||
$rootScope.flash[type].splice($index, 1);
|
||||
}
|
||||
|
||||
$rootScope.initPayPalButton = function($event){
|
||||
//debugger
|
||||
var data = {
|
||||
name:env.t('paypalText'),
|
||||
//env:window.env.NODE_ENV == 'production' ? '' : 'sandbox',
|
||||
quantity:1,
|
||||
amount:5,
|
||||
currency:'USD',
|
||||
tax:0,
|
||||
callback:window.env.BASE_URL + '/api/v2/user/buy-gems/paypal-ipn',
|
||||
custom:'?uid='+User.user._id + '&apiToken=' + User.user.apiToken,
|
||||
'return':window.env.BASE_URL,
|
||||
rm:1,
|
||||
no_shipping:1
|
||||
};
|
||||
PAYPAL.apps.ButtonFactory.create(window.env.PAYPAL_MERCHANT, data, 'buynow', document.getElementById('custom-paypal-button'));
|
||||
}
|
||||
|
||||
$rootScope.showStripe = function(subscription) {
|
||||
StripeCheckout.open({
|
||||
key: window.env.STRIPE_PUB_KEY,
|
||||
address: false,
|
||||
amount: 500,
|
||||
name: subscription ? "Subscribe" : "Checkout",
|
||||
name: subscription ? window.env.t('subscribe') : window.env.t('checkout'),
|
||||
description: subscription ?
|
||||
"Buy gems with Gold, No Ads, Support the Devs" :
|
||||
"20 Gems, No Ads, Support the Devs",
|
||||
panelLabel: subscription ? "Subscribe" : "Checkout",
|
||||
window.env.t('buySubsText') :
|
||||
window.env.t('buyCheckText'),
|
||||
panelLabel: subscription ? window.env.t('subscribe') : window.env.t('checkout'),
|
||||
token: function(data) {
|
||||
var url = '/api/v2/user/buy-gems';
|
||||
if (subscription) url += '?plan=basic_earned';
|
||||
@@ -105,7 +140,7 @@ habitrpg.controller("RootCtrl", ['$scope', '$rootScope', '$location', 'User', '$
|
||||
}
|
||||
|
||||
$scope.cancelSubscription = function(){
|
||||
if (!confirm("Are you sure you want to cancel your subscription?")) return;
|
||||
if (!confirm(window.env.t('sureCancelSub'))) return;
|
||||
//TODO use Stripe API to keep subscription till end of their month
|
||||
$http.post('/api/v2/user/cancel-subscription').success(function(){
|
||||
window.location.reload(true);
|
||||
@@ -117,7 +152,7 @@ habitrpg.controller("RootCtrl", ['$scope', '$rootScope', '$location', 'User', '$
|
||||
if (backer && backer.npc) return backer.npc;
|
||||
var l = contrib && contrib.level;
|
||||
if (l && l > 0) {
|
||||
var level = (l < 3) ? 'Friend' : (l < 5) ? 'Elite' : (l < 7) ? 'Champion' : (l < 8) ? 'Legendary' : 'Heroic';
|
||||
var level = (l < 3) ? window.env.t('friend') : (l < 5) ? window.env.t('elite') : (l < 7) ? window.env.t('champion') : (l < 8) ? window.env.t('legendary') : window.env.t('heroic');
|
||||
return level + ' ' + contrib.text;
|
||||
}
|
||||
}
|
||||
@@ -145,7 +180,7 @@ habitrpg.controller("RootCtrl", ['$scope', '$rootScope', '$location', 'User', '$
|
||||
});
|
||||
data = google.visualization.arrayToDataTable(matrix);
|
||||
options = {
|
||||
title: 'History',
|
||||
title: window.env.t('history'),
|
||||
backgroundColor: {
|
||||
fill: 'transparent'
|
||||
},
|
||||
@@ -163,7 +198,12 @@ habitrpg.controller("RootCtrl", ['$scope', '$rootScope', '$location', 'User', '$
|
||||
------------------------
|
||||
*/
|
||||
$scope.castStart = function(spell) {
|
||||
if (User.user.stats.mp < spell.mana) return Notification.text("Not enough mana.");
|
||||
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') {
|
||||
@@ -178,7 +218,7 @@ habitrpg.controller("RootCtrl", ['$scope', '$rootScope', '$location', 'User', '$
|
||||
$scope.castEnd = function(target, type, $event){
|
||||
if (!$rootScope.applyingAction) return;
|
||||
$event && ($event.stopPropagation(),$event.preventDefault());
|
||||
if ($scope.spell.target != type) return Notification.text("Invalid target");
|
||||
if ($scope.spell.target != type) return Notification.text(window.env.t('invalidTarget'));
|
||||
$scope.spell.cast(User.user, target);
|
||||
User.save();
|
||||
|
||||
@@ -189,11 +229,11 @@ habitrpg.controller("RootCtrl", ['$scope', '$rootScope', '$location', 'User', '$
|
||||
|
||||
$http.post('/api/v2/user/class/cast/'+spell.key+'?targetType='+type+'&targetId='+targetId)
|
||||
.success(function(){
|
||||
var msg = "You cast " + spell.text;
|
||||
var msg = window.env.t('youCast', {spell: spell.text});
|
||||
switch (type) {
|
||||
case 'task': msg += ' on ' + target.text + '.';break;
|
||||
case 'user': msg += ' on ' + target.profile.name + '.';break;
|
||||
case 'party': msg += ' for the Party.';break;
|
||||
case 'task': msg = window.env.t('youCastTarget', {spell: spell.text, target: target.text});break;
|
||||
case 'user': msg = window.env.t('youCastTarget', {spell: spell.text, target: target.profile.name});break;
|
||||
case 'party': msg = window.env.t('youCastParty', {spell: spell.text});break;
|
||||
}
|
||||
Notification.text(msg);
|
||||
});
|
||||
|
||||
@@ -38,7 +38,7 @@ habitrpg.controller('SettingsCtrl',
|
||||
var dayStart = +User.user.preferences.dayStart;
|
||||
if (_.isNaN(dayStart) || dayStart < 0 || dayStart > 24) {
|
||||
dayStart = 0;
|
||||
return alert('Please enter a number between 0 and 24');
|
||||
return alert(window.env.t('enterNumber'));
|
||||
}
|
||||
User.set({'preferences.dayStart': dayStart});
|
||||
}
|
||||
@@ -55,23 +55,21 @@ habitrpg.controller('SettingsCtrl',
|
||||
|
||||
$scope.reroll = function(){
|
||||
User.user.ops.reroll({});
|
||||
$rootScope.modals.reroll = false;
|
||||
$rootScope.$state.go('tasks');
|
||||
}
|
||||
|
||||
$scope.rebirth = function(){
|
||||
User.user.ops.rebirth({});
|
||||
$rootScope.modals.rebirth = false;
|
||||
$rootScope.$state.go('tasks');
|
||||
}
|
||||
|
||||
$scope.changePassword = function(changePass){
|
||||
if (!changePass.oldPassword || !changePass.newPassword || !changePass.confirmNewPassword) {
|
||||
return alert("Please fill out all fields");
|
||||
return alert(window.env.t('fillAll'));
|
||||
}
|
||||
$http.post(API_URL + '/api/v2/user/change-password', changePass)
|
||||
.success(function(){
|
||||
alert("Password successfully changed");
|
||||
alert(window.env.t('passSuccess'));
|
||||
$scope.changePass = {};
|
||||
})
|
||||
.error(function(data){
|
||||
@@ -80,12 +78,11 @@ habitrpg.controller('SettingsCtrl',
|
||||
}
|
||||
|
||||
$scope.restoreValues = {};
|
||||
$rootScope.$watch('modals.restore', function(value){
|
||||
if(value === true){
|
||||
$scope.restoreValues.stats = angular.copy(User.user.stats);
|
||||
$scope.restoreValues.achievements = {streak: User.user.achievements.streak || 0};
|
||||
}
|
||||
})
|
||||
$rootScope.openRestoreModal = function(){
|
||||
$scope.restoreValues.stats = angular.copy(User.user.stats);
|
||||
$scope.restoreValues.achievements = {streak: User.user.achievements.streak || 0};
|
||||
$rootScope.openModal('restore', {scope:$scope});
|
||||
};
|
||||
|
||||
$scope.restore = function(){
|
||||
var stats = $scope.restoreValues.stats,
|
||||
@@ -98,12 +95,10 @@ habitrpg.controller('SettingsCtrl',
|
||||
"stats.mp": stats.mp,
|
||||
"achievements.streak": achievements.streak
|
||||
});
|
||||
$rootScope.modals.restore = false;
|
||||
}
|
||||
|
||||
$scope.reset = function(){
|
||||
User.user.ops.reset({});
|
||||
$rootScope.modals.reset = false;
|
||||
$rootScope.$state.go('tasks');
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ habitrpg.controller("TasksCtrl", ['$scope', '$location', 'User','Notification',
|
||||
};
|
||||
|
||||
$scope.removeTask = function(list, $index) {
|
||||
if (!confirm("Are you sure you want to delete this task?")) return;
|
||||
if (!confirm(window.env.t('sureDelete'))) return;
|
||||
User.user.ops.deleteTask({params:{id:list[$index].id}})
|
||||
};
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ habitrpg.controller("UserCtrl", ['$rootScope', '$scope', '$location', 'User', '$
|
||||
|
||||
$scope.changeClass = function(klass){
|
||||
if (!klass) {
|
||||
if (!confirm("Are you sure? This will reset your character's class and allocated points (you'll get them all back to re-allocate), and costs 3 gems"))
|
||||
if (!confirm(window.env.t('sureReset')))
|
||||
return;
|
||||
return User.user.ops.changeClass({});
|
||||
}
|
||||
@@ -52,11 +52,11 @@ habitrpg.controller("UserCtrl", ['$rootScope', '$scope', '$location', 'User', '$
|
||||
var cost = fullSet ? 1.25 : 0.5; // 5G per set, 2G per individual
|
||||
|
||||
if (fullSet) {
|
||||
if (confirm("Purchase for 5 Gems?") !== true) return;
|
||||
if (User.user.balance < cost) return $rootScope.modals.buyGems = true;
|
||||
if (confirm(window.env.t('purchaseFor5')) !== true) return;
|
||||
if (User.user.balance < cost) return $rootScope.openModal('buyGems');
|
||||
} else if (!User.user.fns.dotGet('purchased.' + path)) {
|
||||
if (confirm("Purchase for 2 Gems?") !== true) return;
|
||||
if (User.user.balance < cost) return $rootScope.modals.buyGems = true;
|
||||
if (confirm(window.env.t('purchaseFor2')) !== true) return;
|
||||
if (User.user.balance < cost) return $rootScope.openModal('buyGems');
|
||||
}
|
||||
User.user.ops.unlock({query:{path:path}})
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ habitrpg.directive('habitrpgAdsense', function() {
|
||||
template: '<div ng-transclude></div>',
|
||||
link: function ($scope, element, attrs) {}
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
habitrpg.directive('whenScrolled', function() {
|
||||
return function(scope, elm, attr) {
|
||||
@@ -85,21 +85,21 @@ habitrpg
|
||||
scope.main = attrs.main;
|
||||
$rootScope.lists = [
|
||||
{
|
||||
header: env.t('habits'),
|
||||
header: window.env.t('habits'),
|
||||
type: 'habit',
|
||||
placeHolder: env.t('newHabit')
|
||||
placeHolder: window.env.t('newHabit')
|
||||
}, {
|
||||
header: env.t('dailies'),
|
||||
header: window.env.t('dailies'),
|
||||
type: 'daily',
|
||||
placeHolder: env.t('newDaily')
|
||||
placeHolder: window.env.t('newDaily')
|
||||
}, {
|
||||
header: env.t('todos'),
|
||||
header: window.env.t('todos'),
|
||||
type: 'todo',
|
||||
placeHolder: env.t('newTodo')
|
||||
placeHolder: window.env.t('newTodo')
|
||||
}, {
|
||||
header: env.t('rewards'),
|
||||
header: window.env.t('rewards'),
|
||||
type: 'reward',
|
||||
placeHolder: env.t('newReward')
|
||||
placeHolder: window.env.t('newReward')
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
"use strict";
|
||||
|
||||
window.env = window.env || {}; //FIX tests
|
||||
|
||||
// If Moment.js is loaded,
|
||||
if(window.moment && window.env.language && window.env.language.momentLang && window.env.language.momentLangCode){
|
||||
var head = document.getElementsByTagName('head')[0];
|
||||
var script = document.createElement('script');
|
||||
script.type = 'text/javascript';
|
||||
script.text = window.env.language.momentLang;
|
||||
head.appendChild(script);
|
||||
window.moment.lang(window.env.language.momentLangCode);
|
||||
}
|
||||
|
||||
window.env.t = function(stringName, vars){
|
||||
var string = window.env.translations[stringName];
|
||||
if(!string) return window._.template(window.env.translations.stringNotFound, {string: stringName});
|
||||
|
||||
return vars === undefined ? string : window._.template(string, vars);
|
||||
}
|
||||
@@ -32,7 +32,7 @@ factory('Facebook',
|
||||
$http.post(API_URL + '/api/v2/user/auth/facebook', data).success(function(data, status, headers, config) {
|
||||
User.authenticate(data.id, data.token, function(err) {
|
||||
if (!err) {
|
||||
alert('Login successful!');
|
||||
alert(window.env.t('loginSuccess'));
|
||||
$location.path("/habit");
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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');
|
||||
if (User.user.newMessages) User.user.newMessages[gid] = false;
|
||||
},
|
||||
|
||||
Group: Group
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,58 +18,58 @@ angular.module('guideServices', []).
|
||||
var tourSteps = [
|
||||
{
|
||||
element: ".main-herobox",
|
||||
title: "Welcome to HabitRPG",
|
||||
content: "Welcome to HabitRPG, a habit-tracker which treats your goals like a Role Playing Game. I'm <a href='http://www.kickstarter.com/profile/1823740484' target='_blank'>Justin</a>, your guide!",
|
||||
title: window.env.t('welcomeHabit'),
|
||||
content: window.env.t('welcomeHabitT1') + " <a href='http://www.kickstarter.com/profile/1823740484' target='_blank'>Justin</a>, " + window.env.t('welcomeHabitT2'),
|
||||
}, {
|
||||
element: ".main-herobox",
|
||||
title: "Your Avatar",
|
||||
content: "This is your avatar. It represents you in the world of Habitica. As you accomplish goals, your avatar will gain levels, earn gold, and equip itself for further challenges ahead.",
|
||||
title: window.env.t('yourAvatar'),
|
||||
content: window.env.t('yourAvatarText'),
|
||||
}, {
|
||||
element: ".main-herobox",
|
||||
title: "Avatar Customization",
|
||||
content: "You can customize your avatar by clicking anywhere in this box. Change your body type, hair color, skin color, and more from this menu. You can also find a number of HabitRPG's exciting social features by clicking through tabs on the customization page.",
|
||||
title: window.env.t('avatarCustom'),
|
||||
content: window.env.t('avatarCustomText'),
|
||||
}, {
|
||||
element: "#bars",
|
||||
title: "Hit Points",
|
||||
content: "The red bar tracks your avatar's health points. Whenever you fail to meet a goal, you take damage and lose health. If your health bar reaches zero, you die. Dying results in the loss of one level, all your gold, and a piece of equipment.",
|
||||
title: window.env.t('hitPoints'),
|
||||
content: window.env.t('hitPointsText'),
|
||||
}, {
|
||||
element: "#bars",
|
||||
title: "Experience Points",
|
||||
content: "The yellow bar tracks your avatar's experience points. Whenever you succeed in achieving a goal, you gain both gold and experience. When your experience bar maxes out, you gain a level. Gaining levels is how you unlock new and exciting features on HabitRPG.",
|
||||
title: window.env.t('expPoints'),
|
||||
content: window.env.t('expPointsText'),
|
||||
}, {
|
||||
element: "ul.habits",
|
||||
title: "Types of Goals",
|
||||
content: "HabitRPG allows you to track your goals in three different ways. These goals are categorized in columns as Habits, Dailies, or To-Dos.",
|
||||
title: window.env.t('typeGoals'),
|
||||
content: window.env.t('typeGoalsText'),
|
||||
placement: "top"
|
||||
}, {
|
||||
element: "ul.habits",
|
||||
title: "Habits",
|
||||
content: "Habits are goals that you constantly track. They can be given plus or minus values, allowing you to gain experience and gold for good habits or lose health for bad ones.",
|
||||
title: window.env.t('habits'),
|
||||
content: window.env.t('tourHabits'),
|
||||
placement: "top"
|
||||
}, {
|
||||
element: "ul.dailys",
|
||||
title: "Dailies",
|
||||
content: "Dailies are goals that you want to complete once a day. Checking off a daily reaps experience and gold. Failing to check off your daily before the day resets results in a loss of health. You can change your day start settings from the options menu.",
|
||||
title: window.env.t('dailies'),
|
||||
content: window.env.t('tourDailies'),
|
||||
placement: "top"
|
||||
}, {
|
||||
element: "ul.todos",
|
||||
title: "To-Dos",
|
||||
content: "To-Dos are one-off goals that you can get to eventually. While it is possible to set a deadline on a to-do, they are not required. To-Dos make for a quick and easy way to gain experience.",
|
||||
title: window.env.t('todos'),
|
||||
content: window.env.t('tourTodos'),
|
||||
placement: "top"
|
||||
}, {
|
||||
element: "ul.main-list.rewards",
|
||||
title: "Rewards",
|
||||
content: "All that gold you earned will allow you to reward yourself with either custom or in-game prizes. Buy them liberally – rewarding yourself is integral in forming good habits.",
|
||||
title: window.env.t('rewards'),
|
||||
content: window.env.t('tourRewards'),
|
||||
placement: "top"
|
||||
}, {
|
||||
element: "ul.habits li:first-child",
|
||||
title: "Hover over comments",
|
||||
content: "You can add comments to your tasks by clicking the edit icon. Hover over each task's comment for more details about how HabitRPG works. When you're ready to get started, you can delete the existing tasks and add your own.",
|
||||
title: window.env.t('hoverOver'),
|
||||
content: window.env.t('hoverOverText'),
|
||||
placement: "right"
|
||||
}, {
|
||||
element: "ul.habits li:first-child",
|
||||
title: "Unlock New Features",
|
||||
content: "That's all you need to know for now, but I'll be back as you level up to let you know about new features you've unlocked. Each new feature will give you more incentives to accomplish your goals. Find out more at the <a href='http://habitrpg.wikia.com' target='_blank'>HabitRPG Wiki</a> or let yourself be surprised. Good luck!",
|
||||
title: window.env.t('unlockFeatures'),
|
||||
content: window.env.t('unlockFeaturesT1') + " <a href='http://habitrpg.wikia.com' target='_blank'>" + window.env.t('habitWiki') + "</a> " + window.env.t('unlockFeaturesT2'),
|
||||
placement: "right"
|
||||
}
|
||||
];
|
||||
@@ -96,7 +96,7 @@ angular.module('guideServices', []).
|
||||
var showPopover = function(selector, title, html, placement) {
|
||||
if (!placement) placement = 'bottom';
|
||||
$(selector).popover('destroy');
|
||||
var button = "<button class='btn btn-sm btn-default' onClick=\"$('" + selector + "').popover('hide');return false;\">Close</button>";
|
||||
var button = "<button class='btn btn-sm btn-default' onClick=\"$('" + selector + "').popover('hide');return false;\">" + window.env.t('close') + "</button>";
|
||||
html = "<div><div class='npc_justin float-left'></div>" + html + '<br/>' + button + '</div>';
|
||||
$(selector).popover({
|
||||
title: title,
|
||||
@@ -109,19 +109,19 @@ angular.module('guideServices', []).
|
||||
|
||||
$rootScope.$watch('user.flags.customizationsNotification', function(after, before) {
|
||||
if (alreadyShown(before, after)) return;
|
||||
showPopover('.main-herobox', 'Customize Your Avatar', "Click your avatar to customize your appearance.", 'bottom');
|
||||
showPopover('.main-herobox', window.env.t('customAvatar'), window.env.t('customAvatarText'), 'bottom');
|
||||
});
|
||||
|
||||
$rootScope.$watch('user.flags.itemsEnabled', function(after, before) {
|
||||
if (alreadyShown(before, after)) return;
|
||||
var html = "Congratulations, you have unlocked the Item Store! You can now buy weapons, armor, potions, etc. Read each item's comment for more information.";
|
||||
showPopover('div.rewards', 'Item Store Unlocked', html, 'left');
|
||||
var html = window.env.t('storeUnlockedText');
|
||||
showPopover('div.rewards', window.env.t('storeUnlocked'), html, 'left');
|
||||
});
|
||||
|
||||
$rootScope.$watch('user.flags.partyEnabled', function(after, before) {
|
||||
if (alreadyShown(before, after)) return;
|
||||
var html = "Be social, join a party and play Habit with your friends! You'll be better at your habits with accountability partners. Click User -> Options -> Party, and follow the instructions. LFG anyone?";
|
||||
showPopover('.user-menu', 'Party System', html, 'bottom');
|
||||
var html = window.env.t('partySysText');
|
||||
showPopover('.user-menu', window.env.t('partySys'), html, 'bottom');
|
||||
});
|
||||
|
||||
$rootScope.$watch('user.flags.dropsEnabled', function(after, before) {
|
||||
@@ -130,20 +130,12 @@ angular.module('guideServices', []).
|
||||
if (!eggs) {
|
||||
eggs['Wolf'] = 1; // This is also set on the server
|
||||
}
|
||||
$rootScope.modals.dropsEnabled = true;
|
||||
});
|
||||
|
||||
$rootScope.$watch('user.items.pets', function(after, before) {
|
||||
if (User.user.achievements && User.user.achievements.beastMaster) return;
|
||||
if (before >= 90) {
|
||||
User.set({'achievements.beastMaster': true});
|
||||
$('#beastmaster-achievement-modal').modal('show'); // FIXME
|
||||
}
|
||||
$rootScope.openModal('dropsEnabled');
|
||||
});
|
||||
|
||||
$rootScope.$watch('user.flags.rebirthEnabled', function(after, before) {
|
||||
if (alreadyShown(before, after)) return;
|
||||
$rootScope.modals.rebirthEnabled = true;
|
||||
$rootScope.openModal('rebirthEnabled');
|
||||
});
|
||||
|
||||
|
||||
@@ -160,8 +152,8 @@ angular.module('guideServices', []).
|
||||
$timeout(function(){tour.goTo(0)});
|
||||
}),
|
||||
element: '.equipment-tab',
|
||||
title: "Class Gear",
|
||||
content: "First: don't panic! Your old gear is in your inventory, and you're now wearing your apprentice <strong>" + User.user.stats.class + "</strong> equipment. Wearing your class's gear grants you a 50% bonus to stats. However, feel free to switch back to your old gear."
|
||||
title: window.env.t('classGear'),
|
||||
content: window.env.t('classGearText', {klass: User.user.stats.class})
|
||||
},
|
||||
{
|
||||
path: '/#/options/profile/stats',
|
||||
@@ -169,21 +161,21 @@ angular.module('guideServices', []).
|
||||
$timeout(function(){tour.goTo(1)});
|
||||
}),
|
||||
element: ".allocate-stats",
|
||||
title: "Stats",
|
||||
content: "These are your class's stats, they affect the game-play. Each time you level up, you get one point to allocate to particular stat. Hover over each stat for more information.",
|
||||
title: window.env.t('stats'),
|
||||
content: window.env.t('classStats'),
|
||||
}, {
|
||||
element: ".auto-allocate",
|
||||
title: "Auto Allocate",
|
||||
title: window.env.t('autoAllocate'),
|
||||
placement: 'left',
|
||||
content: "If 'automatic allocation' is checked, your avatar gains stats automatically based on your tasks' attributes, which you can find in <strong>TASK > Edit > Advanced > Attributes</strong>. Eg, if you hit the gym often, and your 'Gym' Daily is set to 'Physical', you'll gain STR automatically.",
|
||||
content: window.env.t('autoAllocateText'),
|
||||
}, {
|
||||
element: ".meter.mana",
|
||||
title: "Spells",
|
||||
content: "You can now unlock class-specific spells. You'll see your first at level 11. Your mana replenishes 10 points per day, plus 1 point per completed <a target='_blank' href='http://habitrpg.wikia.com/wiki/Todos'>To-Do</a>."
|
||||
title: window.env.t('spells'),
|
||||
content: window.env.t('spellsText') + " <a target='_blank' href='http://habitrpg.wikia.com/wiki/Todos'>" + window.env.t('toDo') + "</a>."
|
||||
}, {
|
||||
orphan: true,
|
||||
title: "Read More",
|
||||
content: "For more information on the class-system, see <a href='http://habitrpg.wikia.com/wiki/Class_System' target='_blank'>Wikia</a>."
|
||||
title: window.env.t('readMore'),
|
||||
content: window.env.t('moreClass') + " <a href='http://habitrpg.wikia.com/wiki/Class_System' target='_blank'>Wikia</a>."
|
||||
}
|
||||
];
|
||||
_.each(tourSteps, function(step){
|
||||
|
||||
@@ -6,11 +6,11 @@ angular.module("notificationServices", [])
|
||||
function growl(html, type) {
|
||||
$.bootstrapGrowl(html, {
|
||||
ele: '#notification-area',
|
||||
type: type, //(null, 'text', 'error', 'success', 'gp', 'xp', 'hp', 'lvl', 'death', 'mp', 'crit')
|
||||
type: type || 'warning', //('info', 'text', 'warning', 'success', 'gp', 'xp', 'hp', 'lvl', 'death', 'mp', 'crit')
|
||||
top_offset: 20,
|
||||
align: 'right', //('left', 'right', or 'center')
|
||||
width: 250, //(integer, or 'auto')
|
||||
delay: 7000,
|
||||
delay: (type=='error') ? 0 : 7000,
|
||||
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 + " <i class='icon-gold'></i> " + silver + " <i class='icon-silver'></i>";
|
||||
return "" + gold + " <span class='notification-icon shop_gold'></span> " + silver + " <span class='notification-icon shop_silver'></span>";
|
||||
} else if (gold > 0) {
|
||||
return "" + gold + " <i class='icon-gold'></i>";
|
||||
return "" + gold + " <span class='notification-icon shop_gold'></span>";
|
||||
} else if (silver > 0) {
|
||||
return "" + silver + " <i class='icon-silver'></i>";
|
||||
return "" + silver + " <span class='notification-icon shop_silver'></span>";
|
||||
}
|
||||
};
|
||||
|
||||
@@ -45,11 +45,11 @@ angular.module("notificationServices", [])
|
||||
coins: coins,
|
||||
hp: function(val) {
|
||||
// don't show notifications if user dead
|
||||
growl("<i class='icon-heart'></i> " + sign(val) + " " + round(val) + " HP", 'hp');
|
||||
growl("<span class='glyphicon glyphicon-heart'></span> " + sign(val) + " " + round(val) + " " + window.env.t('hp'), 'hp');
|
||||
},
|
||||
exp: function(val) {
|
||||
if (val < -50) return; // don't show when they level up (resetting their exp)
|
||||
growl("<i class='icon-star'></i> " + sign(val) + " " + round(val) + " XP", 'xp');
|
||||
growl("<span class='glyphicon glyphicon-star'></span> " + sign(val) + " " + round(val) + " " + window.env.t('xp'), 'xp');
|
||||
},
|
||||
gp: function(val, bonus) {
|
||||
growl(sign(val) + " " + coins(val - bonus), 'gp');
|
||||
@@ -58,22 +58,19 @@ angular.module("notificationServices", [])
|
||||
growl(val);
|
||||
},
|
||||
lvl: function(){
|
||||
growl('<i class="icon-chevron-up"></i> Level Up!', 'lvl');
|
||||
},
|
||||
death: function(){
|
||||
growl("<i class='icon-death'></i> Respawn!", "death");
|
||||
growl('<span class="glyphicon glyphicon-chevron-up"></span> ' + window.env.t('levelUp'), 'lvl');
|
||||
},
|
||||
error: function(error){
|
||||
growl("<i class='icon-exclamation-sign'></i> " + error, "error");
|
||||
growl("<span class='glyphicon glyphicon-exclamation-sign'></span> " + error, "danger");
|
||||
},
|
||||
mp: function(val) {
|
||||
growl("<i class='icon-fire'></i> " + sign(val) + " " + round(val) + " MP", 'mp');
|
||||
growl("<span class='glyphicon glyphicon-fire'></span> " + sign(val) + " " + round(val) + " " + window.env.t('mp'), 'mp');
|
||||
},
|
||||
crit: function(val) {
|
||||
growl("<i class='icon-certificate'></i> Critical Hit! Bonus: " + Math.round(val) + "%", 'crit');
|
||||
growl("<span class='glyphicon glyphicon-certificate'></span> " + window.env.t('critBonus') + Math.round(val) + "%", 'crit');
|
||||
},
|
||||
drop: function(val) {
|
||||
growl("<i class='icon-gift'></i> " + val, 'drop');
|
||||
growl("<span class='glyphicon glyphicon-gift'></span> " + val, 'drop');
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -5,3 +5,22 @@ window.habitrpgStatic = angular.module('habitrpgStatic', ['notificationServices'
|
||||
.constant("STORAGE_USER_ID", 'habitrpg-user')
|
||||
.constant("STORAGE_SETTINGS_ID", 'habit-mobile-settings')
|
||||
.constant("MOBILE_APP", false)
|
||||
|
||||
habitrpgStatic.controller("PlansCtrl", ['$rootScope',
|
||||
function($rootScope) {
|
||||
$rootScope.clickContact = function(){
|
||||
window.ga && ga('send', 'event', 'button', 'click', 'Contact Us (Plans)');
|
||||
}
|
||||
}
|
||||
])
|
||||
.controller('AboutCtrl',[function(){
|
||||
$(document).ready(function(){
|
||||
$('a.gallery').colorbox({
|
||||
maxWidth: '90%',
|
||||
maxHeight: '80%',
|
||||
transition: 'none',
|
||||
scalePhotos:true
|
||||
//maxHeight: '70%'
|
||||
});
|
||||
});
|
||||
}])
|
||||
|
||||
@@ -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",
|
||||
@@ -10,7 +10,6 @@
|
||||
"bower_components/marked/lib/marked.js",
|
||||
"bower_components/angular-ui-router/release/angular-ui-router.js",
|
||||
"bower_components/angular-resource/angular-resource.min.js",
|
||||
"bower_components/angular-ui/build/angular-ui.js",
|
||||
"bower_components/angular-ui-utils/ui-utils.min.js",
|
||||
"bower_components/angular-loading-bar/build/loading-bar.js",
|
||||
"bower_components/Angular-At-Directive/src/at.js",
|
||||
@@ -21,10 +20,11 @@
|
||||
"bower_components/ngInfiniteScroll/ng-infinite-scroll.js",
|
||||
"bower_components/select2/select2.js",
|
||||
"bower_components/angular-ui-select2/src/select2.js",
|
||||
"bower_components/JavaScriptButtons/dist/paypal-button.min.js",
|
||||
|
||||
"bower_components/bootstrap/docs/assets/js/bootstrap.js",
|
||||
"bower_components/angular-bootstrap/ui-bootstrap.js",
|
||||
"bower_components/angular-bootstrap/ui-bootstrap-tpls.js",
|
||||
"bower_components/bootstrap/dist/js/bootstrap.js",
|
||||
|
||||
"bower_components/jquery-ui/ui/minified/jquery.ui.core.min.js",
|
||||
"bower_components/jquery-ui/ui/minified/jquery.ui.widget.min.js",
|
||||
@@ -33,6 +33,8 @@
|
||||
|
||||
"bower_components/habitrpg-shared/dist/habitrpg-shared.js",
|
||||
|
||||
"js/env.js",
|
||||
|
||||
"js/app.js",
|
||||
"js/services/sharedServices.js",
|
||||
"js/services/authServices.js",
|
||||
@@ -63,34 +65,33 @@
|
||||
"js/controllers/hallCtrl.js"
|
||||
],
|
||||
"css": [
|
||||
"bower_components/bootstrap/docs/assets/css/bootstrap.css",
|
||||
"bower_components/bootstrap/dist/css/bootstrap.css",
|
||||
"app.css",
|
||||
"bower_components/habitrpg-shared/dist/habitrpg-shared.css"
|
||||
]
|
||||
},
|
||||
"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/bootstrap/docs/assets/js/bootstrap.js",
|
||||
|
||||
"bower_components/angular-ui/build/angular-ui.js",
|
||||
"bower_components/angular-bootstrap/ui-bootstrap.js",
|
||||
"bower_components/angular-bootstrap/ui-bootstrap-tpls.js",
|
||||
"bower_components/bootstrap/dist/js/bootstrap.js",
|
||||
"bower_components/jquery-colorbox/jquery.colorbox-min.js",
|
||||
|
||||
"bower_components/angular-loading-bar/build/loading-bar.js",
|
||||
"js/env.js",
|
||||
"js/static.js",
|
||||
"js/services/notificationServices.js",
|
||||
"bower_components/habitrpg-shared/script/userServices.js",
|
||||
"js/controllers/authCtrl.js"
|
||||
"js/controllers/authCtrl.js",
|
||||
"js/controllers/footerCtrl.js"
|
||||
],
|
||||
"css": [
|
||||
"bower_components/bootstrap/docs/assets/css/bootstrap.css",
|
||||
"bower_components/bootstrap/docs/assets/css/bootstrap-responsive.css",
|
||||
"bower_components/bootstrap/docs/assets/css/docs.css",
|
||||
|
||||
"bower_components/bootstrap/dist/css/bootstrap.css",
|
||||
"bower_components/jquery-colorbox/example1/colorbox.css",
|
||||
"static.css"
|
||||
]
|
||||
}
|
||||
|
||||
|
After Width: | Height: | Size: 219 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 151 KiB |
|
After Width: | Height: | Size: 165 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 6.6 KiB |
|
After Width: | Height: | Size: 403 KiB |
|
After Width: | Height: | Size: 132 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 65 KiB |
|
After Width: | Height: | Size: 166 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
@@ -8,6 +8,7 @@ var async = require('async');
|
||||
var utils = require('../utils');
|
||||
var nconf = require('nconf');
|
||||
var User = require('../models/user').model;
|
||||
var ga = require('./../utils').ga;
|
||||
|
||||
var api = module.exports;
|
||||
|
||||
@@ -39,7 +40,7 @@ api.authWithSession = function(req, res, next) { //[todo] there is probably a mo
|
||||
if (!(req.session && req.session.userId))
|
||||
return res.json(401, NO_SESSION_FOUND);
|
||||
User.findOne({_id: uid}, function(err, user) {
|
||||
if (err) return res.json(500, {err: err});
|
||||
if (err) return next(err);
|
||||
if (_.isEmpty(user)) return res.json(401, NO_USER_FOUND);
|
||||
res.locals.user = user;
|
||||
next();
|
||||
@@ -88,6 +89,7 @@ api.registerUser = function(req, res, next) {
|
||||
};
|
||||
user = new User(newUser);
|
||||
user.save(cb);
|
||||
ga.event('register', 'Local').send()
|
||||
}
|
||||
], function(err, saved) {
|
||||
if (err) {
|
||||
@@ -107,15 +109,15 @@ api.loginLocal = function(req, res, next) {
|
||||
var password = req.body.password;
|
||||
if (!(username && password)) return res.json(401, {err:'Missing :username or :password in request body, please provide both'});
|
||||
User.findOne({'auth.local.username': username}, function(err, user){
|
||||
if (err) return res.json(500,{err:err});
|
||||
if (!user) return res.json(401, {err:"Username '" + username + "' not found. Usernames are case-sensitive, click 'Forgot Password' if you can't remember the capitalization."});
|
||||
if (err) return next(err);
|
||||
if (!user) return res.json(401, {err:"Username or password incorrect. Click 'Forgot Password' for help with either. (Note: usernames are case-sensitive)"});
|
||||
// We needed the whole user object first so we can get his salt to encrypt password comparison
|
||||
User.findOne({
|
||||
'auth.local.username': username,
|
||||
'auth.local.hashed_password': utils.encryptPassword(password, user.auth.local.salt)
|
||||
}, function(err, user){
|
||||
if (err) return res.json(500,{err:err});
|
||||
if (!user) return res.json(401,{err:'Incorrect password'});
|
||||
if (err) return next(err);
|
||||
if (!user) return res.json(401,{err:"Username or password incorrect. Click 'Forgot Password' for help with either. (Note: usernames are case-sensitive)"});
|
||||
res.json({id: user._id,token: user.apiToken});
|
||||
});
|
||||
});
|
||||
@@ -164,7 +166,7 @@ api.resetPassword = function(req, res, next){
|
||||
hashed_password = utils.encryptPassword(newPassword, salt);
|
||||
|
||||
User.findOne({'auth.local.email':email}, function(err, user){
|
||||
if (err) return res.json(500,{err:err});
|
||||
if (err) return next(err);
|
||||
if (!user) return res.send(500, {err:"Couldn't find a user registered for email " + email});
|
||||
user.auth.local.salt = salt;
|
||||
user.auth.local.hashed_password = hashed_password;
|
||||
@@ -187,18 +189,18 @@ api.changePassword = function(req, res, next) {
|
||||
confirmNewPassword = req.body.confirmNewPassword;
|
||||
|
||||
if (newPassword != confirmNewPassword)
|
||||
return res.json(500, {err: "Password & Confirm don't match"});
|
||||
return res.json(401, {err: "Password & Confirm don't match"});
|
||||
|
||||
var salt = user.auth.local.salt,
|
||||
hashed_old_password = utils.encryptPassword(oldPassword, salt),
|
||||
hashed_new_password = utils.encryptPassword(newPassword, salt);
|
||||
|
||||
if (hashed_old_password !== user.auth.local.hashed_password)
|
||||
return res.json(500, {err:"Old password doesn't match"});
|
||||
return res.json(401, {err:"Old password doesn't match"});
|
||||
|
||||
user.auth.local.hashed_password = hashed_new_password;
|
||||
user.save(function(err, saved){
|
||||
if (err) res.json(500,{err:err});
|
||||
if (err) next(err);
|
||||
res.send(200);
|
||||
})
|
||||
}
|
||||
@@ -250,8 +252,7 @@ api.setupPassport = function(router) {
|
||||
}
|
||||
});
|
||||
user.save(cb);
|
||||
|
||||
|
||||
ga.event('register', 'Facebook').send()
|
||||
}
|
||||
], function(err, saved){
|
||||
if (err) return res.redirect('/static/front?err=' + err);
|
||||
|
||||
@@ -7,6 +7,7 @@ var shared = require('habitrpg-shared');
|
||||
var User = require('./../models/user').model;
|
||||
var Group = require('./../models/group').model;
|
||||
var Challenge = require('./../models/challenge').model;
|
||||
var logging = require('./../logging');
|
||||
var csv = require('express-csv');
|
||||
var api = module.exports;
|
||||
|
||||
@@ -214,7 +215,7 @@ api.update = function(req, res){
|
||||
// Compare whether any changes have been made to tasks. If so, we'll want to sync those changes to subscribers
|
||||
if (before.isOutdated(req.body)) {
|
||||
User.find({_id: {$in: saved.members}}, function(err, users){
|
||||
console.log('Challenge updated, sync to subscribers');
|
||||
logging.info('Challenge updated, sync to subscribers');
|
||||
if (err) throw err;
|
||||
_.each(users, function(user){
|
||||
saved.syncToUser(user);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -13,7 +13,7 @@ api.ensureAdmin = function(req, res, next) {
|
||||
}
|
||||
|
||||
api.getHeroes = function(req,res,next) {
|
||||
User.find({'contributor.level':{$ne:null}})// {$exists:true} causes terrible performance http://goo.gl/GCxzC9
|
||||
User.find({'contributor.level':{$gt:0}})
|
||||
.select('contributor backer balance profile.name')
|
||||
.sort('-contributor.level')
|
||||
.exec(function(err, users){
|
||||
|
||||
@@ -10,8 +10,10 @@ var validator = require('validator');
|
||||
var check = validator.check;
|
||||
var sanitize = validator.sanitize;
|
||||
var User = require('./../models/user').model;
|
||||
var ga = require('./../utils').ga;
|
||||
var Group = require('./../models/group').model;
|
||||
var Challenge = require('./../models/challenge').model;
|
||||
var logging = require('./../logging');
|
||||
var acceptablePUTPaths;
|
||||
var api = module.exports;
|
||||
|
||||
@@ -33,7 +35,7 @@ api.getContent = function(req, res, next) {
|
||||
---------------
|
||||
*/
|
||||
|
||||
findTask = function(req, res) {
|
||||
findTask = function(req, res, next) {
|
||||
return task = res.locals.user.tasks[req.params.id];
|
||||
};
|
||||
|
||||
@@ -80,17 +82,32 @@ api.score = function(req, res, next) {
|
||||
var delta = user.ops.score({params:{id:task.id, direction:direction}});
|
||||
|
||||
user.save(function(err,saved){
|
||||
if (err) return res.json(500, {err: err});
|
||||
if (err) return next(err);
|
||||
// TODO this should be return {_v,task,stats,_tmp}, instead of merging everything togther at top-level response
|
||||
// However, this is the most commonly used API route, and changing it will mess with all 3rd party consumers. Bad idea :(
|
||||
res.json(200, _.extend({
|
||||
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';
|
||||
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();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -192,7 +209,7 @@ api.update = function(req, res, next) {
|
||||
});
|
||||
user.save(function(err) {
|
||||
if (!_.isEmpty(errors)) return res.json(401, {err: errors});
|
||||
if (err) return res.json(500, {err: err});
|
||||
if (err) return next(err);
|
||||
res.json(200, user);
|
||||
});
|
||||
};
|
||||
@@ -232,9 +249,9 @@ api.cron = function(req, res, next) {
|
||||
// api.reroll // Shared.ops
|
||||
// api.reset // Shared.ops
|
||||
|
||||
api['delete'] = function(req, res) {
|
||||
api['delete'] = function(req, res, next) {
|
||||
res.locals.user.remove(function(err){
|
||||
if (err) return res.json(500,{err:err});
|
||||
if (err) return next(err);
|
||||
res.send(200);
|
||||
})
|
||||
}
|
||||
@@ -253,11 +270,11 @@ api['delete'] = function(req, res) {
|
||||
------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
api.addTenGems = function(req, res) {
|
||||
api.addTenGems = function(req, res, next) {
|
||||
var user = res.locals.user;
|
||||
user.balance += 2.5;
|
||||
user.save(function(err){
|
||||
if (err) return res.json(500,{err:err});
|
||||
if (err) return next(err);
|
||||
res.send(204);
|
||||
})
|
||||
}
|
||||
@@ -267,7 +284,7 @@ api.addTenGems = function(req, res) {
|
||||
/*
|
||||
Setup Stripe response when posting payment
|
||||
*/
|
||||
api.buyGems = function(req, res) {
|
||||
api.buyGems = function(req, res, next) {
|
||||
var api_key = nconf.get('STRIPE_API_KEY');
|
||||
var stripe = require("stripe")(api_key);
|
||||
var token = req.body.id;
|
||||
@@ -300,8 +317,12 @@ api.buyGems = function(req, res) {
|
||||
dateUpdated: new Date,
|
||||
gemsBought: 0
|
||||
};
|
||||
ga.event('subscribe', 'Stripe').send()
|
||||
ga.transaction(response.id, 5).item(5, 1, "stripe-subscription", "Subscription > Stripe").send()
|
||||
} else {
|
||||
user.balance += 5;
|
||||
ga.event('checkout', 'Stripe').send()
|
||||
ga.transaction(response.id, 5).item(5, 1, "stripe-checkout", "Gems > Stripe").send()
|
||||
}
|
||||
user.save(cb);
|
||||
}
|
||||
@@ -311,7 +332,7 @@ api.buyGems = function(req, res) {
|
||||
});
|
||||
};
|
||||
|
||||
api.cancelSubscription = function(req, res) {
|
||||
api.cancelSubscription = function(req, res, next) {
|
||||
var api_key = nconf.get('STRIPE_API_KEY');
|
||||
var stripe = require("stripe")(api_key);
|
||||
var user = res.locals.user;
|
||||
@@ -330,6 +351,7 @@ api.cancelSubscription = function(req, res) {
|
||||
], function(err, saved){
|
||||
if (err) return res.send(500, err.toString()); // don't json this, let toString() handle errors
|
||||
res.send(200, saved);
|
||||
ga.event('unsubscribe', 'Stripe').send()
|
||||
});
|
||||
|
||||
}
|
||||
@@ -349,7 +371,9 @@ api.buyGemsPaypalIPN = function(req, res, next) {
|
||||
user.balance += 5;
|
||||
//user.purchased.ads = true;
|
||||
user.save();
|
||||
console.log('PayPal transaction completed and user updated');
|
||||
logging.info('PayPal transaction completed and user updated');
|
||||
ga.event('checkout', 'PayPal').send()
|
||||
ga.transaction(req.body.txn_id, 5).item(5, 1, "paypal-checkout", "Gems > PayPal").send()
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -369,7 +393,7 @@ api.buyGemsPaypalIPN = function(req, res, next) {
|
||||
Spells
|
||||
------------------------------------------------------------------------
|
||||
*/
|
||||
api.cast = function(req, res) {
|
||||
api.cast = function(req, res, next) {
|
||||
var user = res.locals.user;
|
||||
var targetType = req.query.targetType;
|
||||
var targetId = req.query.targetId;
|
||||
@@ -380,7 +404,7 @@ api.cast = function(req, res) {
|
||||
var done = function(){
|
||||
var err = arguments[0];
|
||||
var saved = _.size(arguments == 3) ? arguments[2] : arguments[1];
|
||||
if (err) return res.json(500, {err:err});
|
||||
if (err) return next(err);
|
||||
res.json(saved);
|
||||
}
|
||||
|
||||
@@ -400,7 +424,7 @@ api.cast = function(req, res) {
|
||||
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
|
||||
@@ -444,15 +468,15 @@ _.each(shared.wrap({}).ops, function(op,k){
|
||||
res.locals.user.ops[k](req,function(err, response){
|
||||
// If we want to send something other than 500, pass err as {code: 200, message: "Not enough GP"}
|
||||
if (err) {
|
||||
if (!err.code) return res.json(500,{err:err});
|
||||
if (!err.code) return next(err);
|
||||
if (err.code >= 400) return res.json(err.code,{err:err.message});
|
||||
// In the case of 200s, they're friendly alert messages like "You're pet has hatched!" - still send the op
|
||||
}
|
||||
res.locals.user.save(function(err){
|
||||
if (err) return res.json(500,{err:err});
|
||||
if (err) return next(err);
|
||||
res.json(200,response);
|
||||
})
|
||||
})
|
||||
}, ga);
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -472,28 +496,33 @@ api.batchUpdate = function(req, res, next) {
|
||||
var oldSend = res.send;
|
||||
var oldJson = res.json;
|
||||
|
||||
var callOp = function(_req, cb) {
|
||||
res.send = res.json = function(code, data) {
|
||||
if (_.isNumber(code) && code >= 500)
|
||||
return cb(code+": "+ (data.message ? data.message : data.err ? data.err : JSON.stringify(data)));
|
||||
return cb();
|
||||
};
|
||||
api[_req.op](_req, res);
|
||||
};
|
||||
// Stash user.save, we'll queue the save op till the end (so we don't overload the server)
|
||||
var oldSave = user.save;
|
||||
user.save = function(cb){cb(null,user)}
|
||||
|
||||
res.locals.ops = [];
|
||||
// Setup the array of functions we're going to call in parallel with async
|
||||
var ops = _.transform(req.body, function(result, _req) {
|
||||
if (!_.isEmpty(_req)) {
|
||||
result.push(function(cb) {
|
||||
res.locals.ops.push(_req);
|
||||
callOp(_req, cb);
|
||||
});
|
||||
}
|
||||
res.locals.ops = [];
|
||||
var ops = _.transform(req.body, function(m,_req){
|
||||
if (_.isEmpty(_req)) return;
|
||||
m.push(function() {
|
||||
var cb = arguments[arguments.length-1];
|
||||
res.locals.ops.push(_req);
|
||||
res.send = res.json = function(code, data) {
|
||||
if (_.isNumber(code) && code >= 500)
|
||||
return cb(code+": "+ (data.message ? data.message : data.err ? data.err : JSON.stringify(data)));
|
||||
return cb();
|
||||
};
|
||||
api[_req.op](_req, res, cb);
|
||||
});
|
||||
})
|
||||
// Finally, save user at the end
|
||||
.concat(function(){
|
||||
user.save = oldSave;
|
||||
user.save(arguments[arguments.length-1]);
|
||||
});
|
||||
|
||||
// call all the operations, then return the user object to the requester
|
||||
async.series(ops, function(err) {
|
||||
async.waterfall(ops, function(err,user) {
|
||||
res.json = oldJson;
|
||||
res.send = oldSend;
|
||||
if (err) return next(err);
|
||||
@@ -518,4 +547,4 @@ api.batchUpdate = function(req, res, next) {
|
||||
res.json(200, {_v: response._v});
|
||||
}
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
var nconf = require('nconf');
|
||||
var winston = require('winston');
|
||||
require('winston-mail').Mail;
|
||||
require('winston-newrelic');
|
||||
|
||||
var logger;
|
||||
|
||||
if (logger == null) {
|
||||
logger = new (winston.Logger)({});
|
||||
if (nconf.get('NODE_ENV') == 'production') {
|
||||
logger.add(winston.transports.newrelic, {});
|
||||
logger.add(winston.transports.Mail, {
|
||||
to: nconf.get('ADMIN_EMAIL') || nconf.get('SMTP_USER'),
|
||||
from: "HabitRPG <" + nconf.get('SMTP_USER') + ">",
|
||||
subject: "HabitRPG Error",
|
||||
host: nconf.get('SMTP_HOST'),
|
||||
port: nconf.get('SMTP_PORT'),
|
||||
tls: nconf.get('SMTP_TLS'),
|
||||
username: nconf.get('SMTP_USER'),
|
||||
password: nconf.get('SMTP_PASS'),
|
||||
level: 'error'
|
||||
});
|
||||
} else {
|
||||
logger.add(winston.transports.Console, {colorize:true});
|
||||
logger.add(winston.transports.File, {filename: 'habitrpg.log'});
|
||||
}
|
||||
}
|
||||
|
||||
// A custom log function that wraps Winston. Makes it easy to instrument code
|
||||
// and still possible to replace Winston in the future.
|
||||
module.exports.log = function(/* variable args */) {
|
||||
if (logger)
|
||||
logger.log.apply(logger, arguments);
|
||||
};
|
||||
|
||||
module.exports.info = function(/* variable args */) {
|
||||
if (logger)
|
||||
logger.info.apply(logger, arguments);
|
||||
};
|
||||
|
||||
module.exports.warn = function(/* variable args */) {
|
||||
if (logger)
|
||||
logger.warn.apply(logger, arguments);
|
||||
};
|
||||
|
||||
module.exports.error = function(/* variable args */) {
|
||||
if (logger)
|
||||
logger.error.apply(logger, arguments);
|
||||
};
|
||||
@@ -4,24 +4,57 @@ var fs = require('fs');
|
||||
var path = require('path');
|
||||
var User = require('./models/user').model
|
||||
var limiter = require('connect-ratelimit');
|
||||
var logging = require('./logging');
|
||||
var domainMiddleware = require('domain-middleware');
|
||||
var cluster = require('cluster');
|
||||
|
||||
module.exports.apiThrottle = function(app) {
|
||||
if (nconf.get('NODE_ENV') !== 'production') return;
|
||||
app.use(limiter({
|
||||
end:false,
|
||||
catagories:{
|
||||
normal: {
|
||||
// 2 req/s, but split as minutes
|
||||
totalRequests: 120,
|
||||
totalRequests: 80,
|
||||
every: 60000
|
||||
}
|
||||
}
|
||||
})).use(function(req,res,next){
|
||||
//console.log(res.ratelimit);
|
||||
//logging.info(res.ratelimit);
|
||||
if (res.ratelimit.exceeded) return res.json(429,{err:'Rate limit exceeded'});
|
||||
next();
|
||||
});
|
||||
}
|
||||
|
||||
module.exports.domainMiddleware = function(server,mongoose) {
|
||||
return domainMiddleware({
|
||||
server: {
|
||||
close:function(){
|
||||
server.close();
|
||||
mongoose.connection.close();
|
||||
}
|
||||
},
|
||||
killTimeout: 10000
|
||||
});
|
||||
}
|
||||
|
||||
module.exports.errorHandler = function(err, req, res, next) {
|
||||
//res.locals.domain.emit('error', err);
|
||||
// when we hit an error, send it to admin as an email. If no ADMIN_EMAIL is present, just send it to yourself (SMTP_USER)
|
||||
var stack = (err.stack ? err.stack : err.message ? err.message : err) +
|
||||
"\n ----------------------------\n" +
|
||||
"\n\noriginalUrl: " + req.originalUrl +
|
||||
"\n\nauth: " + req.headers['x-api-user'] + ' | ' + req.headers['x-api-key'] +
|
||||
"\n\nheaders: " + JSON.stringify(req.headers) +
|
||||
"\n\nbody: " + JSON.stringify(req.body) +
|
||||
(res.locals.ops ? "\n\ncompleted ops: " + JSON.stringify(res.locals.ops) : "");
|
||||
logging.error(stack);
|
||||
var message = err.message ? err.message : err;
|
||||
message = (message.length < 200) ? message : message.substring(0,100) + message.substring(message.length-100,message.length);
|
||||
res.json(500,{err:message}); //res.end(err.message);
|
||||
}
|
||||
|
||||
|
||||
module.exports.forceSSL = function(req, res, next){
|
||||
var baseUrl = nconf.get("BASE_URL");
|
||||
// Note x-forwarded-proto is used by Heroku & nginx, you'll have to do something different if you're not using those
|
||||
@@ -89,22 +122,21 @@ var getManifestFiles = function(page){
|
||||
|
||||
if(!files) throw new Error("Page not found!");
|
||||
|
||||
var css = '';
|
||||
|
||||
_.each(files.css, function(file){
|
||||
css += '<link rel="stylesheet" type="text/css" href="' + getBuildUrl(file) + '">';
|
||||
});
|
||||
var code = '';
|
||||
|
||||
if(nconf.get('NODE_ENV') === 'production'){
|
||||
return css + '<script type="text/javascript" src="' + getBuildUrl(page + '.js') + '"></script>';
|
||||
code += '<link rel="stylesheet" type="text/css" href="' + getBuildUrl(page + '.css') + '">';
|
||||
code += '<script type="text/javascript" src="' + getBuildUrl(page + '.js') + '"></script>';
|
||||
}else{
|
||||
var results = css;
|
||||
_.each(files.js, function(file){
|
||||
results += '<script type="text/javascript" src="' + getBuildUrl(file) + '"></script>';
|
||||
_.each(files.css, function(file){
|
||||
code += '<link rel="stylesheet" type="text/css" href="' + getBuildUrl(file) + '">';
|
||||
});
|
||||
_.each(files.js, function(file){
|
||||
code += '<script type="text/javascript" src="' + getBuildUrl(file) + '"></script>';
|
||||
});
|
||||
return results;
|
||||
}
|
||||
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
// Translations
|
||||
@@ -112,12 +144,12 @@ var getManifestFiles = function(page){
|
||||
var translations = {};
|
||||
|
||||
var loadTranslations = function(locale){
|
||||
var files = require(path.join(__dirname, "/../node_modules/habitrpg-shared/locales/", locale, 'app.json')).files;
|
||||
var files = fs.readdirSync(path.join(__dirname, "/../node_modules/habitrpg-shared/locales/", locale));
|
||||
translations[locale] = {};
|
||||
_.each(files, function(file){
|
||||
_.merge(translations[locale], require(path.join(__dirname, "/../node_modules/habitrpg-shared/locales/", locale, file)));
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// First fetch english so we can merge with missing strings in other languages
|
||||
loadTranslations('en');
|
||||
@@ -164,7 +196,6 @@ var getUserLanguage = function(req, callback){
|
||||
var acceptable = _(req.acceptedLanguages).map(function(lang){
|
||||
return lang.slice(0, 2);
|
||||
}).uniq().value();
|
||||
|
||||
var matches = _.intersection(acceptable, langCodes);
|
||||
return matches.length > 0 ? matches[0] : 'en';
|
||||
};
|
||||
@@ -176,44 +207,52 @@ var getUserLanguage = function(req, callback){
|
||||
return callback(null, _.find(avalaibleLanguages, {code: user.preferences.language}));
|
||||
}else{
|
||||
var langCode = getFromBrowser();
|
||||
if(user && translations[langCode]){
|
||||
user.preferences.language = langCode;
|
||||
user.save(); //callback?
|
||||
}
|
||||
// Because english is usually always avalaible as an acceptable language for the browser,
|
||||
// if the user visit the page when his own language is not avalaible yet
|
||||
// he'll have english set in his preferences, which is not good.
|
||||
//if(user && translations[langCode]){
|
||||
//user.preferences.language = langCode;
|
||||
//user.save(); //callback?
|
||||
//}
|
||||
return callback(null, _.find(avalaibleLanguages, {code: langCode}))
|
||||
}
|
||||
});
|
||||
}else{
|
||||
return callback(null, _.find(avalaibleLanguages, {code: getFromBrowser()}));
|
||||
return callback(null, _.find(avalaibleLanguages, {code: getFromBrowser()}));
|
||||
}
|
||||
}
|
||||
|
||||
module.exports.locals = function(req, res, next) {
|
||||
getUserLanguage(req, function(err, language){
|
||||
if(err) return res.json(500, {err: err});
|
||||
if(err) return res.json(500, {err: err});
|
||||
|
||||
var isStaticPage = req.url.split('/')[1] === 'static'; // If url contains '/static/'
|
||||
|
||||
// Load moment.js language file only when not on static pages
|
||||
language.momentLang = ((!isStaticPage && momentLangs[language.code])|| undefined);
|
||||
|
||||
language.momentLang = (momentLangs[language.code] || undefined);
|
||||
|
||||
res.locals.habitrpg = {
|
||||
NODE_ENV: nconf.get('NODE_ENV'),
|
||||
BASE_URL: nconf.get('BASE_URL'),
|
||||
PAYPAL_MERCHANT: nconf.get('PAYPAL_MERCHANT'),
|
||||
GA_ID: nconf.get("GA_ID"),
|
||||
IS_MOBILE: /Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(req.header('User-Agent')),
|
||||
STRIPE_PUB_KEY: nconf.get('STRIPE_PUB_KEY'),
|
||||
getManifestFiles: getManifestFiles,
|
||||
getBuildUrl: getBuildUrl,
|
||||
avalaibleLanguages: avalaibleLanguages,
|
||||
language: language,
|
||||
isStaticPage: isStaticPage,
|
||||
translations: translations[language.code],
|
||||
t: function(stringName, vars){
|
||||
var string = translations[language.code][stringName];
|
||||
if(!string) return _.template(translations[language.code].stringNotFound, {string: stringName});
|
||||
|
||||
return vars === undefined ? string : _.template(string, vars);
|
||||
return vars === undefined ? string : _.template(string, vars);
|
||||
},
|
||||
siteVersion: siteVersion
|
||||
}
|
||||
|
||||
next();
|
||||
next();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ var Schema = mongoose.Schema;
|
||||
var shared = require('habitrpg-shared');
|
||||
var _ = require('lodash');
|
||||
var TaskSchemas = require('./task');
|
||||
var Group = require('./group').model;
|
||||
|
||||
var ChallengeSchema = new Schema({
|
||||
_id: {type: String, 'default': shared.uuid},
|
||||
|
||||
@@ -3,7 +3,6 @@ var Schema = mongoose.Schema;
|
||||
var shared = require('habitrpg-shared');
|
||||
var _ = require('lodash');
|
||||
var async = require('async');
|
||||
var User = require('./user').model;
|
||||
|
||||
var GroupSchema = new Schema({
|
||||
_id: {type: String, 'default': shared.uuid},
|
||||
@@ -107,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){
|
||||
@@ -161,8 +171,6 @@ GroupSchema.methods.finishQuest = function(quest, cb) {
|
||||
})
|
||||
var members = _.keys(group.quest.members);
|
||||
group.quest = {};group.markModified('quest');
|
||||
// FIXME this is TERRIBLE practice. Looks like there are circular dependencies in the models, such that `var User` at
|
||||
// this point is undefined. So we get around that by loading from mongoose only once we get to this point
|
||||
mongoose.models.User.update({_id:{$in:members}}, updates, {multi:true}, cb);
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
@@ -68,7 +69,8 @@ var UserSchema = new Schema({
|
||||
level: Number, // 1-7, see https://trello.com/c/wkFzONhE/277-contributor-gear
|
||||
admin: Boolean,
|
||||
text: String, // Artisan, Friend, Blacksmith, etc
|
||||
contributions: String // a markdown textarea to list their contributions + links
|
||||
contributions: String, // a markdown textarea to list their contributions + links
|
||||
critical: String
|
||||
},
|
||||
|
||||
balance: {type: Number, 'default':0},
|
||||
@@ -135,10 +137,12 @@ 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 -------------------
|
||||
// -------------- Animals -------------------
|
||||
// Complex bit here. The result looks like:
|
||||
// pets: {
|
||||
// 'Wolf-Desert': 0, // 0 means does not own
|
||||
@@ -149,6 +153,8 @@ var UserSchema = new Schema({
|
||||
_.defaults(
|
||||
// First transform to a 1D eggs/potions mapping
|
||||
_.transform(shared.content.pets, function(m,v,k){ m[k] = Number; }),
|
||||
// Then add quest pets
|
||||
_.transform(shared.content.questPets, function(m,v,k){ m[k] = Number; }),
|
||||
// Then add additional pets (backer, contributor)
|
||||
_.transform(shared.content.specialPets, function(m,v,k){ m[k] = Number; })
|
||||
),
|
||||
@@ -180,6 +186,8 @@ var UserSchema = new Schema({
|
||||
mounts: _.defaults(
|
||||
// First transform to a 1D eggs/potions mapping
|
||||
_.transform(shared.content.pets, function(m,v,k){ m[k] = Boolean; }),
|
||||
// Then add quest pets
|
||||
_.transform(shared.content.questPets, function(m,v,k){ m[k] = Boolean; }),
|
||||
// Then add additional pets (backer, contributor)
|
||||
{
|
||||
'LionCub-Ethereal': Boolean,
|
||||
@@ -202,9 +210,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,
|
||||
@@ -240,7 +250,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,
|
||||
@@ -362,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;
|
||||
|
||||
@@ -6,6 +6,7 @@ var icalendar = require('icalendar');
|
||||
var api = require('./../controllers/user');
|
||||
var auth = require('./../controllers/auth');
|
||||
var middleware = require('../middleware');
|
||||
var logging = require('./../logging');
|
||||
|
||||
/* ---------- Deprecated API ------------*/
|
||||
|
||||
@@ -78,7 +79,7 @@ var batchUpdate = function(req, res, next) {
|
||||
req.body = action.data;
|
||||
res.send = res.json = function(code, data) {
|
||||
if (_.isNumber(code) && code >= 400) {
|
||||
console.error({
|
||||
logging.error({
|
||||
code: code,
|
||||
data: data
|
||||
});
|
||||
@@ -168,4 +169,4 @@ router.get('*', deprecated);
|
||||
router.post('*', deprecated);
|
||||
router.put('*', deprecated);
|
||||
|
||||
module.exports = router;
|
||||
module.exports = router;
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -18,9 +18,7 @@ router.get('/', middleware.locals, function(req, res) {
|
||||
// -------- Marketing --------
|
||||
|
||||
router.get('/static/front', middleware.locals, function(req, res) {
|
||||
var env = res.locals.habitrpg;
|
||||
env.isFrontPage = true;
|
||||
res.render('static/front', {env: env});
|
||||
res.render('static/front', {env: res.locals.habitrpg});
|
||||
});
|
||||
|
||||
router.get('/static/privacy', middleware.locals, function(req, res) {
|
||||
@@ -39,6 +37,10 @@ router.get('/static/about', middleware.locals, function(req, res) {
|
||||
res.render('static/about', {env: res.locals.habitrpg});
|
||||
});
|
||||
|
||||
router.get('/static/videos', middleware.locals, function(req, res) {
|
||||
res.render('static/videos', {env: res.locals.habitrpg});
|
||||
});
|
||||
|
||||
router.get('/static/contact', middleware.locals, function(req, res) {
|
||||
res.render('static/contact', {env: res.locals.habitrpg});
|
||||
});
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
require('coffee-script') // for habitrpg-shared
|
||||
var nconf = require('nconf');
|
||||
var utils = require('./utils');
|
||||
var logging = require('./logging');
|
||||
utils.setupConfig();
|
||||
var async = require('async');
|
||||
var mongoose = require('mongoose');
|
||||
@@ -15,7 +16,7 @@ async.waterfall([
|
||||
Group.findById('habitrpg', cb);
|
||||
},
|
||||
function(tavern, cb){
|
||||
console.log({tavern:tavern,cb:cb});
|
||||
logging.info({tavern:tavern,cb:cb});
|
||||
if (!tavern) {
|
||||
tavern = new Group({
|
||||
_id: 'habitrpg',
|
||||
@@ -31,6 +32,6 @@ async.waterfall([
|
||||
}
|
||||
],function(err){
|
||||
if (err) throw err;
|
||||
console.log("Done initializing database");
|
||||
logging.info("Done initializing database");
|
||||
mongoose.disconnect();
|
||||
})
|
||||
|
||||
@@ -4,19 +4,19 @@ var _ = require('lodash');
|
||||
var nconf = require('nconf');
|
||||
var utils = require('./utils');
|
||||
utils.setupConfig();
|
||||
|
||||
var logging = require('./logging');
|
||||
var isProd = nconf.get('NODE_ENV') === 'production';
|
||||
var isDev = nconf.get('NODE_ENV') === 'development';
|
||||
|
||||
if (cluster.isMaster && (isDev || isProd)) {
|
||||
// Fork workers.
|
||||
_.times(require('os').cpus().length, function(){
|
||||
_.times(_.min([require('os').cpus().length,2]), function(){
|
||||
cluster.fork();
|
||||
})
|
||||
});
|
||||
|
||||
cluster.on('exit', function(worker, code, signal) {
|
||||
cluster.on('disconnect', function(worker, code, signal) {
|
||||
var w = cluster.fork(); // replace the dead worker
|
||||
console.error('[%s] [master:%s] worker:%s disconnect! new worker:%s fork', new Date(), process.pid, worker.process.pid, w.process.pid);
|
||||
logging.info('[%s] [master:%s] worker:%s disconnect! new worker:%s fork', new Date(), process.pid, worker.process.pid, w.process.pid);
|
||||
});
|
||||
|
||||
} else {
|
||||
@@ -24,7 +24,6 @@ if (cluster.isMaster && (isDev || isProd)) {
|
||||
var express = require("express");
|
||||
var http = require("http");
|
||||
var path = require("path");
|
||||
var domainMiddleware = require('domain-middleware');
|
||||
var swagger = require("swagger-node-express");
|
||||
|
||||
var middleware = require('./middleware');
|
||||
@@ -35,14 +34,18 @@ if (cluster.isMaster && (isDev || isProd)) {
|
||||
|
||||
// ------------ MongoDB Configuration ------------
|
||||
mongoose = require('mongoose');
|
||||
require('./models/user'); //load up the user schema - TODO is this necessary?
|
||||
require('./models/group');
|
||||
require('./models/challenge');
|
||||
mongoose.connect(nconf.get('NODE_DB_URI'), {auto_reconnect:true}, function(err) {
|
||||
if (err) throw err;
|
||||
console.info('Connected with Mongoose');
|
||||
var mongooseOptions = !isProd ? {} : {
|
||||
replset: { socketOptions: { keepAlive: 1, connectTimeoutMS: 30000 } },
|
||||
server: { socketOptions: { keepAlive: 1, connectTimeoutMS: 30000 } }
|
||||
};
|
||||
mongoose.connect(nconf.get('NODE_DB_URI'), mongooseOptions, function(err) {
|
||||
if (err) throw err;
|
||||
logging.info('Connected with Mongoose');
|
||||
});
|
||||
|
||||
// load schemas & models
|
||||
require('./models/challenge');
|
||||
require('./models/group');
|
||||
require('./models/user');
|
||||
|
||||
// ------------ Passport Configuration ------------
|
||||
var passport = require('passport')
|
||||
@@ -63,7 +66,6 @@ if (cluster.isMaster && (isDev || isProd)) {
|
||||
done(null, obj);
|
||||
});
|
||||
|
||||
|
||||
// Use the FacebookStrategy within Passport.
|
||||
// Strategies in Passport require a `verify` function, which accept
|
||||
// credentials (in this case, an accessToken, refreshToken, and Facebook
|
||||
@@ -88,14 +90,9 @@ if (cluster.isMaster && (isDev || isProd)) {
|
||||
|
||||
// ------------ Server Configuration ------------
|
||||
|
||||
domainMiddleware({
|
||||
server: server,
|
||||
killTimeout: 3000
|
||||
}),
|
||||
|
||||
app.set("port", nconf.get('PORT'));
|
||||
|
||||
middleware.apiThrottle(app);
|
||||
app.use(middleware.domainMiddleware(server,mongoose));
|
||||
if (!isProd) app.use(express.logger("dev"));
|
||||
app.use(express.compress());
|
||||
app.set("views", __dirname + "/../views");
|
||||
@@ -119,14 +116,11 @@ 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")));
|
||||
|
||||
// development only
|
||||
//if ("development" === app.get("env")) {
|
||||
// app.use(express.errorHandler());
|
||||
//}
|
||||
|
||||
// Custom Directives
|
||||
app.use(require('./routes/pages').middleware);
|
||||
app.use(require('./routes/auth').middleware);
|
||||
@@ -134,15 +128,13 @@ if (cluster.isMaster && (isDev || isProd)) {
|
||||
app.use('/api/v2', v2);
|
||||
app.use('/api/v1', require('./routes/apiv1').middleware);
|
||||
app.use('/export', require('./routes/dataexport').middleware);
|
||||
|
||||
app.use(utils.errorHandler);
|
||||
|
||||
require('./routes/apiv2.coffee')(swagger, v2);
|
||||
app.use(middleware.errorHandler);
|
||||
|
||||
server.on('request', app);
|
||||
server.listen(app.get("port"), function() {
|
||||
return console.log("Express server listening on port " + app.get("port"));
|
||||
return logging.info("Express server listening on port " + app.get("port"));
|
||||
});
|
||||
|
||||
module.exports = server;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ var nconf = require('nconf');
|
||||
var crypto = require('crypto');
|
||||
var path = require("path");
|
||||
|
||||
module.exports.ga = undefined; // set Google Analytics on nconf init
|
||||
|
||||
module.exports.sendEmail = function(mailData) {
|
||||
var smtpTransport = nodemailer.createTransport("SMTP",{
|
||||
service: nconf.get('SMTP_SERVICE'),
|
||||
@@ -12,8 +14,9 @@ module.exports.sendEmail = function(mailData) {
|
||||
}
|
||||
});
|
||||
smtpTransport.sendMail(mailData, function(error, response){
|
||||
if(error) console.log(error);
|
||||
else console.log("Message sent: " + response.message);
|
||||
var logging = require('./logging');
|
||||
if(error) logging.error(error);
|
||||
else logging.info("Message sent: " + response.message);
|
||||
smtpTransport.close(); // shut down the connection pool, no more messages
|
||||
});
|
||||
}
|
||||
@@ -31,8 +34,6 @@ module.exports.makeSalt = function() {
|
||||
return crypto.randomBytes(Math.ceil(len / 2)).toString('hex').substring(0, len);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Load nconf and define default configuration values if config.json or ENV vars are not found
|
||||
*/
|
||||
@@ -42,42 +43,10 @@ module.exports.setupConfig = function(){
|
||||
//.file('defaults', path.join(path.resolve(__dirname, '../config.json.example')))
|
||||
.file('user', path.join(path.resolve(__dirname, '../config.json')));
|
||||
|
||||
// var agent;
|
||||
// if (process.env.NODE_ENV === 'development') {
|
||||
// // Follow these instructions for profiling / debugging leaks
|
||||
// // * https://developers.google.com/chrome-developer-tools/docs/heap-profiling
|
||||
// // * https://developers.google.com/chrome-developer-tools/docs/memory-analysis-101
|
||||
// agent = require('webkit-devtools-agent');
|
||||
// console.log("To debug memory leaks:" +
|
||||
// "\n\t(1) Run `kill -SIGUSR2 " + process.pid + "`" +
|
||||
// "\n\t(2) open http://c4milo.github.com/node-webkit-agent/21.0.1180.57/inspector.html?host=localhost:1337&page=0");
|
||||
// }
|
||||
|
||||
if (nconf.get('NODE_ENV') === "development") {
|
||||
if (nconf.get('NODE_ENV') === "development")
|
||||
Error.stackTraceLimit = Infinity;
|
||||
}
|
||||
if (nconf.get('NODE_ENV') === 'production') require('newrelic');
|
||||
};
|
||||
if (nconf.get('NODE_ENV') === 'production')
|
||||
require('newrelic');
|
||||
|
||||
|
||||
module.exports.errorHandler = function(err, req, res, next) {
|
||||
// when we hit an error, send it to admin as an email. If no ADMIN_EMAIL is present, just send it to yourself (SMTP_USER)
|
||||
var stack = (err.stack ? err.stack : err.message ? err.message : err) +
|
||||
"\n ----------------------------\n" +
|
||||
"\n\noriginalUrl: " + req.originalUrl +
|
||||
"\n\nauth: " + req.headers['x-api-user'] + ' | ' + req.headers['x-api-key'] +
|
||||
"\n\nheaders: " + JSON.stringify(req.headers) +
|
||||
"\n\nbody: " + JSON.stringify(req.body) +
|
||||
(res.locals.ops ? "\n\ncompleted ops: " + JSON.stringify(res.locals.ops) : "");
|
||||
module.exports.sendEmail({
|
||||
from: "HabitRPG <" + nconf.get('SMTP_USER') + ">",
|
||||
to: nconf.get('ADMIN_EMAIL') || nconf.get('SMTP_USER'),
|
||||
subject: "HabitRPG Error",
|
||||
text: stack
|
||||
});
|
||||
console.error(stack);
|
||||
var message = err.message ? err.message : err;
|
||||
message = (message.length < 200) ? message : message.substring(0,100) + message.substring(message.length-100,message.length);
|
||||
res.json(500,{err:message}); //res.end(err.message);
|
||||
process.exit(0);
|
||||
}
|
||||
module.exports.ga = require('universal-analytics')(nconf.get('GA_ID'));
|
||||
};
|
||||
@@ -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();
|
||||
|
||||
@@ -3,43 +3,34 @@ doctype 5
|
||||
html(ng-app="habitrpg", ng-controller="RootCtrl", ng-class='{"applying-action":applyingAction}', ui-keyup="{27:'castCancel()'}")
|
||||
head
|
||||
title=env.t('titleIndex')
|
||||
|
||||
// ?v=1 needed to force refresh
|
||||
link(rel='shortcut icon', href='#{env.getBuildUrl("favicon.ico")}?v=2')
|
||||
link(rel='shortcut icon', href='#{env.getBuildUrl("favicon.ico")}?v=3')
|
||||
|
||||
meta(charset='utf-8')
|
||||
meta(name='viewport', content='width=device-width, initial-scale=1.0')
|
||||
meta(name='apple-mobile-web-app-capable', content='yes')
|
||||
|
||||
script(type='text/javascript').
|
||||
window.env = !{JSON.stringify(env)};
|
||||
|
||||
style.
|
||||
[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
|
||||
display: none;
|
||||
}
|
||||
|
||||
!= env.getManifestFiles("app")
|
||||
|
||||
//webfonts
|
||||
link(href='//fonts.googleapis.com/css?family=Lato:300,400,700,400italic,700italic', rel='stylesheet', type='text/css')
|
||||
meta(name='viewport', content='width=device-width')
|
||||
meta(name='apple-mobile-web-app-capable', content='yes')
|
||||
|
||||
body(ng-cloak)
|
||||
div(ng-controller='GroupsCtrl')
|
||||
include ./shared/modals/index
|
||||
include ./shared/header/header
|
||||
|
||||
include ./shared/tasks/lists
|
||||
include ./main/index
|
||||
include ./options/index
|
||||
|
||||
#notification-area(ng-controller='NotificationCtrl')
|
||||
#wrap
|
||||
|
||||
//if they hide the header, we still need user-menu visible
|
||||
div(ng-if='user.preferences.hideHeader')
|
||||
include ./shared/header/menu
|
||||
|
||||
.exp-chart(ng-show='charts.exp')
|
||||
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
|
||||
.row
|
||||
.col-md-12.exp-chart(ng-show='charts.exp')
|
||||
#main(ui-view)
|
||||
|
||||
include ./shared/footer
|
||||
include ./shared/footer
|
||||
@@ -1,26 +1,29 @@
|
||||
.filters.tag-list(ng-controller='FiltersCtrl')
|
||||
.pull-left.filter-description
|
||||
=env.t('tags')
|
||||
|:
|
||||
ul.nav.nav-pills
|
||||
li
|
||||
a(rel='tooltip', title=env.t('editTags'), ng-click='saveOrEdit()')
|
||||
i(ng-class='{"icon-ok": _editing, "icon-pencil": !_editing}')
|
||||
li(bindonce='user.tags', ng-class='{active: user.filters[tag.id]}', ng-repeat='tag in user.tags', style='position: relative;')
|
||||
.input-append.option-group.tag-editing(ng-show='_editing')
|
||||
input.input.input-small.option-content.tag-editing-pill(type='text', ng-model='tag.name')
|
||||
span.add-on.tag-editing-pill
|
||||
a.pull-right(ng-click='user.ops.deleteTag({params:{id:tag.id}})')
|
||||
i.icon-trash
|
||||
a(ng-hide='_editing', ng-click='toggleFilter(tag)')
|
||||
i.icon-bullhorn(bo-if="tag.challenge")
|
||||
markdown(ng-model='tag.name',style='display: inline-block')
|
||||
li
|
||||
form.form-inline(ng-show='_editing', ng-submit='createTag(_newTag)')
|
||||
.input-append.tag-editing
|
||||
input.span2.tag-editing-pill(type='text', ng-model='_newTag', placeholder=env.t('newTag'))
|
||||
button.add-on.tag-editing-pill(type='submit')=env.t('add')
|
||||
// <li class="{#unless activeFilters(users[_userId].filters)}hidden{/}">
|
||||
li
|
||||
a(rel='tooltip', title=env.t('clearFilters'), ng-click='user.filters = {}')
|
||||
i.icon-remove-sign
|
||||
.container-fluid
|
||||
.row
|
||||
.filters.col-md-12(ng-controller='FiltersCtrl')
|
||||
.pull-left.filter-description
|
||||
=env.t('tags')
|
||||
|:
|
||||
ul.nav.nav-pills
|
||||
li
|
||||
a(rel='tooltip', title=env.t('editTags'), ng-click='saveOrEdit()')
|
||||
span.glyphicon(ng-class='{"glyphicon-ok": _editing, "glyphicon-pencil": !_editing}')
|
||||
li(bindonce='user.tags', ng-class='{active: user.filters[tag.id]}', ng-repeat='tag in user.tags')
|
||||
.input-group(ng-show='_editing')
|
||||
input.form-control.input-sm(type='text', ng-model='tag.name')
|
||||
span.input-group-addon
|
||||
a(ng-click='user.ops.deleteTag({params:{id:tag.id}})')
|
||||
span.glyphicon.glyphicon-trash
|
||||
a(ng-hide='_editing', ng-click='toggleFilter(tag)')
|
||||
span.glyphicon.glyphicon-bullhorn(bo-if="tag.challenge")
|
||||
markdown(ng-model='tag.name')
|
||||
li
|
||||
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(ng-click='createTag(_newTag)')
|
||||
=env.t('add')
|
||||
// <li class="{#unless activeFilters(users[_userId].filters)}hidden{/}">
|
||||
li
|
||||
a(rel='tooltip', title=env.t('clearFilters'), ng-click='user.filters = {}')
|
||||
span.glyphicon.glyphicon-remove-sign
|
||||
|
||||
@@ -4,29 +4,34 @@ include ./inventory/index
|
||||
include ./settings
|
||||
|
||||
script(id='partials/options.html', type="text/ng-template")
|
||||
.grid
|
||||
.module.full-width
|
||||
span.option-box.pull-right.wallet
|
||||
include ../shared/gems
|
||||
.container-fluid
|
||||
.row
|
||||
.col-md-12
|
||||
span.option-box.pull-right.wallet
|
||||
include ../shared/gems
|
||||
|
||||
ul.nav.nav-tabs
|
||||
li(ng-class="{ active: $state.includes('options.profile') }")
|
||||
a(ui-sref='options.profile')
|
||||
i.icon-user
|
||||
=env.t('profile')
|
||||
li(ng-class="{ active: $state.includes('options.social') }")
|
||||
a(ui-sref='options.social')
|
||||
i.icon-heart
|
||||
=env.t('social')
|
||||
li(ng-class="{ active: $state.includes('options.inventory') }", ng-if='user.flags.dropsEnabled')
|
||||
a(ui-sref='options.inventory')
|
||||
i.icon-gift
|
||||
=env.t('inventory')
|
||||
li(ng-class="{ active: $state.includes('options.settings') }")
|
||||
a(ui-sref='options.settings')
|
||||
i.icon-wrench
|
||||
=env.t('settings')
|
||||
ul.nav.nav-tabs
|
||||
li(ng-class="{ active: $state.includes('options.profile') }")
|
||||
a(ui-sref='options.profile')
|
||||
span.glyphicon.glyphicon-user
|
||||
|
|
||||
=env.t('profile')
|
||||
li(ng-class="{ active: $state.includes('options.social') }")
|
||||
a(ui-sref='options.social')
|
||||
span.glyphicon.glyphicon-heart
|
||||
|
|
||||
=env.t('social')
|
||||
li(ng-class="{ active: $state.includes('options.inventory') }", ng-if='user.flags.dropsEnabled')
|
||||
a(ui-sref='options.inventory')
|
||||
span.glyphicon.glyphicon-gift
|
||||
|
|
||||
=env.t('inventory')
|
||||
li(ng-class="{ active: $state.includes('options.settings') }")
|
||||
a(ui-sref='options.settings')
|
||||
span.glyphicon.glyphicon-wrench
|
||||
|
|
||||
=env.t('settings')
|
||||
|
||||
.tab-content
|
||||
.tab-pane.active
|
||||
div(ui-view)
|
||||
.tab-content
|
||||
.tab-pane.active
|
||||
div(ui-view)
|
||||
|
||||
@@ -1,145 +1,161 @@
|
||||
script(type='text/ng-template', id='partials/options.inventory.equipment.html')
|
||||
.row-fluid
|
||||
.span6.border-right
|
||||
h3=env.t('battleGear')
|
||||
small=env.t('battleGearText')
|
||||
li.customize-menu.inventory-gear
|
||||
menu.pets-menu(label='{{label}}', ng-repeat='(klass,label) in {base:"Base", warrior:"Warrior", wizard:"Mage", rogue:"Rogue", healer:"Healer", special:"Special"}', ng-show='gear[klass]')
|
||||
div(ng-repeat='item in gear[klass]')
|
||||
button.customize-option(popover='{{item.notes}}', popover-title='{{item.text}}', popover-trigger='mouseenter', popover-placement='right', ng-click='user.ops.equip({params:{key:item.key}})', class='shop_{{item.key}}', ng-class='{selectableInventory: user.items.gear.equipped[item.type] == item.key}')
|
||||
.span6
|
||||
h3=env.t('costume')
|
||||
small=env.t('costumeText')
|
||||
br
|
||||
label.checkbox.inline
|
||||
input(type="checkbox", ng-model="user.preferences.costume", ng-click='set({"preferences.costume":!user.preferences.costume})')
|
||||
=env.t('useCostume')
|
||||
li.customize-menu(ng-if='user.preferences.costume')
|
||||
menu.pets-menu(label='{{label}}', ng-repeat='(klass,label) in {base:"Base", warrior:"Warrior", wizard:"Mage", rogue:"Rogue", healer:"Healer", special:"Special"}', ng-show='gear[klass]')
|
||||
div(ng-repeat='item in gear[klass]')
|
||||
button.customize-option(popover='{{item.notes}}', popover-title='{{item.text}}', popover-trigger='mouseenter', popover-placement='right', ng-click='user.ops.equip({params:{type:"costume", key:item.key}})', class='shop_{{item.key}}', ng-class='{selectableInventory: user.items.gear.costume[item.type] == item.key}')
|
||||
.container-fluid
|
||||
.row
|
||||
.col-md-6.border-right
|
||||
h3.equipment-title=env.t('battleGear')
|
||||
|
||||
.glyphicon.glyphicon-question-sign(popover-trigger='mouseenter', popover-placement='right', popover=env.t('battleGearText'))
|
||||
li.customize-menu.inventory-gear
|
||||
menu.pets-menu(label='{{label}}', ng-repeat='(klass,label) in {base:"Base", warrior:"Warrior", wizard:"Mage", rogue:"Rogue", healer:"Healer", special:"Special"}', ng-show='gear[klass]')
|
||||
div(ng-repeat='item in gear[klass]')
|
||||
button.customize-option(popover='{{item.notes}}', popover-title='{{item.text}}', popover-trigger='mouseenter', popover-placement='right', ng-click='user.ops.equip({params:{key:item.key}})', class='shop_{{item.key}}', ng-class='{selectableInventory: user.items.gear.equipped[item.type] == item.key}')
|
||||
.col-md-6
|
||||
h3.equipment-title=env.t('costume')
|
||||
|
||||
i.icon-question-sign(popover-trigger='mouseenter', popover-placement='right', popover=env.t('costumeText'))
|
||||
.checkbox
|
||||
label
|
||||
input(type="checkbox", ng-model="user.preferences.costume", ng-click='set({"preferences.costume":!user.preferences.costume})')
|
||||
|
|
||||
=env.t('useCostume')
|
||||
li.customize-menu(ng-if='user.preferences.costume')
|
||||
menu.pets-menu(label='{{label}}', ng-repeat='(klass,label) in {base:"Base", warrior:"Warrior", wizard:"Mage", rogue:"Rogue", healer:"Healer", special:"Special"}', ng-show='gear[klass]')
|
||||
div(ng-repeat='item in gear[klass]')
|
||||
button.customize-option(popover='{{item.notes}}', popover-title='{{item.text}}', popover-trigger='mouseenter', popover-placement='right', ng-click='user.ops.equip({params:{type:"costume", key:item.key}})', class='shop_{{item.key}}', ng-class='{selectableInventory: user.items.gear.costume[item.type] == item.key}')
|
||||
|
||||
script(type='text/ng-template', id='partials/options.inventory.drops.html')
|
||||
.row-fluid
|
||||
.span6.border-right
|
||||
h2=env.t('inventory')
|
||||
p.well=env.t('inventoryText')
|
||||
menu.inventory-list(type='list')
|
||||
|
||||
li.customize-menu
|
||||
menu.pets-menu(label=(env.t('eggs') + ' ({{eggCount}})'))
|
||||
p.muted(ng-show='eggCount < 1')=env.t('noEggs')
|
||||
div(ng-repeat='(egg,points) in ownedItems(user.items.eggs)')
|
||||
//TODO move positioning this styling to css
|
||||
button.customize-option(popover='{{Content.eggs[egg].notes}}', popover-title='{{Content.eggs[egg].text}} Egg', popover-trigger='mouseenter', popover-placement='right', ng-click='chooseEgg(egg)', class='Pet_Egg_{{egg}}', ng-class='{selectableInventory: selectedPotion && !(user.items.pets[egg+"-"+selectedPotion.key]>0)}')
|
||||
.badge.badge-info.stack-count {{points}}
|
||||
//-p {{Content.eggs[egg].text}}
|
||||
|
||||
li.customize-menu
|
||||
menu.hatchingPotion-menu(label=(env.t('hatchingPotions') + ' ({{potCount}})'))
|
||||
p.muted(ng-show='potCount < 1')=env.t('noHatchingPotions')
|
||||
div(ng-repeat='(pot,points) in ownedItems(user.items.hatchingPotions)')
|
||||
button.customize-option(popover='{{Content.hatchingPotions[pot].notes}}', popover-title='{{Content.hatchingPotions[pot].text}} Potion', popover-trigger='mouseenter', popover-placement='right', ng-click='choosePotion(pot)', class='Pet_HatchingPotion_{{pot}}', ng-class='{selectableInventory: selectedEgg && !(user.items.pets[selectedEgg.key+"-"+pot]>0)}')
|
||||
.badge.badge-info.stack-count {{points}}
|
||||
|
||||
li.customize-menu
|
||||
menu.pets-menu(label=(env.t('scrolls') + ' ({{questCount}})'))
|
||||
p.muted(ng-show='questCount < 1')=env.t('noScrolls')
|
||||
p.muted!=env.t('scrollsText1') + ' <a href="/#/options/groups/party">' + env.t('scrollsText2') + '</a>'
|
||||
div(ng-repeat='(quest_key,points) in ownedItems(user.items.quests)', ng-init='quest = Content.quests[quest_key]')
|
||||
button.customize-option(popover="{{quest.previous && !user.achievements.quests[quest.previous] ? env.t('scrollsPre') : quest.notes | htmlDecode}}", popover-title='{{quest.text}}', popover-trigger='mouseenter', popover-placement='right', ng-click='showQuest(quest_key)', class='inventory_quest_scroll', ng-class='{locked: quest.previous && !user.achievements.quests[quest.previous]}')
|
||||
.badge.badge-info.stack-count {{points}}
|
||||
|
||||
li.customize-menu
|
||||
menu.pets-menu(label=env.t('food') + ' ({{foodCount}})')
|
||||
p(ng-show='foodCount < 1')=env.t('noFood')
|
||||
div(ng-repeat='(food,points) in ownedItems(user.items.food)')
|
||||
button.customize-option(popover='{{Content.food[food].notes}}', popover-title='{{Content.food[food].text}}', popover-trigger='mouseenter', popover-placement='right', ng-click='chooseFood(food)', class='Pet_Food_{{food}}')
|
||||
.badge.badge-info.stack-count {{points}}
|
||||
|
||||
li.customize-menu(ng-if='user.items.special.snowball')
|
||||
menu.pets-menu(label=env.t('special'))
|
||||
div
|
||||
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}}
|
||||
|
||||
.span6
|
||||
h2=env.t('market')
|
||||
.row-fluid
|
||||
table.npc_alex_container
|
||||
tr
|
||||
td
|
||||
.npc_alex.pull-left
|
||||
td
|
||||
.popover.static-popover.fade.right.in
|
||||
.arrow
|
||||
h3.popover-title
|
||||
a(target='_blank', href='http://www.kickstarter.com/profile/523661924')=env.t('alexander')
|
||||
.popover-content
|
||||
p=env.t('welcomeMarket')
|
||||
p
|
||||
button.btn.btn-primary(ng-show='selectedEgg', ng-click='sellInventory()')=env.t('sellForGold', {item: "{{selectedEgg.text}}", gold: "{{selectedEgg.value}}"})
|
||||
button.btn.btn-primary(ng-show='selectedPotion', ng-click='sellInventory()')=env.t('sellForGold', {item: "{{selectedPotion.text}}", gold: "{{selectedPotion.value}}"})
|
||||
button.btn.btn-primary(ng-show='selectedFood', ng-click='sellInventory()')=env.t('sellForGold', {item: "{{selectedFood.text}}", gold: "{{selectedFood.value}}"})
|
||||
.container-fluid
|
||||
.row
|
||||
.col-md-6.border-right
|
||||
h2=env.t('inventory')
|
||||
p.well=env.t('inventoryText')
|
||||
menu.inventory-list(type='list')
|
||||
li.customize-menu
|
||||
menu.pets-menu(label=env.t('eggs'))
|
||||
div(ng-repeat='egg in Content.eggs', ng-if='egg.canBuy')
|
||||
button.customize-option(popover='{{egg.notes}}', popover-title='{{egg.text}} Egg', popover-trigger='mouseenter', popover-placement='left', ng-click='purchase("eggs", egg)', class='Pet_Egg_{{egg.key}}')
|
||||
p
|
||||
| {{egg.value}}
|
||||
span.Pet_Currency_Gem1x.inline-gems
|
||||
|
||||
li.customize-menu
|
||||
menu.pets-menu(label=env.t('hatchingPotions'))
|
||||
div(ng-repeat='pot in Content.hatchingPotions')
|
||||
button.customize-option(popover='{{pot.notes}}', popover-title='{{pot.text}} Potion', popover-trigger='mouseenter', popover-placement='left', ng-click='purchase("hatchingPotions", pot)', class='Pet_HatchingPotion_{{pot.key}}')
|
||||
p
|
||||
| {{pot.value}}
|
||||
span.Pet_Currency_Gem1x.inline-gems
|
||||
menu.pets-menu(label=(env.t('eggs') + ' ({{eggCount}})'))
|
||||
p.muted(ng-show='eggCount < 1')=env.t('noEggs')
|
||||
div(ng-repeat='(egg,points) in ownedItems(user.items.eggs)')
|
||||
//TODO move positioning this styling to css
|
||||
button.customize-option(popover='{{Content.eggs[egg].notes}}', popover-title='{{Content.eggs[egg].text}} Egg', popover-trigger='mouseenter', popover-placement='right', ng-click='chooseEgg(egg)', class='Pet_Egg_{{egg}}', ng-class='{selectableInventory: selectedPotion && !(user.items.pets[egg+"-"+selectedPotion.key]>0)}')
|
||||
.badge.badge-info.stack-count {{points}}
|
||||
//-p {{Content.eggs[egg].text}}
|
||||
|
||||
li.customize-menu
|
||||
menu.pets-menu(label=env.t('food'))
|
||||
div(ng-repeat='food in Content.food', ng-if='food.key !== "Saddle" && food.canBuy')
|
||||
button.customize-option(popover='{{food.notes}}', popover-title='{{food.text}}', popover-trigger='mouseenter', popover-placement='left', ng-click='purchase("food", food)', class='Pet_Food_{{food.key}}')
|
||||
p
|
||||
| {{food.value}}
|
||||
span.Pet_Currency_Gem1x.inline-gems
|
||||
menu.hatchingPotion-menu(label=(env.t('hatchingPotions') + ' ({{potCount}})'))
|
||||
p.muted(ng-show='potCount < 1')=env.t('noHatchingPotions')
|
||||
div(ng-repeat='(pot,points) in ownedItems(user.items.hatchingPotions)')
|
||||
button.customize-option(popover='{{Content.hatchingPotions[pot].notes}}', popover-title='{{Content.hatchingPotions[pot].text}} Potion', popover-trigger='mouseenter', popover-placement='right', ng-click='choosePotion(pot)', class='Pet_HatchingPotion_{{pot}}', ng-class='{selectableInventory: selectedEgg && !(user.items.pets[selectedEgg.key+"-"+pot]>0)}')
|
||||
.badge.badge-info.stack-count {{points}}
|
||||
|
||||
li.customize-menu
|
||||
menu.pets-menu(label=env.t('quests'))
|
||||
menu.pets-menu(label=(env.t('scrolls') + ' ({{questCount}})'))
|
||||
p.muted(ng-show='questCount < 1')=env.t('noScrolls')
|
||||
p.muted!=env.t('scrollsText1') + ' <a href="/#/options/groups/party">' + env.t('scrollsText2') + '</a>'
|
||||
div(ng-repeat='quest in Content.quests', ng-if='quest.canBuy')
|
||||
button.customize-option(popover="{{quest.previous && !user.achievements.quests[quest.previous] ? env.t('scrollsPre') : quest.notes | htmlDecode}}", popover-title='{{quest.text}}', popover-trigger='mouseenter', popover-placement='left', ng-click='buyQuest(quest.key)', class='inventory_quest_scroll', ng-class='{locked: quest.previous && !user.achievements.quests[quest.previous]}')
|
||||
p
|
||||
| {{quest.value}}
|
||||
span.Pet_Currency_Gem1x.inline-gems
|
||||
div(ng-repeat='(quest_key,points) in ownedItems(user.items.quests)', ng-init='quest = Content.quests[quest_key]')
|
||||
button.customize-option(popover="{{quest.previous && !user.achievements.quests[quest.previous] ? env.t('scrollsPre') : quest.notes | htmlDecode}}", popover-title='{{quest.text}}', popover-trigger='mouseenter', popover-placement='right', ng-click='showQuest(quest_key)', class='inventory_quest_scroll', ng-class='{locked: quest.previous && !user.achievements.quests[quest.previous]}')
|
||||
.badge.badge-info.stack-count {{points}}
|
||||
|
||||
li.customize-menu
|
||||
menu.pets-menu(label=env.t('food') + ' ({{foodCount}})')
|
||||
p(ng-show='foodCount < 1')=env.t('noFood')
|
||||
div(ng-repeat='(food,points) in ownedItems(user.items.food)')
|
||||
button.customize-option(popover='{{Content.food[food].notes}}', popover-title='{{Content.food[food].text}}', popover-trigger='mouseenter', popover-placement='right', ng-click='chooseFood(food)', class='Pet_Food_{{food}}')
|
||||
.badge.badge-info.stack-count {{points}}
|
||||
|
||||
li.customize-menu(ng-if='user.items.special.snowball')
|
||||
menu.pets-menu(label=env.t('special'))
|
||||
div
|
||||
button.customize-option(popover='{{Content.food.Saddle.notes}}', popover-title='{{Content.food.Saddle.text}}', popover-trigger='mouseenter', popover-placement='left', ng-click='purchase("food", Content.food.Saddle)', class='Pet_Food_{{Content.food.Saddle.key}}')
|
||||
p
|
||||
| {{Content.food.Saddle.value}}
|
||||
span.Pet_Currency_Gem1x.inline-gems
|
||||
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=env.t('fortifyPop'), popover-title=env.t('fortifyName'), popover-trigger='mouseenter', popover-placement='left', ng-click='modals.reroll = true', class='inventory_special_fortify')
|
||||
p
|
||||
| 4
|
||||
span.Pet_Currency_Gem1x.inline-gems
|
||||
//-div
|
||||
button.customize-option(popover='{{Content.spells.special.snowball.notes}}', popover-title='{{Content.spells.special.snowball.text}}', popover-trigger='mouseenter', popover-placement='left', ng-click='purchase("special", Content.spells.special.snowball)', class='inventory_special_snowball')
|
||||
p
|
||||
| {{Content.spells.special.snowball.value}}
|
||||
span.Pet_Currency_Gem1x.inline-gems
|
||||
div(ng-show='user.flags.rebirthEnabled')
|
||||
button.customize-option(popover=env.t('rebirthPop'), popover-title=env.t('rebirthName'), popover-trigger='mouseenter', popover-placement='left', ng-click='modals.rebirth = true', class='rebirth_orb')
|
||||
p
|
||||
| 8
|
||||
span.Pet_Currency_Gem1x.inline-gems
|
||||
div(ng-if='user.purchased.plan.planId')
|
||||
button.customize-option(ng-click='user.ops.purchase({params:{type:"gems",key:"gem"}})')
|
||||
span.Pet_Currency_Gem.inline-gems
|
||||
p
|
||||
| 20
|
||||
span.shop_gold
|
||||
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
|
||||
button.customize-option(popover=env.t('subscriberItemText'), popover-trigger='mouseenter', popover-placement='right', class='inventory_present')
|
||||
|
||||
.col-md-6
|
||||
h2=env.t('market')
|
||||
.row-fluid
|
||||
table.npc_alex_container
|
||||
tr
|
||||
td
|
||||
.npc_alex.pull-left
|
||||
td
|
||||
.popover.static-popover.fade.right.in
|
||||
.arrow
|
||||
h3.popover-title
|
||||
a(target='_blank', href='http://www.kickstarter.com/profile/523661924')=env.t('alexander')
|
||||
.popover-content
|
||||
p=env.t('welcomeMarket')
|
||||
p
|
||||
button.btn.btn-primary(ng-show='selectedEgg', ng-click='sellInventory()')=env.t('sellForGold', {item: "{{selectedEgg.text}}", gold: "{{selectedEgg.value}}"})
|
||||
button.btn.btn-primary(ng-show='selectedPotion', ng-click='sellInventory()')=env.t('sellForGold', {item: "{{selectedPotion.text}}", gold: "{{selectedPotion.value}}"})
|
||||
button.btn.btn-primary(ng-show='selectedFood', ng-click='sellInventory()')=env.t('sellForGold', {item: "{{selectedFood.text}}", gold: "{{selectedFood.value}}"})
|
||||
menu.inventory-list(type='list')
|
||||
li.customize-menu
|
||||
menu.pets-menu(label=env.t('eggs'))
|
||||
div(ng-repeat='egg in Content.eggs', ng-if='egg.canBuy')
|
||||
button.customize-option(popover='{{egg.notes}}', popover-title='{{egg.text}} Egg', popover-trigger='mouseenter', popover-placement='left', ng-click='purchase("eggs", egg)', class='Pet_Egg_{{egg.key}}')
|
||||
p
|
||||
| {{egg.value}}
|
||||
span.Pet_Currency_Gem1x.inline-gems
|
||||
|
||||
li.customize-menu
|
||||
menu.pets-menu(label=env.t('hatchingPotions'))
|
||||
div(ng-repeat='pot in Content.hatchingPotions')
|
||||
button.customize-option(popover='{{pot.notes}}', popover-title='{{pot.text}} Potion', popover-trigger='mouseenter', popover-placement='left', ng-click='purchase("hatchingPotions", pot)', class='Pet_HatchingPotion_{{pot.key}}')
|
||||
p
|
||||
| {{pot.value}}
|
||||
span.Pet_Currency_Gem1x.inline-gems
|
||||
|
||||
li.customize-menu
|
||||
menu.pets-menu(label=env.t('food'))
|
||||
div(ng-repeat='food in Content.food', ng-if='food.key !== "Saddle" && food.canBuy')
|
||||
button.customize-option(popover='{{food.notes}}', popover-title='{{food.text}}', popover-trigger='mouseenter', popover-placement='left', ng-click='purchase("food", food)', class='Pet_Food_{{food.key}}')
|
||||
p
|
||||
| {{food.value}}
|
||||
span.Pet_Currency_Gem1x.inline-gems
|
||||
|
||||
li.customize-menu
|
||||
menu.pets-menu(label=env.t('quests'))
|
||||
p.muted!=env.t('scrollsText1') + ' <a href="/#/options/groups/party">' + env.t('scrollsText2') + '</a>'
|
||||
div(ng-repeat='quest in Content.quests', ng-if='quest.canBuy')
|
||||
button.customize-option(popover="{{quest.previous && !user.achievements.quests[quest.previous] ? env.t('scrollsPre') : quest.notes | htmlDecode}}", popover-title='{{quest.text}}', popover-trigger='mouseenter', popover-placement='left', ng-click='buyQuest(quest.key)', class='inventory_quest_scroll', ng-class='{locked: quest.previous && !user.achievements.quests[quest.previous]}')
|
||||
p
|
||||
| {{quest.value}}
|
||||
span.Pet_Currency_Gem1x.inline-gems
|
||||
|
||||
li.customize-menu
|
||||
menu.pets-menu(label=env.t('special'))
|
||||
div
|
||||
button.customize-option(popover='{{Content.food.Saddle.notes}}', popover-title='{{Content.food.Saddle.text}}', popover-trigger='mouseenter', popover-placement='left', ng-click='purchase("food", Content.food.Saddle)', class='Pet_Food_{{Content.food.Saddle.key}}')
|
||||
p
|
||||
| {{Content.food.Saddle.value}}
|
||||
span.Pet_Currency_Gem1x.inline-gems
|
||||
div
|
||||
button.customize-option(popover=env.t('fortifyPop'), popover-title=env.t('fortifyName'), popover-trigger='mouseenter', popover-placement='left', ng-click='openModal("reroll")', class='inventory_special_fortify')
|
||||
p
|
||||
| 4
|
||||
span.Pet_Currency_Gem1x.inline-gems
|
||||
//-div
|
||||
button.customize-option(popover='{{Content.spells.special.snowball.notes}}', popover-title='{{Content.spells.special.snowball.text}}', popover-trigger='mouseenter', popover-placement='left', ng-click='purchase("special", Content.spells.special.snowball)', class='inventory_special_snowball')
|
||||
p
|
||||
| {{Content.spells.special.snowball.value}}
|
||||
span.Pet_Currency_Gem1x.inline-gems
|
||||
div(ng-show='user.flags.rebirthEnabled')
|
||||
button.customize-option(popover=env.t('rebirthPop'), popover-title=env.t('rebirthName'), popover-trigger='mouseenter', popover-placement='left', ng-click='openModal("rebirth")', class='rebirth_orb')
|
||||
p
|
||||
| 8
|
||||
span.Pet_Currency_Gem1x.inline-gems
|
||||
div(ng-if='user.purchased.plan.planId')
|
||||
button.customize-option(ng-click='user.ops.purchase({params:{type:"gems",key:"gem"}})')
|
||||
span.Pet_Currency_Gem.inline-gems
|
||||
p
|
||||
| 20
|
||||
span.shop_gold
|
||||
|
||||
@@ -1,85 +1,99 @@
|
||||
script(type='text/ng-template', id='partials/options.inventory.mounts.html')
|
||||
.stable
|
||||
table(style='width:100%')
|
||||
tr
|
||||
td(style='width:144px')
|
||||
.npc_matt
|
||||
td
|
||||
.popover.static-popover.fade.right.in(style='max-width: 550px; margin-left: 10px;')
|
||||
.arrow
|
||||
h3.popover-title
|
||||
a(target='_blank', href='http://www.kickstarter.com/profile/mattboch')=env.t('mattBoch')
|
||||
.popover-content
|
||||
p=env.t('mattShall', {name: "{{user.profile.name}}"})
|
||||
h4= '{{mountCount}} / {{totalPets}} ' + env.t('mountsTamed')
|
||||
menu.pets(type='list')
|
||||
li.customize-menu(ng-repeat='egg in Content.eggs')
|
||||
.container-fluid
|
||||
.stable.row
|
||||
.col-md-2
|
||||
.npc_matt
|
||||
.col-md-10
|
||||
.popover.static-popover.fade.right.in
|
||||
.arrow
|
||||
h3.popover-title
|
||||
a(target='_blank', href='http://www.kickstarter.com/profile/mattboch')=env.t('mattBoch')
|
||||
.popover-content
|
||||
p=env.t('mattShall', {name: "{{user.profile.name}}"})
|
||||
h4= '{{Shared.countMounts(null,User.user.items.mounts) || 0}} / {{totalMounts}} ' + env.t('mountsTamed')
|
||||
.col-md-12
|
||||
menu.pets(type='list')
|
||||
li.customize-menu(ng-repeat='egg in Content.eggs')
|
||||
menu
|
||||
div(ng-repeat='potion in Content.hatchingPotions', popover-trigger='mouseenter', popover='{{potion.text}} {{egg.mountText}}', popover-placement='bottom', ng-init='mount = egg.key+"-"+potion.key')
|
||||
button(class="pet-button Mount_Head_{{mount}}", ng-show='user.items.mounts[mount]', ng-class='{active: user.items.currentMount == mount}', ng-click='chooseMount(egg.key, potion.key)')
|
||||
//div(class='Mount_Head_{{mount}}')
|
||||
button(class="pet-button pet-not-owned", ng-hide='user.items.mounts[mount]')
|
||||
.PixelPaw
|
||||
.col-md-12
|
||||
h4=env.t('rareMounts')
|
||||
menu
|
||||
div(ng-repeat='potion in Content.hatchingPotions', popover-trigger='mouseenter', popover='{{potion.text}} {{egg.mountText}}', popover-placement='bottom', ng-init='mount = egg.key+"-"+potion.key')
|
||||
button(class="pet-button Mount_Head_{{mount}}", ng-show='user.items.mounts[mount]', ng-class='{active: user.items.currentMount == mount}', ng-click='chooseMount(egg.key, potion.key)')
|
||||
//div(class='Mount_Head_{{mount}}')
|
||||
button(class="pet-button pet-not-owned", ng-hide='user.items.mounts[mount]')
|
||||
.PixelPaw
|
||||
|
||||
h4=env.t('rareMounts')
|
||||
menu
|
||||
div
|
||||
button(ng-if='user.items.mounts["BearCub-Polar"]', class="pet-button Mount_Head_BearCub-Polar", ng-class='{active: user.items.currentMount == "BearCub-Polar"}', ng-click='chooseMount("BearCub", "Polar")', popover=env.t('polarBear'), popover-trigger='mouseenter', popover-placement='bottom')
|
||||
//.Mount_Head_BearCub-Polar
|
||||
button(ng-if='user.items.mounts["LionCub-Ethereal"]', class="pet-button Mount_Head_LionCub-Ethereal", ng-class='{active: user.items.currentMount == "LionCub-Ethereal"}', ng-click='chooseMount("LionCub", "Ethereal")', popover=env.t('etherealLion'), popover-trigger='mouseenter', popover-placement='bottom')
|
||||
//.Mount_Head_LionCub-Ethereal
|
||||
div
|
||||
button(ng-if='user.items.mounts["BearCub-Polar"]', class="pet-button Mount_Head_BearCub-Polar", ng-class='{active: user.items.currentMount == "BearCub-Polar"}', ng-click='chooseMount("BearCub", "Polar")', popover=env.t('polarBear'), popover-trigger='mouseenter', popover-placement='bottom')
|
||||
//.Mount_Head_BearCub-Polar
|
||||
button(ng-if='user.items.mounts["LionCub-Ethereal"]', class="pet-button Mount_Head_LionCub-Ethereal", ng-class='{active: user.items.currentMount == "LionCub-Ethereal"}', ng-click='chooseMount("LionCub", "Ethereal")', popover=env.t('etherealLion'), popover-trigger='mouseenter', popover-placement='bottom')
|
||||
//.Mount_Head_LionCub-Ethereal
|
||||
|
||||
script(type='text/ng-template', id='partials/options.inventory.pets.html')
|
||||
.stable
|
||||
table(style='width:100%')
|
||||
tr
|
||||
td(style='width:144px')
|
||||
.npc_matt
|
||||
td
|
||||
.popover.static-popover.fade.right.in(style='max-width: 550px; margin-left: 10px;')
|
||||
.arrow
|
||||
h3.popover-title
|
||||
a(target='_blank', href='http://www.kickstarter.com/profile/mattboch')=env.t('mattBoch')
|
||||
.popover-content
|
||||
p
|
||||
=env.t('mattBochText1') + ' '
|
||||
| <a target='_blank' href='https://f.cloud.github.com/assets/2374703/164631/3ed5fa6c-78cd-11e2-8743-f65ac477b55e.png'>
|
||||
=env.t('mattBochText2')
|
||||
| </a>
|
||||
= ' ' + env.t('mattBochText3')
|
||||
h4= '{{petCount}} / {{totalPets}} ' + env.t('petsFound')
|
||||
.container-fluid
|
||||
.stable.row
|
||||
.col-md-2
|
||||
.npc_matt
|
||||
.col-md-10
|
||||
.popover.static-popover.fade.right.in
|
||||
.arrow
|
||||
h3.popover-title
|
||||
a(target='_blank', href='http://www.kickstarter.com/profile/mattboch')=env.t('mattBoch')
|
||||
.popover-content
|
||||
p
|
||||
=env.t('mattBochText1') + ' '
|
||||
| <a target='_blank' href='https://f.cloud.github.com/assets/2374703/164631/3ed5fa6c-78cd-11e2-8743-f65ac477b55e.png'>
|
||||
=env.t('mattBochText2')
|
||||
| </a>
|
||||
= ' ' + env.t('mattBochText3')
|
||||
h4= env.t('beastmasterProgress') + ': {{petCount}} / {{totalPets}} ' + env.t('petsFound')
|
||||
|
||||
menu.pets(type='list')
|
||||
li.customize-menu(ng-repeat='egg in Content.eggs')
|
||||
.col-md-12
|
||||
menu.pets(type='list')
|
||||
li.customize-menu(ng-repeat='egg in Content.dropEggs')
|
||||
menu
|
||||
div(ng-repeat='potion in Content.hatchingPotions', popover-trigger='mouseenter', popover='{{potion.text}} {{egg.text}}', popover-placement='bottom', ng-init='pet = egg.key+"-"+potion.key')
|
||||
button(class="pet-button Pet-{{pet}}", ng-if='user.items.pets[pet]>0', ng-class='{active: user.items.currentPet == pet, selectableInventory: selectedFood}', ng-click='choosePet(egg.key, potion.key)')
|
||||
.progress(ng-show='!user.items.mounts[pet]')
|
||||
.progress-bar.progress-bar-success(style="width:{{user.items.pets[pet]/.5}}%")
|
||||
button(class="pet-button pet-not-owned", ng-if='!user.items.pets[pet]')
|
||||
.PixelPaw
|
||||
// How to apply this style in stylus files?
|
||||
button(class="pet-button Pet-{{pet}}" ng-if='user.items.pets[pet]<0',style='opacity:0.1;filter:alpha(opacity=10)')
|
||||
//if this could be changed to the opacity talked about? can't figure it out
|
||||
.col-md-12
|
||||
h4=env.t('questPets')
|
||||
menu.pets(type='list')
|
||||
li.customize-menu(ng-repeat='egg in Content.questEggs')
|
||||
menu
|
||||
div(ng-repeat='potion in Content.hatchingPotions', popover-trigger='mouseenter', popover='{{potion.text}} {{egg.text}}', popover-placement='bottom', ng-init='pet = egg.key+"-"+potion.key')
|
||||
button(class="pet-button Pet-{{pet}}", ng-if='user.items.pets[pet]>0', ng-class='{active: user.items.currentPet == pet, selectableInventory: selectedFood}', ng-click='choosePet(egg.key, potion.key)')
|
||||
.progress(ng-show='!user.items.mounts[pet]')
|
||||
.progress-bar.progress-bar-success(style="width:{{user.items.pets[pet]/.5}}%")
|
||||
button(class="pet-button pet-not-owned", ng-if='!user.items.pets[pet]')
|
||||
.PixelPaw
|
||||
button(class="pet-button Pet-{{pet}}" ng-if='user.items.pets[pet]<0',style='opacity:0.1;filter:alpha(opacity=10)')
|
||||
|
||||
.col-md-12
|
||||
h4=env.t('rarePets')
|
||||
menu
|
||||
div(ng-repeat='potion in Content.hatchingPotions', popover-trigger='mouseenter', popover='{{potion.text}} {{egg.text}}', popover-placement='bottom', ng-init='pet = egg.key+"-"+potion.key')
|
||||
button(class="pet-button Pet-{{pet}}", ng-if='user.items.pets[pet]>0', ng-class='{active: user.items.currentPet == pet, selectableInventory: selectedFood}', ng-click='choosePet(egg.key, potion.key)')
|
||||
.progress(ng-class='{"progress-success": user.items.pets[pet]<50}')
|
||||
.bar(style="width: {{user.items.pets[pet]/.5}}%;")
|
||||
button(class="pet-button pet-not-owned", ng-if='!user.items.pets[pet]')
|
||||
.PixelPaw
|
||||
button(class="pet-button Pet-{{pet}}" ng-if='user.items.pets[pet]<0',style='opacity:0.1;filter:alpha(opacity=10)')
|
||||
//if this could be changed to the opacity talked about? can't figure it out
|
||||
div
|
||||
button(ng-if='user.items.pets["Wolf-Veteran"]', class="pet-button Pet-Wolf-Veteran", ng-class='{active: user.items.currentPet == "Wolf-Veteran"}', ng-click='choosePet("Wolf", "Veteran")', popover=env.t('veteranWolf'), popover-trigger='mouseenter', popover-placement='bottom')
|
||||
button(ng-if='user.items.pets["Wolf-Cerberus"]', class="pet-button Pet-Wolf-Cerberus", ng-class='{active: user.items.currentPet == "Wolf-Cerberus"}', ng-click='choosePet("Wolf", "Cerberus")', popover=env.t('cerberusPup'), popover-trigger='mouseenter', popover-placement='bottom')
|
||||
button(ng-if='user.items.pets["Turkey-Base"]', class="pet-button Pet-Turkey-Base", ng-class='{active: user.items.currentPet == "Turkey-Base"}', ng-click='choosePet("Turkey", "Base")', popover=env.t('turkey'), popover-trigger='mouseenter', popover-placement='bottom')
|
||||
button(ng-if='user.items.pets["BearCub-Polar"]', class="pet-button Pet-BearCub-Polar", ng-class='{active: user.items.currentPet == "BearCub-Polar"}', ng-click='choosePet("BearCub", "Polar")', popover=env.t('polarBearPup'), popover-trigger='mouseenter', popover-placement='bottom')
|
||||
button(ng-if='user.items.pets["Dragon-Hydra"]', class="pet-button Pet-Dragon-Hydra", ng-class='{active: user.items.currentPet == "Dragon-Hydra"}', ng-click='choosePet("Dragon", "Hydra")', popover=env.t('hydra'), popover-trigger='mouseenter', popover-placement='bottom')
|
||||
a(target='_blank', href='http://habitrpg.wikia.com/wiki/Contributing_to_HabitRPG')
|
||||
button(ng-if='!user.items.pets["Dragon-Hydra"]', class="pet-button pet-not-owned", popover-trigger='mouseenter', popover-placement='right', popover=env.t('rarePetPop1'), popover-title=env.t('rarePetPop2'))
|
||||
.PixelPaw-Gold
|
||||
|
||||
h4=env.t('rarePets')
|
||||
menu
|
||||
div
|
||||
button(ng-if='user.items.pets["Wolf-Veteran"]', class="pet-button Pet-Wolf-Veteran", ng-class='{active: user.items.currentPet == "Wolf-Veteran"}', ng-click='choosePet("Wolf", "Veteran")', popover=env.t('veteranWolf'), popover-trigger='mouseenter', popover-placement='bottom')
|
||||
button(ng-if='user.items.pets["Wolf-Cerberus"]', class="pet-button Pet-Wolf-Cerberus", ng-class='{active: user.items.currentPet == "Wolf-Cerberus"}', ng-click='choosePet("Wolf", "Cerberus")', popover=env.t('cerberusPup'), popover-trigger='mouseenter', popover-placement='bottom')
|
||||
button(ng-if='user.items.pets["Turkey-Base"]', class="pet-button Pet-Turkey-Base", ng-class='{active: user.items.currentPet == "Turkey-Base"}', ng-click='choosePet("Turkey", "Base")', popover=env.t('turkey'), popover-trigger='mouseenter', popover-placement='bottom')
|
||||
button(ng-if='user.items.pets["BearCub-Polar"]', class="pet-button Pet-BearCub-Polar", ng-class='{active: user.items.currentPet == "BearCub-Polar"}', ng-click='choosePet("BearCub", "Polar")', popover=env.t('polarBearPup'), popover-trigger='mouseenter', popover-placement='bottom')
|
||||
button(ng-if='user.items.pets["Dragon-Hydra"]', class="pet-button Pet-Dragon-Hydra", ng-class='{active: user.items.currentPet == "Dragon-Hydra"}', ng-click='choosePet("Dragon", "Hydra")', popover=env.t('hydra'), popover-trigger='mouseenter', popover-placement='bottom')
|
||||
a(target='_blank', href='http://habitrpg.wikia.com/wiki/Contributing_to_HabitRPG')
|
||||
button(ng-if='!user.items.pets["Dragon-Hydra"]', class="pet-button pet-not-owned", popover-trigger='mouseenter', popover-placement='right', popover=env.t('rarePetPop1'), popover-title=env.t('rarePetPop2'))
|
||||
.PixelPaw-Gold
|
||||
|
||||
.well.food-tray
|
||||
p(ng-show='foodCount < 1')=env.t('noFood')
|
||||
menu.inventory-list(type='list', ng-if='foodCount > 0')
|
||||
li.customize-menu
|
||||
menu.pets-menu(label=env.t('food'))
|
||||
div(ng-repeat='(food,points) in ownedItems(user.items.food)')
|
||||
button.customize-option(popover-append-to-body='true', popover='{{Content.food[food].notes}}', popover-title='{{Content.food[food].text}}', popover-trigger='mouseenter', popover-placement='left', ng-click='chooseFood(food)', class='Pet_Food_{{food}}')
|
||||
.badge.badge-info.stack-count {{points}}
|
||||
// Remove this once we have images in
|
||||
p {{Content.food[food].text}}
|
||||
.well.food-tray
|
||||
p(ng-show='foodCount < 1')=env.t('noFood')
|
||||
menu.inventory-list(type='list', ng-if='foodCount > 0')
|
||||
li.customize-menu
|
||||
menu.pets-menu(label=env.t('food'))
|
||||
div(ng-repeat='(food,points) in ownedItems(user.items.food)')
|
||||
button.customize-option(popover-append-to-body='true', popover='{{Content.food[food].notes}}', popover-title='{{Content.food[food].text}}', popover-trigger='mouseenter', popover-placement='left', ng-click='chooseFood(food)', class='Pet_Food_{{food}}')
|
||||
.badge.badge-info.stack-count {{points}}
|
||||
// Remove this once we have images in
|
||||
p {{Content.food[food].text}}
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
script(id='partials/options.profile.avatar.html', type='text/ng-template')
|
||||
.row-fluid
|
||||
.span4
|
||||
.row
|
||||
.col-md-4
|
||||
h3=env.t('bodyBody')
|
||||
small
|
||||
| 2 <span class="Pet_Currency_Gem1x inline-gems"/> /
|
||||
| 2 <span class="Pet_Currency_Gem1x inline-gems"></span> /
|
||||
= ' ' + env.t('locked')
|
||||
|
||||
h5=env.t('bodySize')
|
||||
.btn-group
|
||||
button.btn.btn-small(ng-class='{active: user.preferences.size=="slim"}', ng-click='set({"preferences.size":"slim"})')=env.t('bodySlim')
|
||||
button.btn.btn-small(ng-class='{active: user.preferences.size=="broad"}', ng-click='set({"preferences.size":"broad"})')=env.t('bodyBroad')
|
||||
button.btn.btn-sm.btn-default(ng-class='{active: user.preferences.size=="slim"}', ng-click='set({"preferences.size":"slim"})')=env.t('bodySlim')
|
||||
button.btn.btn-sm.btn-default(ng-class='{active: user.preferences.size=="broad"}', ng-click='set({"preferences.size":"broad"})')=env.t('bodyBroad')
|
||||
|
||||
menu(type='list')
|
||||
li.customize-menu
|
||||
@@ -21,31 +21,30 @@ script(id='partials/options.profile.avatar.html', type='text/ng-template')
|
||||
each shirt in ['convict', 'cross', 'fire', 'horizon', 'ocean', 'purple', 'rainbow', 'redblue', 'thunder', 'tropical', 'zombie']
|
||||
button.customize-option(type='button', class='{{user.preferences.size}}_shirt_'+shirt, ng-class='{locked: !user.purchased.shirt.'+shirt+'}', ng-click='unlock("shirt.'+shirt+'")')
|
||||
menu
|
||||
button.btn.btn-small.btn-primary(ng-hide="user.purchased.shirt.convict && user.purchased.shirt.cross && user.purchased.shirt.fire && user.purchased.shirt.horizon && user.purchased.shirt.ocean && user.purchased.shirt.purple && user.purchased.shirt.rainbow && user.purchased.shirt.redblue && user.purchased.shirt.thunder && user.purchased.shirt.tropical && user.purchased.shirt.zombie", ng-click='unlock("shirt.convict,shirt.cross,shirt.fire,shirt.horizon,shirt.ocean,shirt.purple,shirt.rainbow,shirt.redblue,shirt.thunder,shirt.tropical,shirt.zombie")')!= env.t('unlockSet5') + ' <span class="Pet_Currency_Gem1x inline-gems"/>'
|
||||
button.btn.btn-sm.btn-primary(ng-hide="user.purchased.shirt.convict && user.purchased.shirt.cross && user.purchased.shirt.fire && user.purchased.shirt.horizon && user.purchased.shirt.ocean && user.purchased.shirt.purple && user.purchased.shirt.rainbow && user.purchased.shirt.redblue && user.purchased.shirt.thunder && user.purchased.shirt.tropical && user.purchased.shirt.zombie", ng-click='unlock("shirt.convict,shirt.cross,shirt.fire,shirt.horizon,shirt.ocean,shirt.purple,shirt.rainbow,shirt.redblue,shirt.thunder,shirt.tropical,shirt.zombie")')!= env.t('unlockSet5') + ' <span class="Pet_Currency_Gem1x inline-gems"/>'
|
||||
|
||||
|
||||
.span4
|
||||
.col-md-4
|
||||
h3=env.t('bodyHead')
|
||||
small
|
||||
| 2 <span class="Pet_Currency_Gem1x inline-gems"/> /
|
||||
| 2 <span class="Pet_Currency_Gem1x inline-gems"></span> /
|
||||
= ' ' + env.t('locked')
|
||||
menu(type='list')
|
||||
// For special events code, see commit dfa27b3
|
||||
|
||||
// Color
|
||||
li.customize-menu
|
||||
menu(label=env.t('color'))
|
||||
each v,k in {'c8c8c8':'white','903a00':'brown','cfb853':'blond','ec720f':'red','2e2e2e':'black'}
|
||||
button(type='button', class='customize-option', style='width: 40px; height: 40px; background-color:##{k};', ng-click='set({"preferences.hair.color": "#{v}"})')
|
||||
|
||||
// Special Events
|
||||
li.customize-menu.well.limited-edition
|
||||
.label.label-info.pull-right(popover=env.t('limited31Jan'), popover-title=env.t('limitedEdition'), popover-placement='right', popover-trigger='mouseenter')
|
||||
=env.t('limitedEdition')
|
||||
|
|
||||
i.icon.icon-question-sign
|
||||
menu(label=env.t('winterColors'))
|
||||
button(type='button', class='customize-option hair', style='background-color:##{k};', ng-click='set({"preferences.hair.color": "#{v}"})')
|
||||
each color in ['candycane','frost','winternight','holly']
|
||||
button(type='button', ng-class='{locked: !user.purchased.hair.color.#{color}}', class='customize-option hair_bangs_1_#{color}', style='width: 40px; height: 40px;', ng-click='unlock("hair.color.#{color}")')
|
||||
button.btn.btn-small.btn-primary(ng-hide='user.purchased.hair.color.candycane && user.purchased.hair.color.frost && user.purchased.hair.color.winternight && user.purchased.hair.color.holly', ng-click='unlock("hair.color.candycane,hair.color.frost,hair.color.winternight,hair.color.holly")')!= env.t('unlockSet5') + ' <span class="Pet_Currency_Gem1x inline-gems"/>'
|
||||
button(type='button', ng-if='user.purchased.hair.color.#{color}', class='customize-option hair hair_bangs_1_#{color}', style='width: 40px; height: 40px;', ng-click='unlock("hair.color.#{color}")')
|
||||
|
||||
li.customize-menu
|
||||
menu(label=env.t('rainbowColors'))
|
||||
each color in ['rainbow','yellow','green','purple','blue','TRUred']
|
||||
button(type='button', ng-class='{locked: !user.purchased.hair.color.#{color}}', class='customize-option hair hair_bangs_1_#{color}', ng-click='unlock("hair.color.#{color}")')
|
||||
button.btn.btn-sm.btn-primary(ng-hide='user.purchased.hair.color.rainbow && user.purchased.hair.color.yellow && user.purchased.hair.color.green && user.purchased.hair.color.purple && user.purchased.hair.color.blue && user.purchased.hair.color.TRUred', ng-click='unlock("hair.color.rainbow,hair.color.yellow,hair.color.green,hair.color.purple,hair.color.blue,hair.color.TRUred")')!= env.t('unlockSet5') + ' <span class="Pet_Currency_Gem1x inline-gems"/>'
|
||||
|
||||
h5=env.t('bodyHair')
|
||||
// Bangs
|
||||
@@ -64,7 +63,7 @@ script(id='partials/options.profile.avatar.html', type='text/ng-template')
|
||||
when true: button(class='hair_base_#{k}_{{user.preferences.hair.color}} customize-option', type='button', ng-click='set({"preferences.hair.base":#{k}})')
|
||||
when false: button(class='hair_base_#{k}_{{user.preferences.hair.color}} customize-option', type='button', ng-class='{locked: !user.purchased.hair.base.#{k}}', ng-click='unlock("hair.base.#{k}")')
|
||||
|
||||
button.btn.btn-small.btn-primary(ng-hide='user.purchased.hair.base.2 && user.purchased.hair.base.4 && user.purchased.hair.base.5 && user.purchased.hair.base.6 && user.purchased.hair.base.7 && user.purchased.hair.base.8', ng-click='unlock("hair.base.2,hair.base.4,hair.base.5,hair.base.6,hair.base.7,hair.base.8")')!= env.t('unlockSet5') + ' <span class="Pet_Currency_Gem1x inline-gems"/>'
|
||||
button.btn.btn-sm.btn-primary(ng-hide='user.purchased.hair.base.2 && user.purchased.hair.base.4 && user.purchased.hair.base.5 && user.purchased.hair.base.6 && user.purchased.hair.base.7 && user.purchased.hair.base.8', ng-click='unlock("hair.base.2,hair.base.4,hair.base.5,hair.base.6,hair.base.7,hair.base.8")')!= env.t('unlockSet5') + ' <span class="Pet_Currency_Gem1x inline-gems"/>'
|
||||
|
||||
h5=env.t('bodyFacialHair')
|
||||
|
||||
@@ -82,12 +81,12 @@ script(id='partials/options.profile.avatar.html', type='text/ng-template')
|
||||
each num in [1,2]
|
||||
button(class='hair_mustache_#{num}_{{user.preferences.hair.color}} customize-option', type='button', ng-class='{locked: !user.purchased.hair.mustache.#{num}}', ng-click='unlock("hair.mustache.#{num}")')
|
||||
|
||||
button.btn.btn-small.btn-primary(ng-hide='user.purchased.hair.mustache.1 && user.purchased.hair.mustache.2 && user.purchased.hair.beard.1 && user.purchased.hair.beard.2 && user.purchased.hair.beard.3', ng-click='unlock("hair.mustache.1,hair.mustache.2,hair.beard.1,hair.beard.2,hair.beard.3")')!= env.t('unlockSet5') + ' <span class="Pet_Currency_Gem1x inline-gems"/>'
|
||||
button.btn.btn-sm.btn-primary(ng-hide='user.purchased.hair.mustache.1 && user.purchased.hair.mustache.2 && user.purchased.hair.beard.1 && user.purchased.hair.beard.2 && user.purchased.hair.beard.3', ng-click='unlock("hair.mustache.1,hair.mustache.2,hair.beard.1,hair.beard.2,hair.beard.3")')!= env.t('unlockSet5') + ' <span class="Pet_Currency_Gem1x inline-gems"/>'
|
||||
|
||||
.span4
|
||||
.col-md-4
|
||||
h3=env.t('bodySkin')
|
||||
small
|
||||
| 2 <span class="Pet_Currency_Gem1x inline-gems"/> /
|
||||
| 2 <span class="Pet_Currency_Gem1x inline-gems"></span> /
|
||||
= ' ' + env.t('locked')
|
||||
// skin
|
||||
li.customize-menu
|
||||
@@ -101,7 +100,7 @@ script(id='partials/options.profile.avatar.html', type='text/ng-template')
|
||||
menu
|
||||
each color in ['eb052b','f69922','f5d70f','0ff591','2b43f6','d7a9f7','800ed0','rainbow']
|
||||
button.customize-option(type='button', class='skin_#{color}', ng-class='{locked: !user.purchased.skin.#{color}}', ng-click='unlock("skin.#{color}")')
|
||||
button.btn.btn-small.btn-primary(ng-hide='user.purchased.skin.eb052b && user.purchased.skin.f69922 && user.purchased.skin.f5d70f && user.purchased.skin.0ff591 && user.purchased.skin.2b43f6 && user.purchased.skin.d7a9f7 && user.purchased.skin.800ed0 && user.purchased.skin.rainbow', ng-click='unlock("skin.eb052b,skin.f69922,skin.f5d70f,skin.0ff591,skin.2b43f6,skin.d7a9f7,skin.800ed0,skin.rainbow")')!= env.t('unlockSet5') + ' <span class="Pet_Currency_Gem1x inline-gems"/>'
|
||||
button.btn.btn-sm.btn-primary(ng-hide='user.purchased.skin.eb052b && user.purchased.skin.f69922 && user.purchased.skin.f5d70f && user.purchased.skin.0ff591 && user.purchased.skin.2b43f6 && user.purchased.skin.d7a9f7 && user.purchased.skin.800ed0 && user.purchased.skin.rainbow', ng-click='unlock("skin.eb052b,skin.f69922,skin.f5d70f,skin.0ff591,skin.2b43f6,skin.d7a9f7,skin.800ed0,skin.rainbow")')!= env.t('unlockSet5') + ' <span class="Pet_Currency_Gem1x inline-gems"/>'
|
||||
|
||||
// Special Events
|
||||
// restore to d4df481 to see purchasing + "limited edition" code
|
||||
@@ -112,108 +111,117 @@ script(id='partials/options.profile.avatar.html', type='text/ng-template')
|
||||
button.customize-option(type='button', class='skin_#{color}', ng-if='user.purchased.skin.#{color}', ng-click='unlock("skin.#{color}")')
|
||||
|
||||
script(id='partials/options.profile.stats.html', type='text/ng-template')
|
||||
.row-fluid
|
||||
.border-right(ng-class='user.flags.classSelected && !user.preferences.disableClasses ? "span4" : "span6"')
|
||||
include ../shared/profiles/stats
|
||||
.span4.border-right.allocate-stats(ng-if='user.flags.classSelected && !user.preferences.disableClasses')
|
||||
h3=env.t('characterBuild')
|
||||
h4
|
||||
=env.t('class') + ': '
|
||||
span {{ {warrior:'Warrior',wizard:'Mage',healer:'Healer',rogue:'Rogue'}[user.stats.class] }}
|
||||
a.btn.btn-danger.btn-mini(ng-click='changeClass(null)')=env.t('changeClass')
|
||||
small 3 <span class="Pet_Currency_Gem1x inline-gems"/>
|
||||
table.table.table-striped
|
||||
tr
|
||||
td
|
||||
strong
|
||||
{{user.stats.points}}
|
||||
=env.t('unallocated')
|
||||
|
||||
i.icon-question-sign(popover-trigger='mouseenter', popover-placement='right', popover=env.t('levelPopover'))
|
||||
td
|
||||
tr
|
||||
td(colspan=2)
|
||||
fieldset.auto-allocate
|
||||
label.checkbox
|
||||
input(type='checkbox', ng-model='user.preferences.automaticAllocation', ng-change='set({"preferences.automaticAllocation": user.preferences.automaticAllocation?true: false})', ng-click='set({"preferences.allocationMode":"taskbased"})')
|
||||
=env.t('autoAllocation')
|
||||
|
||||
i.icon-question-sign(popover-trigger='mouseenter', popover-placement='right', popover=env.t('autoAllocationPop'))
|
||||
form(ng-show='user.preferences.automaticAllocation',style='margin-left:1em')
|
||||
label.radio
|
||||
input(type='radio', name='allocationMode', value='flat', ng-model='user.preferences.allocationMode', ng-change='set({"preferences.allocationMode": "flat"})')
|
||||
=env.t('evenAllocation')
|
||||
|
||||
i.icon-question-sign(popover-trigger='mouseenter', popover-placement='right', popover=env.t('evenAllocationPop'))
|
||||
label.radio
|
||||
input(type='radio', name='allocationMode', value='classbased', ng-model='user.preferences.allocationMode', ng-change='set({"preferences.allocationMode": "classbased"})')
|
||||
=env.t('classAllocation')
|
||||
|
||||
i.icon-question-sign(popover-trigger='mouseenter', popover-placement='right', popover=env.t('classAllocationPop'))
|
||||
label.radio
|
||||
input(type='radio', name='allocationMode', value='taskbased', ng-model='user.preferences.allocationMode', ng-change='set({"preferences.allocationMode": "taskbased"})')
|
||||
=env.t('taskAllocation')
|
||||
|
||||
i.icon-question-sign(popover-trigger='mouseenter', popover-placement='right', popover=env.t('taskAllocationPop'))
|
||||
div(ng-show='user.preferences.automaticAllocation && !(user.preferences.allocationMode === "taskbased") && (user.stats.points > 0)')
|
||||
a.btn.btn-primary.btn-mini(ng-click='user.ops.allocateNow({})', popover-trigger='mouseenter', popover-placement='right', popover=env.t('distributePointsPop'))
|
||||
i.icon-download.icon-white
|
||||
|
||||
=env.t('distributePoints')
|
||||
tr
|
||||
td= env.t('allocateStr') + ' {{user.stats.str}}'
|
||||
td
|
||||
a.btn.btn-primary(ng-show='user.stats.points', ng-click='allocate("str")', popover-trigger='mouseenter', popover-placement='right', popover=env.t('allocateStrPop')) +
|
||||
tr
|
||||
td= env.t('allocateCon') + ' {{user.stats.con}}'
|
||||
td
|
||||
a.btn.btn-primary(ng-show='user.stats.points', ng-click='allocate("con")', popover-trigger='mouseenter', popover-placement='right', popover=env.t('allocateConPop')) +
|
||||
tr
|
||||
td= env.t('allocatePer') + ' {{user.stats.per}}'
|
||||
td
|
||||
a.btn.btn-primary(ng-show='user.stats.points', ng-click='allocate("per")', popover-trigger='mouseenter', popover-placement='right', popover=env.t('allocatePerPop')) +
|
||||
tr
|
||||
td= env.t('allocateInt') + ' {{user.stats.int}}'
|
||||
td
|
||||
a.btn.btn-primary(ng-show='user.stats.points', ng-click='allocate("int")', popover-trigger='mouseenter', popover-placement='right', popover=env.t('allocateIntPop')) +
|
||||
div(ng-class='user.flags.classSelected && !user.preferences.disableClasses ? "span4" : "span6"')
|
||||
include ../shared/profiles/achievements
|
||||
.container-fluid
|
||||
.row
|
||||
.border-right(ng-class='user.flags.classSelected && !user.preferences.disableClasses ? "col-md-4" : "col-md-6"')
|
||||
include ../shared/profiles/stats
|
||||
.col-md-4.border-right.allocate-stats(ng-if='user.flags.classSelected && !user.preferences.disableClasses')
|
||||
h3=env.t('characterBuild')
|
||||
h4
|
||||
=env.t('class') + ': '
|
||||
span {{ {warrior:'Warrior',wizard:'Mage',healer:'Healer',rogue:'Rogue'}[user.stats.class] }}
|
||||
a.btn.btn-danger.btn-xs(ng-click='changeClass(null)')=env.t('changeClass')
|
||||
small 3 <span class="Pet_Currency_Gem1x inline-gems"/>
|
||||
table.table.table-striped
|
||||
tr
|
||||
td
|
||||
strong
|
||||
{{user.stats.points}}
|
||||
=env.t('unallocated')
|
||||
|
||||
span.glyphicon.glyphicon-question-sign(popover-trigger='mouseenter', popover-placement='right', popover=env.t('levelPopover'))
|
||||
td
|
||||
tr
|
||||
td(colspan=2)
|
||||
fieldset.auto-allocate
|
||||
.checkbox
|
||||
label
|
||||
input(type='checkbox', ng-model='user.preferences.automaticAllocation', ng-change='set({"preferences.automaticAllocation": user.preferences.automaticAllocation?true: false})', ng-click='set({"preferences.allocationMode":"taskbased"})')
|
||||
=env.t('autoAllocation')
|
||||
|
|
||||
span.glyphicon.glyphicon-question-sign(popover-trigger='mouseenter', popover-placement='right', popover=env.t('autoAllocationPop'))
|
||||
form(ng-show='user.preferences.automaticAllocation',style='margin-left:1em')
|
||||
.radio
|
||||
label
|
||||
input(type='radio', name='allocationMode', value='flat', ng-model='user.preferences.allocationMode', ng-change='set({"preferences.allocationMode": "flat"})')
|
||||
=env.t('evenAllocation')
|
||||
|
|
||||
span.glyphicon.glyphicon-question-sign(popover-trigger='mouseenter', popover-placement='right', popover=env.t('evenAllocationPop'))
|
||||
.radio
|
||||
label
|
||||
input(type='radio', name='allocationMode', value='classbased', ng-model='user.preferences.allocationMode', ng-change='set({"preferences.allocationMode": "classbased"})')
|
||||
=env.t('classAllocation')
|
||||
|
|
||||
span.glyphicon.glyphicon-question-sign(popover-trigger='mouseenter', popover-placement='right', popover=env.t('classAllocationPop'))
|
||||
.radio
|
||||
label
|
||||
input(type='radio', name='allocationMode', value='taskbased', ng-model='user.preferences.allocationMode', ng-change='set({"preferences.allocationMode": "taskbased"})')
|
||||
=env.t('taskAllocation')
|
||||
|
|
||||
span.glyphicon.glyphicon-question-sign(popover-trigger='mouseenter', popover-placement='right', popover=env.t('taskAllocationPop'))
|
||||
div(ng-show='user.preferences.automaticAllocation && !(user.preferences.allocationMode === "taskbased") && (user.stats.points > 0)')
|
||||
a.btn.btn-primary.btn-xs(ng-click='user.ops.allocateNow({})', popover-trigger='mouseenter', popover-placement='right', popover=env.t('distributePointsPop'))
|
||||
span.glyphicon.glyphicon-download
|
||||
|
||||
=env.t('distributePoints')
|
||||
tr
|
||||
td= env.t('allocateCon') + ' {{user.stats.con}}'
|
||||
td
|
||||
a.btn.btn-primary(ng-show='user.stats.points', ng-click='allocate("con")', popover-trigger='mouseenter', popover-placement='right', popover=env.t('allocateConPop')) +
|
||||
tr
|
||||
td= env.t('allocateInt') + ' {{user.stats.int}}'
|
||||
td
|
||||
a.btn.btn-primary(ng-show='user.stats.points', ng-click='allocate("int")', popover-trigger='mouseenter', popover-placement='right', popover=env.t('allocateIntPop')) +
|
||||
tr
|
||||
td= env.t('allocatePer') + ' {{user.stats.per}}'
|
||||
td
|
||||
a.btn.btn-primary(ng-show='user.stats.points', ng-click='allocate("per")', popover-trigger='mouseenter', popover-placement='right', popover=env.t('allocatePerPop')) +
|
||||
tr
|
||||
td= env.t('allocateStr') + ' {{user.stats.str}}'
|
||||
td
|
||||
a.btn.btn-primary(ng-show='user.stats.points', ng-click='allocate("str")', popover-trigger='mouseenter', popover-placement='right', popover=env.t('allocateStrPop')) +
|
||||
|
||||
div(ng-class='user.flags.classSelected && !user.preferences.disableClasses ? "col-md-4" : "col-md-6"')
|
||||
include ../shared/profiles/achievements
|
||||
|
||||
script(id='partials/options.profile.profile.html', type='text/ng-template')
|
||||
button.btn.btn-default(ng-click='_editing.profile = true', ng-show='!_editing.profile')= env.t('edit')
|
||||
button.btn.btn-primary(ng-click='save()', ng-show='_editing.profile')= env.t('save')
|
||||
div(ng-show='!_editing.profile')
|
||||
h4=env.t('displayName')
|
||||
span(ng-show='profile.profile.name') {{profile.profile.name}}
|
||||
span.muted(ng-hide='profile.profile.name') -
|
||||
=env.t('none')
|
||||
| -
|
||||
.container-fluid
|
||||
.row
|
||||
.col-md-12(ng-show='!_editing.profile')
|
||||
button.btn.btn-default(ng-click='_editing.profile = true', ng-show='!_editing.profile')= env.t('edit')
|
||||
h4=env.t('displayName')
|
||||
span(ng-show='profile.profile.name') {{profile.profile.name}}
|
||||
span.muted(ng-hide='profile.profile.name') -
|
||||
=env.t('none')
|
||||
| -
|
||||
|
||||
h4=env.t('displayPhoto')
|
||||
img(ng-show='profile.profile.imageUrl', ng-src='{{profile.profile.imageUrl}}')
|
||||
span.muted(ng-hide='profile.profile.imageUrl') -
|
||||
=env.t('none')
|
||||
| -
|
||||
h4=env.t('displayPhoto')
|
||||
img(ng-show='profile.profile.imageUrl', ng-src='{{profile.profile.imageUrl}}')
|
||||
span.muted(ng-hide='profile.profile.imageUrl') -
|
||||
=env.t('none')
|
||||
| -
|
||||
|
||||
h4=env.t('displayBlurb')
|
||||
markdown(ng-show='profile.profile.blurb', ng-model='profile.profile.blurb')
|
||||
span.muted(ng-hide='profile.profile.blurb') -
|
||||
=env.t('none')
|
||||
| -
|
||||
//{{profile.profile.blurb | linky:'_blank'}}
|
||||
h4=env.t('displayBlurb')
|
||||
markdown(ng-show='profile.profile.blurb', ng-model='profile.profile.blurb')
|
||||
span.muted(ng-hide='profile.profile.blurb') -
|
||||
=env.t('none')
|
||||
| -
|
||||
//{{profile.profile.blurb | linky:'_blank'}}
|
||||
|
||||
div.whatever-options(ng-show='_editing.profile')
|
||||
// TODO use photo-upload instead: https://groups.google.com/forum/?fromgroups=#!topic/derbyjs/xMmADvxBOak
|
||||
.control-group.option-large
|
||||
label.control-label=env.t('displayName')
|
||||
input.option-content(type='text', placeholder=env.t('fullName'), ng-model='editingProfile.name')
|
||||
.control-group.option-large
|
||||
label.control-label=env.t('photoUrl')
|
||||
input.option-content(type='url', ng-model='editingProfile.imageUrl', placeholder=env.t('imageUrl'))
|
||||
.control-group.option-large
|
||||
label.control-label=env.t('displayBlurb')
|
||||
textarea.option-content(style='height:15em;', placeholder=env.t('displayBlurb'), ng-model='editingProfile.blurb')
|
||||
include ../shared/formatting-help
|
||||
form.col-md-4(ng-show='_editing.profile', ng-submit='save()')
|
||||
input.btn.btn-primary(type='submit', value=env.t('save'))
|
||||
|
||||
// TODO use photo-upload instead: https://groups.google.com/forum/?fromgroups=#!topic/derbyjs/xMmADvxBOak
|
||||
.form-group
|
||||
label=env.t('displayName')
|
||||
input.form-control(type='text', placeholder=env.t('fullName'), ng-model='editingProfile.name')
|
||||
.form-group
|
||||
label=env.t('photoUrl')
|
||||
input.form-control(type='url', ng-model='editingProfile.imageUrl', placeholder=env.t('imageUrl'))
|
||||
.form-group
|
||||
label=env.t('displayBlurb')
|
||||
textarea.form-control(rows=5, placeholder=env.t('displayBlurb'), ng-model='editingProfile.blurb')
|
||||
include ../shared/formatting-help
|
||||
|
||||
script(id='partials/options.profile.html', type="text/ng-template")
|
||||
ul.nav.nav-tabs
|
||||
|
||||
@@ -17,102 +17,108 @@ script(id='partials/options.settings.html', type="text/ng-template")
|
||||
div(ui-view)
|
||||
|
||||
script(type='text/ng-template', id='partials/options.settings.settings.html')
|
||||
.row-fluid
|
||||
.personal-options.span6
|
||||
h2=env.t('settings')
|
||||
h4=env.t('customDayStart')
|
||||
.option-group.option-short
|
||||
input.option-content.option-time(type='number', min='0', max='24', ng-model='user.preferences.dayStart', ng-change='saveDayStart()')
|
||||
span.input-suffix= ':00 (' + env.t('24HrClock') + ')'
|
||||
div
|
||||
small
|
||||
div=env.t('clockInfo')
|
||||
.alert.alert-danger
|
||||
=env.t('subWarning1')
|
||||
a(href='https://github.com/HabitRPG/habitrpg/issues/1057' target='_blank')=env.t('subWarning2')
|
||||
=env.t('subWarning3')
|
||||
hr
|
||||
h4=env.t('language')
|
||||
select(ng-model='language.code', ng-options='lang.code as lang.name for lang in avalaibleLanguages', ng-change='changeLanguage()')
|
||||
hr
|
||||
h4=env.t('misc')
|
||||
label.checkbox
|
||||
input(type='checkbox', ng-click='set({"preferences.hideHeader":user.preferences.hideHeader?false:true})', ng-checked='user.preferences.hideHeader!==true')
|
||||
=env.t('showHeader')
|
||||
|
||||
i.icon-question-sign(popover-trigger='mouseenter', popover-placement='right', popover=env.t('showHeaderPop'))
|
||||
label.checkbox
|
||||
input(type='checkbox', ng-click='toggleStickyHeader()', ng-checked='user.preferences.stickyHeader!==false')
|
||||
=env.t('stickyHeader')
|
||||
|
||||
i.icon-question-sign(popover-trigger='mouseenter', popover-placement='right', popover=env.t('stickyHeaderPop'))
|
||||
label.checkbox
|
||||
input(type='checkbox', ng-model='user.preferences.newTaskEdit', ng-change='set({"preferences.newTaskEdit": user.preferences.newTaskEdit?true: false})')
|
||||
=env.t('newTaskEdit')
|
||||
|
||||
i.icon-question-sign(popover-trigger='mouseenter', popover-placement='right', popover=env.t('newTaskEditPop'))
|
||||
label.checkbox
|
||||
input(type='checkbox', ng-model='user.preferences.tagsCollapsed', ng-change='set({"preferences.tagsCollapsed": user.preferences.tagsCollapsed?true: false})')
|
||||
=env.t('startCollapsed')
|
||||
|
||||
i.icon-question-sign(popover-trigger='mouseenter', popover-placement='right', popover=env.t('startCollapsedPop'))
|
||||
label.checkbox
|
||||
input(type='checkbox', ng-model='user.preferences.advancedCollapsed', ng-change='set({"preferences.advancedCollapsed": user.preferences.advancedCollapsed?true: false})')
|
||||
=env.t('startAdvCollapsed')
|
||||
|
||||
i.icon-question-sign(popover-trigger='mouseenter', popover-placement='right', popover=env.t('startAdvCollapsedPop'))
|
||||
button.btn(ng-click='showTour()', popover-placement='right', popover-trigger='mouseenter', popover=env.t('restartTour'))= env.t('showTour')
|
||||
br
|
||||
button.btn(ng-click='showBailey()', popover-trigger='mouseenter', popover-placement='right', popover=env.t('showBaileyPop'))= env.t('showBailey')
|
||||
br
|
||||
button.btn(ng-click='modals.restore = true', popover-trigger='mouseenter', popover-placement='right', popover=env.t('fixValPop'))= env.t('fixVal')
|
||||
div(ng-if='user.preferences.disableClasses==true')
|
||||
button.btn(ng-click='user.ops.changeClass({})', popover-trigger='mouseenter', popover-placement='right', popover=env.t('enableClassPop'))= env.t('enableClass')
|
||||
div(ng-if='!user.preferences.disableClasses && user.flags.classSelected')
|
||||
button.btn(ng-click='showClassesTour()', popover-trigger='mouseenter', popover-placement='right', popover=env.t('classTourPop'))= env.t('showClass')
|
||||
|
||||
//- Why is ng-if='user.auth.local' validating for users *without* user.auth.local (facebook users)? adding .username here for extra
|
||||
div(ng-if='user.auth.local.username')
|
||||
.containter-fluid
|
||||
.row
|
||||
.personal-options.col-md-6
|
||||
h2=env.t('settings')
|
||||
h4=env.t('customDayStart')
|
||||
.form-group
|
||||
input.form-control(type='number', min='0', max='24', ng-model='user.preferences.dayStart', ng-change='saveDayStart()')
|
||||
span.input-suffix= ':00 (' + env.t('24HrClock') + ')'
|
||||
div
|
||||
small
|
||||
div=env.t('clockInfo')
|
||||
.alert.alert-danger.alert-sm
|
||||
=env.t('subWarning1')
|
||||
|
|
||||
a(href='https://github.com/HabitRPG/habitrpg/issues/1057' target='_blank')=env.t('subWarning2')
|
||||
|
|
||||
=env.t('subWarning3')
|
||||
hr
|
||||
h4=env.t('changePass')
|
||||
form(ng-submit='changePassword(changePass)', ng-show='user.auth.local')
|
||||
.control-group
|
||||
input(type='password', placeholder=env.t('oldPass'), ng-model='changePass.oldPassword', required)
|
||||
.control-group
|
||||
input(type='password', placeholder=env.t('newPass'), ng-model='changePass.newPassword', required)
|
||||
.control-group
|
||||
input(type='password', placeholder=env.t('confirmPass'), ng-model='changePass.confirmNewPassword', required)
|
||||
input.btn(type='submit', value=env.t('submit'))
|
||||
h4=env.t('language')
|
||||
select(ng-model='language.code', ng-options='lang.code as lang.name for lang in avalaibleLanguages', ng-change='changeLanguage()')
|
||||
hr
|
||||
h4=env.t('misc')
|
||||
.checkbox
|
||||
label
|
||||
input(type='checkbox', ng-click='set({"preferences.hideHeader":user.preferences.hideHeader?false:true})', ng-checked='user.preferences.hideHeader!==true')
|
||||
=env.t('showHeader')
|
||||
|
||||
span.glyphicon.glyphicon-question-sign(popover-trigger='mouseenter', popover-placement='right', popover=env.t('showHeaderPop'))
|
||||
.checkbox
|
||||
label
|
||||
input(type='checkbox', ng-click='toggleStickyHeader()', ng-checked='user.preferences.stickyHeader!==false')
|
||||
=env.t('stickyHeader')
|
||||
|
||||
span.glyphicon.glyphicon-question-sign(popover-trigger='mouseenter', popover-placement='right', popover=env.t('stickyHeaderPop'))
|
||||
.checkbox
|
||||
label
|
||||
input(type='checkbox', ng-model='user.preferences.newTaskEdit', ng-change='set({"preferences.newTaskEdit": user.preferences.newTaskEdit?true: false})')
|
||||
=env.t('newTaskEdit')
|
||||
|
||||
span.glyphicon.glyphicon-question-sign(popover-trigger='mouseenter', popover-placement='right', popover=env.t('newTaskEditPop'))
|
||||
.checkbox
|
||||
label
|
||||
input(type='checkbox', ng-model='user.preferences.tagsCollapsed', ng-change='set({"preferences.tagsCollapsed": user.preferences.tagsCollapsed?true: false})')
|
||||
=env.t('startCollapsed')
|
||||
|
||||
span.glyphicon.glyphicon-question-sign(popover-trigger='mouseenter', popover-placement='right', popover=env.t('startCollapsedPop'))
|
||||
.checkbox
|
||||
label
|
||||
input(type='checkbox', ng-model='user.preferences.advancedCollapsed', ng-change='set({"preferences.advancedCollapsed": user.preferences.advancedCollapsed?true: false})')
|
||||
=env.t('startAdvCollapsed')
|
||||
|
||||
span.glyphicon.glyphicon-question-sign(popover-trigger='mouseenter', popover-placement='right', popover=env.t('startAdvCollapsedPop'))
|
||||
button.btn.btn-default(ng-click='showTour()', popover-placement='right', popover-trigger='mouseenter', popover=env.t('restartTour'))= env.t('showTour')
|
||||
button.btn.btn-default(ng-click='showBailey()', popover-trigger='mouseenter', popover-placement='right', popover=env.t('showBaileyPop'))= env.t('showBailey')
|
||||
button.btn.btn-default(ng-click='openRestoreModal()', popover-trigger='mouseenter', popover-placement='right', popover=env.t('fixValPop'))= env.t('fixVal')
|
||||
button.btn.btn-default(ng-if='user.preferences.disableClasses==true', ng-click='user.ops.changeClass({})', popover-trigger='mouseenter', popover-placement='right', popover=env.t('enableClassPop'))= env.t('enableClass')
|
||||
button.btn.btn-default(ng-if='!user.preferences.disableClasses && user.flags.classSelected', ng-click='showClassesTour()', popover-trigger='mouseenter', popover-placement='right', popover=env.t('classTourPop'))= env.t('showClass')
|
||||
|
||||
hr
|
||||
h4=env.t('dangerZone')
|
||||
a.btn.btn-danger(ng-click='modals.reset = true', popover-trigger='mouseenter', popover-placement='right', popover=env.t('resetAccPop'))= env.t('resetAccount')
|
||||
a.btn.btn-danger(ng-click='modals.delete = true', popover-trigger='mouseenter', popover=env.t('deleteAccPop'))= env.t('deleteAccount')
|
||||
//- Why is ng-if='user.auth.local' validating for users *without* user.auth.local (facebook users)? adding .username here for extra
|
||||
div(ng-if='user.auth.local.username')
|
||||
hr
|
||||
h4=env.t('changePass')
|
||||
form(ng-submit='changePassword(changePass)', ng-show='user.auth.local')
|
||||
.form-group
|
||||
input.form-control(type='password', placeholder=env.t('oldPass'), ng-model='changePass.oldPassword', required)
|
||||
.form-group
|
||||
input.form-control(type='password', placeholder=env.t('newPass'), ng-model='changePass.newPassword', required)
|
||||
.form-group
|
||||
input.form-control(type='password', placeholder=env.t('confirmPass'), ng-model='changePass.confirmNewPassword', required)
|
||||
input.btn.btn-default(type='submit', value=env.t('submit'))
|
||||
|
||||
hr
|
||||
h4=env.t('dangerZone')
|
||||
a.btn.btn-danger(ng-click='openModal("reset", {controller:"SettingsCtrl"})', popover-trigger='mouseenter', popover-placement='right', popover=env.t('resetAccPop'))= env.t('resetAccount')
|
||||
a.btn.btn-danger(ng-click='openModal("delete", {controller:"SettingsCtrl"})', popover-trigger='mouseenter', popover=env.t('deleteAccPop'))= env.t('deleteAccount')
|
||||
|
||||
script(type='text/ng-template', id='partials/options.settings.api.html')
|
||||
.row.fluid
|
||||
.span6
|
||||
h2=env.t('API')
|
||||
small=env.t('APIText')
|
||||
h6=env.t('userId')
|
||||
pre.prettyprint {{user.id}}
|
||||
h6=env.t('APIToken')
|
||||
pre.prettyprint {{user.apiToken}}
|
||||
h6=env.t('qrCode')
|
||||
img(src='https://chart.googleapis.com/chart?cht=qr&chs=200x200&chl=%7B%22address%22%3A%22https%3A%2F%2Fhabitrpg.com%22%2C%22user%22%3A%22{{user.id}}%22%2C%22key%22%3A%22{{user.apiToken}}%22%7D&choe=UTF-8&chld=L', alt='qrcode')
|
||||
.containter-fluid
|
||||
.row
|
||||
.col-md-6
|
||||
h2=env.t('API')
|
||||
small=env.t('APIText')
|
||||
h6=env.t('userId')
|
||||
pre.prettyprint {{user.id}}
|
||||
h6=env.t('APIToken')
|
||||
pre.prettyprint {{user.apiToken}}
|
||||
h6=env.t('qrCode')
|
||||
img(src='https://chart.googleapis.com/chart?cht=qr&chs=200x200&chl=%7B%22address%22%3A%22https%3A%2F%2Fhabitrpg.com%22%2C%22user%22%3A%22{{user.id}}%22%2C%22key%22%3A%22{{user.apiToken}}%22%7D&choe=UTF-8&chld=L', alt='qrcode')
|
||||
|
||||
script(id='partials/options.settings.export.html', type="text/ng-template")
|
||||
.row.fluid
|
||||
.span6
|
||||
h2=env.t('dataExport')
|
||||
small=env.t('saveData')
|
||||
h4=env.t('habitHistory')
|
||||
=env.t('exportHistory')
|
||||
a(href="/export/history.csv")= ' ' + env.t('csv')
|
||||
h4=env.t('userData')
|
||||
=env.t('exportUserData')
|
||||
a(href="/export/userdata.xml")= ' ' + env.t('xml') + ' '
|
||||
a(href="/export/userdata.json")= env.t('json')
|
||||
.containter-fluid
|
||||
.row
|
||||
.col-md-6
|
||||
h2=env.t('dataExport')
|
||||
small=env.t('saveData')
|
||||
h4=env.t('habitHistory')
|
||||
=env.t('exportHistory')
|
||||
a(href="/export/history.csv")= ' ' + env.t('csv')
|
||||
h4=env.t('userData')
|
||||
=env.t('exportUserData')
|
||||
a(href="/export/userdata.xml")= ' ' + env.t('xml') + ' '
|
||||
a(href="/export/userdata.json")= env.t('json')
|
||||
|
||||
script(id='partials/options.settings.subscription.perks.html',type='text/ng-template')
|
||||
table.table.table-striped
|
||||
@@ -153,7 +159,9 @@ script(id='partials/options.settings.subscription.html',type='text/ng-template')
|
||||
|
||||
div(ng-if='user.purchased.plan.customerId')
|
||||
.well
|
||||
div(style='font-size:22px')
|
||||
i.icon-ok=env.t('subscribed')
|
||||
p.lead
|
||||
=env.t('subscribed')
|
||||
|
|
||||
span.glyphicon.glyphicon-ok
|
||||
div(ng-include="'partials/options.settings.subscription.perks.html'")
|
||||
.btn.btn-small.btn-danger(ng-click='cancelSubscription()')=env.t('cancelSub')
|
||||
.btn.btn-sm.btn-danger(ng-click='cancelSubscription()')=env.t('cancelSub')
|
||||
|
||||
@@ -1,18 +1,23 @@
|
||||
// ------ Challenges -------
|
||||
.modal(style='position: relative;top: auto;left: auto;right: auto;margin: 0 auto 20px;z-index: 1;max-width: 100%;')
|
||||
.modal-header
|
||||
h3=env.t('challenges')
|
||||
.panel.panel-default
|
||||
.panel-heading
|
||||
h3.panel-title=env.t('challenges')
|
||||
a.pull-right(target='_blank', href='https://trello.com/card/challenges-individual-party-guild-public/50e5d3684fe3a7266b0036d6/58')
|
||||
i.icon-question-sign
|
||||
.modal-body(bindonce='group.challenges')
|
||||
span.glyphicon.glyphicon-question-sign
|
||||
.panel-body.modal-fixed-height(bindonce='group.challenges')
|
||||
div(ng-if='group.challenges.length > 0')
|
||||
table.table.table-striped
|
||||
tr(ng-repeat='challenge in group.challenges')
|
||||
td
|
||||
a(ui-sref='options.social.challenges.detail({cid:challenge._id})') {{challenge.name}}
|
||||
div(ng-if='group.challenges.length == 0')
|
||||
p=env.t('noChallenges')
|
||||
a(class='label' ui-sref='options.social.challenges')
|
||||
i.icon-bullhorn
|
||||
p
|
||||
|
|
||||
=env.t('noChallenges')
|
||||
|
|
||||
a.label.label-primary(ui-sref='options.social.challenges')
|
||||
span.glyphicon.glyphicon-bullhorn
|
||||
|
|
||||
=env.t('challenges')
|
||||
|
|
||||
=env.t('toCreate')
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
script(type='text/ng-template', id='partials/options.social.challenges.detail.close.html')
|
||||
a.btn.btn-small.btn-danger(ng-click="delete(closingChal)")=env.t('delete')
|
||||
a.btn.btn-sm.btn-danger(ng-click="delete(closingChal)")=env.t('delete')
|
||||
h5= '- ' + env.t('or') + ' -'
|
||||
select(ui-select2, ng-required=true, ng-model='closingChal.winner', data-placeholder=env.t('selectWinner'), ng-change='selectWinner(closingChal)', )
|
||||
option(value='')
|
||||
@@ -9,42 +9,44 @@ script(type='text/ng-template', id='partials/options.social.challenges.detail.cl
|
||||
a(ng-click='cancelClosing(closingChal)')=env.t('cancel')
|
||||
|
||||
script(type='text/ng-template', id='partials/options.social.challenges.detail.member.html')
|
||||
.modal.wide-modal
|
||||
.modal-header
|
||||
button.close(type='button', ng-click='$state.go("^")', aria-hidden='true') ×
|
||||
h3 {{obj.profile.name}}
|
||||
.modal-body
|
||||
habitrpg-tasks(main=false)
|
||||
.modal-footer
|
||||
a.btn(ng-click='$state.go("^")')=env.t('close')
|
||||
.modal.bs-modal-lg(style='display: block')
|
||||
.modal-dialog.modal-lg
|
||||
.modal-content
|
||||
.modal-header
|
||||
button.close(type='button', ng-click='$state.go("^")', aria-hidden='true') ×
|
||||
h3 {{obj.profile.name}}
|
||||
.modal-body
|
||||
habitrpg-tasks(main=false)
|
||||
.modal-footer
|
||||
a.btn.btn-default(ng-click='$state.go("^")')=env.t('close')
|
||||
|
||||
script(type='text/ng-template', id='partials/options.social.challenges.detail.html')
|
||||
// Edit button
|
||||
div(bindonce='challenge', ng-if='challenge.leader==user._id')
|
||||
ul.unstyled
|
||||
li(ng-hide='challenge._locked==false')
|
||||
button.btn.btn-small.btn-default(ng-click='challenge._locked = false')=env.t('edit')
|
||||
button.btn.btn-small.btn-warning(ng-click='close(challenge, $event)', tooltip=env.t('deleteOrSelect'))=env.t('endChallenge')
|
||||
li(ng-show='challenge._locked==false')
|
||||
button.btn.btn-small.btn-primary(ng-click='save(challenge)')=env.t('save')
|
||||
button.btn.btn-small.btn-default(ng-click='challenge._locked=true')=env.t('cancel')
|
||||
div(ng-hide='challenge._locked==false')
|
||||
button.btn.btn-sm.btn-default(ng-click='challenge._locked = false')=env.t('edit')
|
||||
button.btn.btn-sm.btn-warning(ng-click='close(challenge, $event)', tooltip=env.t('deleteOrSelect'))=env.t('endChallenge')
|
||||
|
||||
div(ng-show='challenge._locked==false')
|
||||
.-options
|
||||
input.option-content(type='text', ng-model='challenge.name')
|
||||
.option-medium
|
||||
input.option-content(type='text', minlength="3", maxlength="16", ng-model='challenge.shortName', placeholder=env.t('challengeTag'), required)
|
||||
textarea.option-content(cols='3', placeholder=env.t('challengeDescr'), ng-model='challenge.description')
|
||||
form(ng-show='challenge._locked==false')
|
||||
.form-group(ng-show='challenge._locked==false')
|
||||
button.btn.btn-sm.btn-primary(ng-click='save(challenge)')=env.t('save')
|
||||
button.btn.btn-sm.btn-default(ng-click='challenge._locked=true')=env.t('cancel')
|
||||
.form-group
|
||||
input.form-control(type='text', ng-model='challenge.name')
|
||||
.form-group
|
||||
input.form-control(type='text', minlength="3", maxlength="16", ng-model='challenge.shortName', placeholder=env.t('challengeTag'), required)
|
||||
.form-group
|
||||
textarea.form-control(cols='3', placeholder=env.t('challengeDescr'), ng-model='challenge.description')
|
||||
hr
|
||||
|
||||
.well(bindonce='challenge', ng-if='challenge.description')
|
||||
markdown(ng-model='challenge.description')
|
||||
i.icon-question-sign(popover=env.t('challengeDiscription'), popover-trigger='mouseenter', popover-placement='right')
|
||||
span.glyphicon.glyphicon-question-sign(popover=env.t('challengeDiscription'), popover-trigger='mouseenter', popover-placement='right')
|
||||
habitrpg-tasks(obj='challenge', main=false)
|
||||
|
||||
// Member List
|
||||
div(bindonce='challenge', ng-if='challenge.members.length > 0')
|
||||
a.btn.btn-primary.btn-small.pull-right(href='/api/v2/challenges/{{challenge._id}}/csv')
|
||||
a.btn.btn-primary.btn-sm.pull-right(href='/api/v2/challenges/{{challenge._id}}/csv')
|
||||
=env.t('exportChallengeCSV')
|
||||
h3=env.t('hows')
|
||||
menu
|
||||
@@ -62,94 +64,102 @@ script(type='text/ng-template', id='partials/options.social.challenges.detail.ht
|
||||
div(ui-view)
|
||||
|
||||
script(type='text/ng-template', id='partials/options.social.challenges.html')
|
||||
.row-fluid
|
||||
.span2.well#challenges-filters
|
||||
h3=env.t('filter') + ':'
|
||||
h4=env.t('groups')
|
||||
ul.unstyled
|
||||
a.btn.btn-mini.pull-left(ng-click='selectAll()')=env.t('all')
|
||||
a.btn.btn-mini(ng-click='selectNone()')=env.t('none')
|
||||
br
|
||||
label.checkbox(ng-repeat='group in groupsFilter')
|
||||
input(type='checkbox', ng-model='search.group[group._id]')
|
||||
| {{group.name}}
|
||||
h4=env.t('membership')
|
||||
label.radio
|
||||
input(type='radio', name='search-participation-radio', ng-click='search._isMember = true')
|
||||
=env.t('participating')
|
||||
label.radio
|
||||
input(type='radio', name='search-participation-radio', ng-click='search._isMember = false')
|
||||
=env.t('notParticipating')
|
||||
label.radio
|
||||
input(type='radio', name='search-participation-radio', ng-click='search._isMember = undefined', checked='checked')
|
||||
=env.t('either')
|
||||
.span10
|
||||
// Creation form
|
||||
button.btn.btn-success#create-challenge-btn(ng-click='create()', ng-hide='newChallenge')=env.t('createChallenge')
|
||||
.create-challenge-from.well(ng-if='newChallenge')
|
||||
form(ng-submit='save(newChallenge)')
|
||||
div
|
||||
input.btn.btn-success(type='submit', value=env.t('save'))
|
||||
input.btn.btn-danger(type='button', ng-click='discard()', value=env.t('discard'))
|
||||
select(ng-model='newChallenge.group', ng-required='required', name='Group', ng-options='g._id as g.name for g in groups')
|
||||
.challenge-options
|
||||
input.option-content(type='text', ng-model='newChallenge.name', placeholder=env.t('challengeTitle'), required='required')
|
||||
.container-fluid
|
||||
.row
|
||||
.col-md-2.well#challenges-filters
|
||||
h3=env.t('filter') + ':'
|
||||
h4=env.t('groups')
|
||||
ul.list-unstyled
|
||||
a.btn.btn-xs.btn-default.pull-left(ng-click='selectAll()')=env.t('all')
|
||||
a.btn.btn-xs.btn-default(ng-click='selectNone()')=env.t('none')
|
||||
br
|
||||
.checkbox(ng-repeat='group in groupsFilter')
|
||||
label
|
||||
input(type='checkbox', ng-model='search.group[group._id]')
|
||||
| {{group.name}}
|
||||
h4=env.t('membership')
|
||||
.radio
|
||||
label
|
||||
input(type='radio', name='search-participation-radio', ng-click='search._isMember = true')
|
||||
=env.t('participating')
|
||||
.radio
|
||||
label
|
||||
input(type='radio', name='search-participation-radio', ng-click='search._isMember = false')
|
||||
=env.t('notParticipating')
|
||||
.radio
|
||||
label
|
||||
input(type='radio', name='search-participation-radio', ng-click='search._isMember = undefined', checked='checked')
|
||||
=env.t('either')
|
||||
.col-md-10
|
||||
// Creation form
|
||||
button.btn.btn-success#create-challenge-btn(ng-click='create()', ng-hide='newChallenge')=env.t('createChallenge')
|
||||
.create-challenge-from.well(ng-if='newChallenge')
|
||||
form(ng-submit='save(newChallenge)')
|
||||
div
|
||||
input.btn.btn-success(type='submit', value=env.t('save'))
|
||||
input.btn.btn-danger(type='button', ng-click='discard()', value=env.t('discard'))
|
||||
select(ng-model='newChallenge.group', ng-required='required', name='Group', ng-options='g._id as g.name for g in groups')
|
||||
.challenge-options
|
||||
.form-group
|
||||
input.form-control(type='text', ng-model='newChallenge.name', placeholder=env.t('challengeTitle'), required='required')
|
||||
|
||||
.option-medium
|
||||
input.option-content(type='text', minlength="3", maxlength="16", ng-model='newChallenge.shortName', placeholder=env.t('challengeTag'), required)
|
||||
a(target='_blank', href='http://habitrpg.wikia.com/wiki/Tags')
|
||||
i.icon-question-sign(popover=env.t('challengeTagPop'), popover-trigger='mouseenter', popover-placement='right')
|
||||
.form-group
|
||||
input.form-control(type='text', minlength="3", maxlength="16", ng-model='newChallenge.shortName', placeholder=env.t('challengeTag'), required)
|
||||
a(target='_blank', href='http://habitrpg.wikia.com/wiki/Tags')
|
||||
span.glyphicon.glyphicon-question-sign(popover=env.t('challengeTagPop'), popover-trigger='mouseenter', popover-placement='right')
|
||||
|
||||
textarea.option-content(cols='3', placeholder=env.t('challengeDescr'), ng-model='newChallenge.description')
|
||||
.form-group
|
||||
textarea.form-control(cols='3', placeholder=env.t('challengeDescr'), ng-model='newChallenge.description')
|
||||
|
||||
//- what's going on here?
|
||||
br
|
||||
br
|
||||
//- what's going on here?
|
||||
br
|
||||
br
|
||||
|
||||
.option-medium
|
||||
input.option-content(type='number', min="{{newChallenge.group=='habitrpg' ? 1 : 0}}", max="{{maxPrize}}", ng-model='newChallenge.prize', placeholder=env.t('prize'))
|
||||
span.input-suffix.Pet_Currency_Gem1x.inline-gems
|
||||
i.icon-question-sign(popover=env.t('prizePop'), popover-trigger='mouseenter', popover-placement='right')
|
||||
span(ng-show='newChallenge.group=="habitrpg"')
|
||||
!=env.t('publicChallenges')
|
||||
.form-group
|
||||
input.form-control(type='number', min="{{newChallenge.group=='habitrpg' ? 1 : 0}}", max="{{maxPrize}}", ng-model='newChallenge.prize', placeholder=env.t('prize'))
|
||||
span.input-suffix.Pet_Currency_Gem1x.inline-gems
|
||||
span.glyphicon.glyphicon-question-sign(popover=env.t('prizePop'), popover-trigger='mouseenter', popover-placement='right')
|
||||
span(ng-show='newChallenge.group=="habitrpg"')
|
||||
!=env.t('publicChallenges')
|
||||
|
||||
.option-medium(ng-if='user.contributor.admin')
|
||||
label.checkbox
|
||||
input(type='checkbox', ng-model='newChallenge.official')
|
||||
=env.t('officialChallenge')
|
||||
.form-group(ng-if='user.contributor.admin')
|
||||
.checkbox
|
||||
label
|
||||
input(type='checkbox', ng-model='newChallenge.official')
|
||||
=env.t('officialChallenge')
|
||||
|
||||
habitrpg-tasks(main=false, obj='newChallenge')
|
||||
habitrpg-tasks(main=false, obj='newChallenge')
|
||||
|
||||
// Challenges list
|
||||
.accordion-group(ng-repeat='challenge in challenges|filter:filterChallenges')
|
||||
.accordion-heading
|
||||
ul.pull-right.challenge-accordion-header-specs
|
||||
li(ng-if='challenge.official')
|
||||
span.label.label-success=env.t('officialChallenge')
|
||||
li {{challenge.group.name}}
|
||||
li
|
||||
=env.t('by')
|
||||
strong {{challenge.leader.profile.name}}
|
||||
li
|
||||
| {{challenge.memberCount}}
|
||||
= ' ' + env.t('participants')
|
||||
li(ng-show='challenge.prize')
|
||||
// prize
|
||||
table(ng-show='challenge.prize')
|
||||
tr
|
||||
td {{challenge.prize}}
|
||||
td
|
||||
.Pet_Currency_Gem1x(style='margin-left:0px')
|
||||
td=env.t('prize')
|
||||
li
|
||||
// leave / join
|
||||
a.btn.btn-small.btn-danger(ng-show='challenge._isMember', ng-click='clickLeave(challenge, $event)')
|
||||
i.icon-ban-circle
|
||||
=env.t('leave')
|
||||
a.btn.btn-small.btn-success(ng-hide='challenge._isMember', ng-click='join(challenge)')
|
||||
i.icon-ok
|
||||
=env.t('join')
|
||||
a.accordion-toggle(ng-click='toggle(challenge._id)') {{challenge.name}}
|
||||
.accordion-body(ng-class='{collapse: !$stateParams.cid == challenge._id}')
|
||||
.accordion-inner(ng-if='$stateParams.cid == challenge._id')
|
||||
div(ui-view)
|
||||
// Challenges list
|
||||
.panel-group
|
||||
.panel.panel-default(ng-repeat='challenge in challenges|filter:filterChallenges')
|
||||
.panel-heading
|
||||
ul.pull-right.challenge-accordion-header-specs
|
||||
li(ng-if='challenge.official')
|
||||
span.label.label-success=env.t('officialChallenge')
|
||||
li {{challenge.group.name}}
|
||||
li
|
||||
=env.t('by')
|
||||
strong {{challenge.leader.profile.name}}
|
||||
li
|
||||
| {{challenge.memberCount}}
|
||||
= ' ' + env.t('participants')
|
||||
li(ng-show='challenge.prize')
|
||||
p
|
||||
// prize
|
||||
| {{challenge.prize}}
|
||||
span.inline-block.Pet_Currency_Gem1x
|
||||
|
|
||||
=env.t('prize')
|
||||
li
|
||||
// leave / join
|
||||
a.btn.btn-sm.btn-danger(ng-show='challenge._isMember', ng-click='clickLeave(challenge, $event)')
|
||||
span.glyphicon.glyphicon-ban-circle
|
||||
=env.t('leave')
|
||||
a.btn.btn-sm.btn-success(ng-hide='challenge._isMember', ng-click='join(challenge)')
|
||||
span.glyphicon.glyphicon-ok
|
||||
=env.t('join')
|
||||
a.accordion-toggle(ng-click='toggle(challenge._id)') {{challenge.name}}
|
||||
.panel-body(ng-class='{collapse: !$stateParams.cid == challenge._id}')
|
||||
.accordion-inner(ng-if='$stateParams.cid == challenge._id')
|
||||
div(ui-view)
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
form.chat-form(ng-submit='postChat(group,message.content)')
|
||||
.-options
|
||||
//FIXME ng-model makes this painfully slow! using jquery for now, which is really non-angular-like
|
||||
.control-group.option-large(ng-controller='AutocompleteCtrl')
|
||||
textarea.chat-textarea.option-content(style='height:6em;', ui-keypress='{13:"postChat(group,message.content)"}', ng-model='message.content', updateinterval='250', flag='@', at-user, auto-complete)
|
||||
span.user-list(ng-show='!isAtListHidden')
|
||||
ul.list-at-user
|
||||
li(bindonce='response', ng-repeat='user in response | filter:query.text | limitTo: 5', ng-click='autoComplete(user)')
|
||||
span.username.label(class='label-contributor-{{user.contributor.level}}', ng-class='{"label-npc": user.backer.npc}') {{user.user}}
|
||||
table.pull-right
|
||||
tr
|
||||
td
|
||||
input.btn.chat-btn(type='submit', value=env.t('sendChat'), ng-class='{disabled: _sending == true}')
|
||||
td
|
||||
button.btn(type="button", ng-click='sync(group)', tooltip=env.t('toolTipMsg'))
|
||||
i(class='pull-right icon-refresh')
|
||||
div(ng-controller='AutocompleteCtrl')
|
||||
textarea.form-control(rows=4, ui-keypress='{13:"postChat(group,message.content)"}', ng-model='message.content', updateinterval='250', flag='@', at-user, auto-complete)
|
||||
span.user-list(ng-show='!isAtListHidden')
|
||||
ul.list-at-user
|
||||
li(bindonce='response', ng-repeat='user in response | filter:query.text | limitTo: 5', ng-click='autoComplete(user)')
|
||||
span.username.label.label-default(ng-class='userLevelStyle(user)') {{user.user}}
|
||||
.row
|
||||
.col-md-9
|
||||
include ../../shared/formatting-help
|
||||
.col-md-3
|
||||
input.btn.btn-default.chat-btn(type='submit', value=env.t('sendChat'), ng-class='{disabled: _sending == true}')
|
||||
button.btn.btn-default(type="button", ng-click='sync(group)', tooltip=env.t('toolTipMsg'))
|
||||
span.glyphicon.glyphicon-refresh.pull-right
|
||||
@@ -1,14 +1,16 @@
|
||||
li.chat-message(bindonce='group.chat', ng-repeat='message in group.chat', bo-class='{highlight: isUserMentioned(user,message), "own-message": user._id == message.uuid}')
|
||||
div(class='scrollable-message')
|
||||
a.label.chat-message(class='hidden-label')
|
||||
span {{message.user}}
|
||||
markdown(ng-model='message.text', style='padding:0px 3px')
|
||||
a.label.label-default.chat-message(class='hidden-label')
|
||||
span {{message.user}}
|
||||
|
|
||||
markdown(ng-model='message.text')
|
||||
| -
|
||||
span.muted.time(from-now='message.timestamp',style='padding:0px 3px')
|
||||
span(style='padding:0px 3px')
|
||||
a.label(ng-show='countExists(message.likes)',ng-class='{"label-success":message.likes[user._id]}',ng-click='likeChatMessage(group,message)') +{{countExists(message.likes)}}
|
||||
a.chat-plus-one.muted(ng-show='!countExists(message.likes)',ng-click='likeChatMessage(group,message)',style='background-color:#eee;padding:3px 3px 0px 3px') +1
|
||||
a(bo-show='user.contributor.admin || message.uuid == user.id', ng-click='deleteChatMessage(group, message)',style='padding: 0px 3px')
|
||||
i.icon-trash(tooltip=env.t('delete'))
|
||||
a.label.chat-message(bo-show='message.user', class='float-label', bo-class='{"label-npc": message.backer.npc, "label-contributor-{{message.contributor.level}}":message.contributor.level}', ng-click='clickMember(message.uuid, true)')
|
||||
span.muted.time(from-now='message.timestamp')
|
||||
span
|
||||
a.label.label-default(ng-show='countExists(message.likes)', ng-class='{"label-success":message.likes[user._id]}', ng-click='likeChatMessage(group,message)') +{{countExists(message.likes)}}
|
||||
a.chat-plus-one.muted(ng-show='!countExists(message.likes)', ng-click='likeChatMessage(group,message)') +1
|
||||
|
|
||||
a(bo-show='user.contributor.admin || message.uuid == user.id', ng-click='deleteChatMessage(group, message)')
|
||||
span.glyphicon.glyphicon-trash(tooltip=env.t('delete'))
|
||||
a.label.label-default.chat-message(bo-show='message.user', class='float-label', bo-class='{"label-npc": message.backer.npc, "label-contributor-{{message.contributor.level}}":message.contributor.level}', ng-click='clickMember(message.uuid, true)')
|
||||
span(tooltip='{{contribText(message.contributor, message.backer)}}') {{message.user}}
|
||||
|
||||
@@ -1,27 +1,27 @@
|
||||
form.form-horizontal(ng-submit='create(newGroup)')
|
||||
.control-group.whatever-options
|
||||
.control-group
|
||||
label.control-label(for='new-group-name')
|
||||
| {{text}}
|
||||
=env.t('name')
|
||||
.controls
|
||||
input#new-group-name.input-medium.option-content(required, type='text', placeholder='{{text}} Name', ng-model='newGroup.name')
|
||||
.control-group
|
||||
label.control-label(for='new-group-description')=env.t('description')
|
||||
.controls
|
||||
textarea#new-group-description.option-content(cols='3', placeholder=env.t('description'), ng-model='newGroup.description')
|
||||
.control-group(ng-show='type=="guild"')
|
||||
.controls
|
||||
label.radio
|
||||
input(type='radio', name='new-group-privacy', value='public', ng-model='newGroup.privacy')
|
||||
=env.t('public')
|
||||
label.radio
|
||||
input(type='radio', name='new-group-privacy', value='private', ng-model='newGroup.privacy')
|
||||
=env.t('inviteOnly')
|
||||
input.btn(type='submit', ng-disabled='!newGroup.privacy && !newGroup.name', value=env.t('create'))
|
||||
.container-fluid
|
||||
.row
|
||||
form.col-md-12.form-horizontal(ng-submit='create(newGroup)')
|
||||
.form-group
|
||||
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}} ' + 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')
|
||||
.form-group(ng-show='type=="guild"')
|
||||
.radio
|
||||
label
|
||||
input(type='radio', name='new-group-privacy', value='public', ng-model='newGroup.privacy')
|
||||
=env.t('public')
|
||||
.radio
|
||||
label
|
||||
input(type='radio', name='new-group-privacy', value='private', ng-model='newGroup.privacy')
|
||||
=env.t('inviteOnly')
|
||||
br
|
||||
input.btn.btn-default(type='submit', ng-disabled='!newGroup.privacy && !newGroup.name', value=env.t('create'))
|
||||
span.gem-cost= '4 ' + env.t('gems')
|
||||
p
|
||||
small=env.t('gemCost')
|
||||
.control-group(ng-show='type=="party"')
|
||||
.controls
|
||||
input.btn(type='submit', value=env.t('create'))
|
||||
.form-group(ng-show='type=="party"')
|
||||
input.btn.btn-default.form-control(type='submit', value=env.t('create'))
|
||||
|
||||
@@ -4,174 +4,177 @@ a.pull-right.gem-wallet(popover-trigger='mouseenter', popover-title=env.t('guild
|
||||
.Pet_Currency_Gem2x.Gems
|
||||
| {{group.balance * 4 | number:0 }}
|
||||
=env.t('guildGems')
|
||||
.row-fluid
|
||||
.span4
|
||||
|
||||
.container-fluid
|
||||
.row
|
||||
.col-md-4
|
||||
|
||||
// ------ Bosses -------
|
||||
.modal.inline-modal(bindonce='group', ng-if='group.type==="party" && group.quest.key')
|
||||
.modal-header
|
||||
h3(ng-if='group.quest.active==false')=env.t('questInvitation') + '{{Content.quests[group.quest.key].text}}'
|
||||
h3(ng-if='group.quest.active==true') {{Content.quests[group.quest.key].text}}
|
||||
.modal-body
|
||||
div(ng-if='group.quest.active==false')
|
||||
table.table.table-striped
|
||||
tr(ng-repeat='member in group.members')
|
||||
td {{member.profile.name}}
|
||||
td {{group.quest.members[member._id] === true ? env.t('accepted') : group.quest.members[member._id] === false ? env.t('rejected') : env.t('pending')}}
|
||||
hr
|
||||
.npc_ian.pull-left
|
||||
p=env.t('questStart')
|
||||
button.btn.btn-small.btn-warning(ng-if='!group.quest.leader || group.quest.leader==user._id', ng-click='party.$questAccept({"force":true})')=env.t('begin')
|
||||
//-TODO Cancel button
|
||||
//-TODO Both force-start & cancel should only be available to quest-initiator
|
||||
|
||||
div(ng-if='group.quest.active==true')
|
||||
div(ng-if='Content.quests[group.quest.key].boss')
|
||||
div(class="quest_{{group.quest.key}}")
|
||||
//-
|
||||
.progress(style="height:10px")
|
||||
.bar(style='width: {{Shared.percent(group.quest.hp, Content.quests[group.quest.key].hp)}}%;')
|
||||
span.meter-text
|
||||
i.icon-heart
|
||||
| {{group.quest.hp | number:0}} / {{Content.quests[group.quest.key].hp}}
|
||||
.hero-stats
|
||||
.meter.health(title=env.t('bossHP'))
|
||||
.bar(style='width: {{Shared.percent(group.quest.progress.hp, Content.quests[group.quest.key].boss.hp)}}%;')
|
||||
span.meter-text
|
||||
i.icon-heart
|
||||
| {{group.quest.progress.hp | number:0}} / {{Content.quests[group.quest.key].boss.hp}}
|
||||
|
||||
div(ng-if='Content.quests[group.quest.key].collect')
|
||||
h4=env.t('collected') + ':'
|
||||
// ------ Bosses -------
|
||||
.panel.panel-default(bindonce='group', ng-if='group.type==="party" && group.quest.key')
|
||||
.panel-heading
|
||||
h3.panel-title(ng-if='group.quest.active==false')=env.t('questInvitation') + ' {{Content.quests[group.quest.key].text}}'
|
||||
h3.panel-title(ng-if='group.quest.active==true') {{Content.quests[group.quest.key].text}}
|
||||
.panel-body.modal-fixed-height
|
||||
div(ng-if='group.quest.active==false')
|
||||
table.table.table-striped
|
||||
tr(ng-repeat='(k,v) in group.quest.progress.collect', class='quest_collected_{{v >= Content.quests[group.quest.key].collect[k].count}}')
|
||||
td
|
||||
div.pull-left(class='quest_{{group.quest.key}}_{{k}}')
|
||||
| {{Content.quests[group.quest.key].collect[k].text}}
|
||||
td
|
||||
{{v}} / {{Content.quests[group.quest.key].collect[k].count}}
|
||||
tr(ng-repeat='member in group.members')
|
||||
td {{member.profile.name}}
|
||||
td {{group.quest.members[member._id] === true ? env.t('accepted') : group.quest.members[member._id] === false ? env.t('rejected') : env.t('pending')}}
|
||||
hr
|
||||
.npc_ian.pull-left
|
||||
p=env.t('questStart')
|
||||
button.btn.btn-sm.btn-warning(ng-if='!group.quest.leader || group.quest.leader==user._id', ng-click='party.$questAccept({"force":true})')=env.t('begin')
|
||||
//-TODO Cancel button
|
||||
//-TODO Both force-start & cancel should only be available to quest-initiator
|
||||
|
||||
div(ng-bind-html='Content.quests[group.quest.key].notes')
|
||||
div(ng-if='group.quest.active==true')
|
||||
div(ng-if='Content.quests[group.quest.key].boss')
|
||||
div(class="quest_{{group.quest.key}}")
|
||||
//-
|
||||
.progress
|
||||
.bar(style='width: {{Shared.percent(group.quest.hp, Content.quests[group.quest.key].hp)}}%;')
|
||||
span.meter-text
|
||||
span.glyphicon.glyphicon-heart
|
||||
| {{group.quest.hp | number:0}} / {{Content.quests[group.quest.key].hp}}
|
||||
.hero-stats
|
||||
.meter.health(title=env.t('bossHP'))
|
||||
.bar(style='width: {{Shared.percent(group.quest.progress.hp, Content.quests[group.quest.key].boss.hp)}}%;')
|
||||
span.meter-text
|
||||
span.glyphicon.glyphicon-heart
|
||||
| {{group.quest.progress.hp | number:0}} / {{Content.quests[group.quest.key].boss.hp}}
|
||||
|
||||
div(ng-if='Content.quests[group.quest.key].collect')
|
||||
h4=env.t('collected') + ':'
|
||||
table.table.table-striped
|
||||
tr(ng-repeat='(k,v) in group.quest.progress.collect', class='quest_collected_{{v >= Content.quests[group.quest.key].collect[k].count}}')
|
||||
td
|
||||
div.pull-left(class='quest_{{group.quest.key}}_{{k}}')
|
||||
| {{Content.quests[group.quest.key].collect[k].text}}
|
||||
td
|
||||
{{v}} / {{Content.quests[group.quest.key].collect[k].count}}
|
||||
|
||||
div(ng-bind-html='Content.quests[group.quest.key].notes')
|
||||
hr
|
||||
h5=env.t('participants')
|
||||
table.table.table-striped
|
||||
tr(ng-repeat='(k,v) in group.members', ng-show='group.quest.members[v._id]')
|
||||
td {{v.profile.name}}
|
||||
quest-rewards(key='{{group.quest.key}}')
|
||||
|
||||
div(ng-if='Content.quests[group.quest.key].boss')
|
||||
.npc_ian.pull-left
|
||||
p!=env.t('bossDmg1')
|
||||
br
|
||||
p=env.t('bossDmg2')
|
||||
|
||||
div(ng-if='Content.quests[group.quest.key].collect')
|
||||
.npc_ian.pull-left
|
||||
p=env.t('bossColl1')
|
||||
br
|
||||
p=env.t('bossColl2')
|
||||
|
||||
|
||||
button.btn.btn-xs.btn-danger(ng-if='!group.quest.leader || group.quest.leader==user._id', ng-click='questAbort()')=env.t('abort')
|
||||
|
||||
// ------ Information -------
|
||||
.panel.panel-default
|
||||
.panel-heading(bindonce='group')
|
||||
h3.panel-title
|
||||
| {{group.name}}
|
||||
span(ng-if='group.leader == user.id')
|
||||
button.btn.btn-primary.pull-right(ng-click='save(group)', ng-show='group._editing')=env.t('save')
|
||||
button.btn.btn-default.pull-right(ng-click='group._editing = true', ng-hide='group._editing')=env.t('editGroup')
|
||||
|
||||
.panel-body
|
||||
form(ng-show='group._editing')
|
||||
.form-group
|
||||
label=env.t('groupName')
|
||||
input.form-control(type='text', ng-model='group.name', placeholder=env.t('groupName'))
|
||||
.form-group
|
||||
label=env.t('description')
|
||||
textarea.form-control(rows=6, ng-model='group.description')
|
||||
include ../../shared/formatting-help
|
||||
.form-group
|
||||
label=env.t('logoUrl')
|
||||
input.form-control(type='url', placeholder=env.t('logoUrl'), ng-model='group.logo')
|
||||
|
||||
h4=env.t('assignLeader')
|
||||
select#group-leader-selection(ng-model='group._newLeader', ng-options='member.profile.name for member in group.members')
|
||||
|
||||
div(ng-show='!group._editing')
|
||||
img.pull-right(ng-show='group.logo', ng-src='{{group.logo}}')
|
||||
markdown(ng-model='group.description')
|
||||
hr
|
||||
h5=env.t('participants')
|
||||
small.muted Group ID: {{group._id}}
|
||||
|
||||
include ./challenge-box
|
||||
|
||||
// ------ Members -------
|
||||
.panel.panel-default
|
||||
.panel-heading
|
||||
h3.panel-title=env.t('members')
|
||||
.panel-body.modal-fixed-height
|
||||
span
|
||||
=env.t('partyList')
|
||||
|
|
||||
select#partyOrder(
|
||||
ng-model='user.party.order',
|
||||
ng-controller='ChatCtrl',
|
||||
ng-options='k as v for (k , v) in partyOrderChoices',
|
||||
ng-change='set({"party.order": user.party.order})'
|
||||
)
|
||||
table.table.table-striped(bindonce='group')
|
||||
tr(ng-repeat='member in group.members')
|
||||
td
|
||||
// allow leaders to ban members
|
||||
div(ng-show='group.leader == user.id && user.id!=member._id')
|
||||
a(ng-click='removeMember(group, member, true)')
|
||||
span.glyphicon.glyphicon-ban-circle(tooltip=env.t('banTip'))
|
||||
a
|
||||
span(ng-class='{"badge badge-info": group.leader==member._id}', ng-click='clickMember(member._id, true)')
|
||||
| {{member.profile.name}}
|
||||
tr(ng-if='group.memberCount > group.members.length')
|
||||
td
|
||||
|<span class='badge'>{{group.memberCount - group.members.length}}
|
||||
= ' ' + env.t('moreMembers')
|
||||
|</span>
|
||||
|
||||
h4(ng-show='group.invites.length > 0')=env.t('invited')
|
||||
table.table.table-striped
|
||||
tr(ng-repeat='(k,v) in group.members', ng-show='group.quest.members[v._id]')
|
||||
td {{v.profile.name}}
|
||||
quest-rewards(key='{{group.quest.key}}')
|
||||
|
||||
div(ng-if='Content.quests[group.quest.key].boss')
|
||||
.npc_ian.pull-left
|
||||
p!=env.t('bossDmg1')
|
||||
br
|
||||
p=env.t('bossDmg2')
|
||||
|
||||
div(ng-if='Content.quests[group.quest.key].collect')
|
||||
.npc_ian.pull-left
|
||||
p=env.t('bossColl1')
|
||||
br
|
||||
p=env.t('bossColl2')
|
||||
tr(ng-repeat='invite in group.invites')
|
||||
td
|
||||
// allow leaders to ban members
|
||||
div(ng-show='group.leader == user.id')
|
||||
a(ng-click='removeMember(group, invite, false)')
|
||||
span.glyphicon.glyphicon-ban-circle(tooltip=env.t('banTip'))
|
||||
a
|
||||
span(ng-click='clickMember(invite._id, true)')
|
||||
| {{invite.profile.name}}
|
||||
.panel-footer
|
||||
form.form-inline(ng-submit='invite(group)')
|
||||
//.alert.alert-danger(ng-show='_groupError') {{_groupError}}
|
||||
.form-group
|
||||
input.form-control(type='text', placeholder=env.t('userId'), ng-model='group.invitee')
|
||||
|
||||
input.btn.btn-default(type='submit', value=env.t('invite'))
|
||||
|
||||
|
||||
button.btn.btn-mini.btn-danger(ng-if='!group.quest.leader || group.quest.leader==user._id', ng-click='questAbort()')=env.t('abort')
|
||||
a.btn.btn-danger(data-id='{{group.id}}', ng-click='clickLeave(group, $event)')=env.t('leave')
|
||||
|
||||
// ------ Information -------
|
||||
.modal.inline-modal
|
||||
.modal-header(bindonce='group')
|
||||
span(ng-if='group.leader == user.id')
|
||||
button.btn.btn-primary.pull-right(ng-click='save(group)', ng-show='group._editing')=env.t('save')
|
||||
button.btn.btn-default.pull-right(ng-click='group._editing = true', ng-hide='group._editing')=env.t('editGroup')
|
||||
h3 {{group.name}}
|
||||
.modal-body
|
||||
div.whatever-options(ng-show='group._editing')
|
||||
.control-group.option-large
|
||||
label.control-labe=env.t('groupName')
|
||||
input.option-content(type='text', ng-model='group.name', placeholder=env.t('groupName'))
|
||||
.control-group.option-large
|
||||
label.control-label=env.t('description')
|
||||
textarea.option-content(style='height:15em;', placeholder=env.t('groupDescr'), ng-model='group.description')
|
||||
.control-group.option-large
|
||||
label.control-label=env.t('logoUrl')
|
||||
input.option-content(type='url', placeholder=env.t('logoUrl'), ng-model='group.logo')
|
||||
.col-md-8
|
||||
div()
|
||||
textarea.form-control(ng-show='group._editing', rows=6, placeholder=env.t('leaderMsg'), ng-model='group.leaderMessage')
|
||||
table(ng-show='group.leaderMessage')
|
||||
tr
|
||||
td
|
||||
.popover.static-popover.fade.right.in.wide-popover
|
||||
.arrow
|
||||
h3.popover-title {{Members.members[group.leader].profile.name}}
|
||||
.popover-content
|
||||
markdown(ng-model='group.leaderMessage')
|
||||
div(ng-controller='ChatCtrl')
|
||||
h3=env.t('chat')
|
||||
include ./chat-box
|
||||
|
||||
h4=env.t('assignLeader')
|
||||
select#group-leader-selection(ng-model='group._newLeader', ng-options='member.profile.name for member in group.members')
|
||||
|
||||
div(ng-show='!group._editing')
|
||||
img.pull-right(ng-show='group.logo', style='max-width:150px', ng-src='{{group.logo}}')
|
||||
markdown(ng-model='group.description')
|
||||
hr
|
||||
small.muted Group ID: {{group._id}}
|
||||
|
||||
include ./challenge-box
|
||||
|
||||
// ------ Members -------
|
||||
.modal.inline-modal
|
||||
.modal-header
|
||||
h3=env.t('members')
|
||||
.modal-body
|
||||
span
|
||||
=env.t('partyList')
|
||||
select#partyOrder(
|
||||
style='width:140px',
|
||||
ng-model='user.party.order',
|
||||
ng-controller='ChatCtrl',
|
||||
ng-options='k as v for (k , v) in partyOrderChoices',
|
||||
ng-change='set({"party.order": user.party.order})'
|
||||
)
|
||||
table.table.table-striped(bindonce='group')
|
||||
tr(ng-repeat='member in group.members')
|
||||
td
|
||||
// allow leaders to ban members
|
||||
div(ng-show='group.leader == user.id && user.id!=member._id')
|
||||
a(ng-click='removeMember(group, member, true)')
|
||||
i.icon-ban-circle(tooltip=env.t('banTip'))
|
||||
a
|
||||
span(ng-class='{"badge badge-info": group.leader==member._id}', ng-click='clickMember(member._id, true)')
|
||||
| {{member.profile.name}}
|
||||
tr(ng-if='group.memberCount > group.members.length')
|
||||
td
|
||||
|<span class='badge'>{{group.memberCount - group.members.length}}
|
||||
= ' ' + env.t('moreMembers')
|
||||
|</span>
|
||||
|
||||
h4(ng-show='group.invites.length > 0')=env.t('invited')
|
||||
table.table.table-striped
|
||||
tr(ng-repeat='invite in group.invites')
|
||||
td
|
||||
// allow leaders to ban members
|
||||
div(ng-show='group.leader == user.id')
|
||||
a(ng-click='removeMember(group, invite, false)')
|
||||
i.icon-ban-circle(tooltip=env.t('banTip'))
|
||||
a
|
||||
span(ng-click='clickMember(invite._id, true)')
|
||||
| {{invite.profile.name}}
|
||||
.modal-footer.whatever-options
|
||||
form.form-inline(ng-submit='invite(group)')
|
||||
//.alert.alert-danger(ng-show='_groupError') {{_groupError}}
|
||||
.control-group.option-large
|
||||
input.option-content(type='text', placeholder=env.t('userId'), ng-model='group.invitee')
|
||||
input.btn(type='submit', value=env.t('invite'))
|
||||
|
||||
|
||||
a.btn.btn-danger(data-id='{{group.id}}', ng-click='clickLeave(group, $event)')=env.t('leave')
|
||||
|
||||
.span8
|
||||
div.blah-options(ng-show='group._editing')
|
||||
.option-large
|
||||
textarea.option-content(style='height:15em;', placeholder=env.t('leaderMsg'), ng-model='group.leaderMessage')
|
||||
table(ng-show='group.leaderMessage')
|
||||
tr
|
||||
td
|
||||
.popover.static-popover.fade.right.in.wide-popover
|
||||
.arrow
|
||||
h3.popover-title {{Members.members[group.leader].profile.name}}
|
||||
.popover-content
|
||||
markdown(ng-model='group.leaderMessage')
|
||||
div(ng-controller='ChatCtrl')
|
||||
h3=env.t('chat')
|
||||
include ./chat-box
|
||||
include ../../shared/formatting-help
|
||||
|
||||
ul.unstyled.tavern-chat
|
||||
include ./chat-message
|
||||
ul.list-unstyled.tavern-chat
|
||||
include ./chat-message
|
||||
|
||||
@@ -12,83 +12,83 @@ script(type='text/ng-template', id='partials/options.social.hall.html')
|
||||
div(ui-view)
|
||||
|
||||
script(type='text/ng-template', id='partials/options.social.hall.heroes.html')
|
||||
div.well(ng-if='user.contributor.admin')
|
||||
.well(ng-if='user.contributor.admin')
|
||||
h2=env.t('rewardUser')
|
||||
form.form-horizontal(ng-submit='loadHero(_heroID)')
|
||||
.-options
|
||||
.option-group.option-large
|
||||
input.option-content(type='text', ng-model='_heroID', placeholder=env.t('UUID'))
|
||||
button.btn(type='submit')=env.t('loadUser')
|
||||
form.form-horizontal(ng-show='hero', ng-submit='saveHero(hero)')
|
||||
form(ng-submit='loadHero(_heroID)')
|
||||
.form-group
|
||||
input.form-control(type='text', ng-model='_heroID', placeholder=env.t('UUID'))
|
||||
.form-group
|
||||
input.btn.btn-default(type='submit')=env.t('loadUser')
|
||||
form(ng-show='hero', ng-submit='saveHero(hero)')
|
||||
h3 {{hero.profile.name}}
|
||||
.-options
|
||||
.control-group.option-large
|
||||
input.option-content(type='text', ng-model='hero.contributor.text', placeholder=env.t('contribTitle'))
|
||||
.control-group.option-medium
|
||||
input.option-content(type='number', step="any", ng-model='hero.contributor.level')
|
||||
span.input-suffix=env.t('contribLevel')
|
||||
br
|
||||
small=env.t('contribHallText')
|
||||
a(target='_blank', href='https://trello.com/c/wkFzONhE/277-contributor-gear')=env.t('moreDetails')
|
||||
.control-group.option-large
|
||||
textarea.option-content(style='height:15em;', placeholder=env.t('contributions'), ng-model='hero.contributor.contributions')
|
||||
//-include ../../shared/formatting-help
|
||||
.control-group.option-medium
|
||||
label.checkbox
|
||||
.form-group
|
||||
input.form-control(type='text', ng-model='hero.contributor.text', placeholder=env.t('contribTitle'))
|
||||
.form-group
|
||||
label=env.t('contribLevel')
|
||||
input.form-control(type='number', step="any", ng-model='hero.contributor.level')
|
||||
small=env.t('contribHallText')
|
||||
a(target='_blank', href='https://trello.com/c/wkFzONhE/277-contributor-gear')=env.t('moreDetails')
|
||||
.form-group
|
||||
textarea.form-control(cols=5, placeholder=env.t('contributions'), ng-model='hero.contributor.contributions')
|
||||
include ../../shared/formatting-help
|
||||
.form-group
|
||||
.checkbox
|
||||
label
|
||||
input(type='checkbox', ng-model='hero.contributor.admin')
|
||||
=env.t('admin')
|
||||
|
||||
hr
|
||||
|
||||
.control-group.option-medium
|
||||
input.option-content(type='number', step="any", ng-model='hero.balance')
|
||||
span.input-suffix=env.t('balance')
|
||||
p
|
||||
small!= '`user.balance`' + env.t('notGems')
|
||||
.form-group
|
||||
label=env.t('balance')
|
||||
input.form-control(type='number', step="any", ng-model='hero.balance')
|
||||
small!= '`user.balance`' + env.t('notGems')
|
||||
|
||||
.control-group.option-medium
|
||||
label.checkbox
|
||||
input(type='checkbox', ng-model='hero.purchased.ads')
|
||||
=env.t('hideAds')
|
||||
.form-group
|
||||
.checkbox
|
||||
label
|
||||
input(type='checkbox', ng-model='hero.purchased.ads')
|
||||
=env.t('hideAds')
|
||||
|
||||
// h4 Backer Status
|
||||
// Add backer stuff like tier, disable adds, etcs
|
||||
button.btn-primary(type='submit')=env.t('save')
|
||||
// h4 Backer Status
|
||||
// Add backer stuff like tier, disable adds, etcs
|
||||
.form-group
|
||||
input.form-control.btn.btn-primary(type='submit')=env.t('save')
|
||||
|
||||
|
||||
table.table.table-striped
|
||||
tr
|
||||
thead
|
||||
tr
|
||||
th=env.t('name')
|
||||
th(ng-if='user.contributor.admin')=env.t('UUID')
|
||||
th=env.t('contribLevel')
|
||||
th=env.t('title')
|
||||
th=env.t('contributions')
|
||||
tr(ng-repeat='hero in heroes')
|
||||
td
|
||||
span(ng-if='hero.contributor.admin',popover=env.t('gamemaster'),popover-trigger='mouseenter',popover-placement='right')
|
||||
a.label(class='label-contributor-{{hero.contributor.level}}', ng-class='{"label-npc": hero.backer.npc}', ng-click='clickMember(hero._id, true)')
|
||||
| {{hero.profile.name}}
|
||||
i.icon-star.icon-white
|
||||
span(ng-if='!hero.contributor.admin')
|
||||
a.label(class='label-contributor-{{hero.contributor.level}}', ng-class='{"label-npc": hero.backer.npc}', ng-click='clickMember(hero._id, true)') {{hero.profile.name}}
|
||||
td(ng-if='user.contributor.admin') {{hero._id}}
|
||||
td {{hero.contributor.level}}
|
||||
td {{hero.contributor.text}}
|
||||
td
|
||||
markdown(ng-model='hero.contributor.contributions', target='_blank')
|
||||
thead
|
||||
tr
|
||||
th=env.t('name')
|
||||
th(ng-if='user.contributor.admin')=env.t('UUID')
|
||||
th=env.t('contribLevel')
|
||||
th=env.t('title')
|
||||
th=env.t('contributions')
|
||||
tbody
|
||||
tr(ng-repeat='hero in heroes')
|
||||
td
|
||||
span(ng-if='hero.contributor.admin',popover=env.t('gamemaster'),popover-trigger='mouseenter',popover-placement='right')
|
||||
a.label.label-default(ng-class='userLevelStyle(hero)', ng-click='clickMember(hero._id, true)')
|
||||
| {{hero.profile.name}}
|
||||
span.glyphicon.glyphicon-star
|
||||
span(ng-if='!hero.contributor.admin')
|
||||
a.label.label-default(ng-class='userLevelStyle(hero)', ng-click='clickMember(hero._id, true)') {{hero.profile.name}}
|
||||
td(ng-if='user.contributor.admin') {{hero._id}}
|
||||
td {{hero.contributor.level}}
|
||||
td {{hero.contributor.text}}
|
||||
td
|
||||
markdown(ng-model='hero.contributor.contributions', target='_blank')
|
||||
|
||||
script(type='text/ng-template', id='partials/options.social.hall.patrons.html')
|
||||
table.table.table-striped(infinite-scroll="loadMore()")
|
||||
tr
|
||||
thead
|
||||
tr
|
||||
th=env.t('name')
|
||||
th(ng-if='user.contributor.admin')=env.t('UUID')
|
||||
th=env.t('backerTier')
|
||||
tr(ng-repeat='patron in patrons')
|
||||
td
|
||||
a.label(class='label-contributor-{{patron.contributor.level}}', ng-class='{"label-npc": patron.backer.npc}', ng-click='clickMember(patron._id, true)') {{patron.profile.name}}
|
||||
td(ng-if='user.contributor.admin') {{patron._id}}
|
||||
td {{patron.backer.tier}}
|
||||
thead
|
||||
tr
|
||||
th=env.t('name')
|
||||
th(ng-if='user.contributor.admin')=env.t('UUID')
|
||||
th=env.t('backerTier')
|
||||
tbody
|
||||
tr(ng-repeat='patron in patrons')
|
||||
td
|
||||
a.label.label-default(ng-class='userLevelStyle(patron)', ng-click='clickMember(patron._id, true)') {{patron.profile.name}}
|
||||
td(ng-if='user.contributor.admin') {{patron._id}}
|
||||
td {{patron.backer.tier}}
|
||||
|
||||
@@ -7,13 +7,12 @@ include ./hall.jade
|
||||
script(type='text/ng-template', id='partials/options.social.tavern.html')
|
||||
include ./tavern
|
||||
|
||||
|
||||
script(type='text/ng-template', id='partials/options.social.party.html')
|
||||
div(ng-show='group._id')
|
||||
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') + ' {{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')
|
||||
@@ -30,12 +29,12 @@ 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') + ' {{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
|
||||
.options-group.option-large.whatever-options
|
||||
input.option-content(type='text',ng-model='guildSearch', placeholder=env.t('search'))
|
||||
.col-md-3
|
||||
input.form-control(type='text',ng-model='guildSearch', placeholder=env.t('search'))
|
||||
table.table.table-striped
|
||||
tr(ng-repeat='group in groups.public | filter:guildSearch')
|
||||
td
|
||||
@@ -43,11 +42,11 @@ script(type='text/ng-template', id='partials/options.social.guilds.public.html')
|
||||
li='{{group.memberCount}} ' + env.t('members')
|
||||
li
|
||||
// join / leave
|
||||
a.btn.btn-small.btn-danger(ng-show='group._isMember', ng-click='clickLeave(group, $event)')
|
||||
i.icon-ban-circle
|
||||
a.btn.btn-sm.btn-danger(ng-show='group._isMember', ng-click='clickLeave(group, $event)')
|
||||
span.glyphicon.glyphicon-ban-circle
|
||||
=env.t('leave')
|
||||
a.btn.btn-small.btn-success(ng-hide='group._isMember', ng-click='join(group)')
|
||||
i.icon-ok
|
||||
a.btn.btn-sm.btn-success(ng-hide='group._isMember', ng-click='join(group)')
|
||||
span.glyphicon.glyphicon-ok
|
||||
=env.t('join')
|
||||
h4 {{group.name}}
|
||||
p {{group.description}}
|
||||
@@ -78,7 +77,8 @@ script(type='text/ng-template', id='partials/options.social.html')
|
||||
ul.nav.nav-tabs
|
||||
li(ng-class="{ active: $state.includes('options.social.tavern') }")
|
||||
a(ui-sref='options.social.tavern')
|
||||
i.icon-eye-close
|
||||
span.glyphicon.glyphicon-eye-close
|
||||
|
|
||||
=env.t('tavern')
|
||||
li(ng-class="{ active: $state.includes('options.social.party') }")
|
||||
a(ui-sref='options.social.party')
|
||||
@@ -88,11 +88,13 @@ script(type='text/ng-template', id='partials/options.social.html')
|
||||
=env.t('guilds')
|
||||
li(ng-class="{ active: $state.includes('options.social.challenges') }")
|
||||
a(ui-sref='options.social.challenges')
|
||||
i.icon-bullhorn
|
||||
span.glyphicon.glyphicon-bullhorn
|
||||
|
|
||||
=env.t('challenges')
|
||||
li(ng-class="{ active: $state.includes('options.social.hall') }")
|
||||
a(ui-sref='options.social.hall')
|
||||
i.icon-flag
|
||||
span.glyphicon.glyphicon-flag
|
||||
|
|
||||
=env.t('hall')
|
||||
|
||||
.tab-content
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
.row-fluid
|
||||
.span4
|
||||
.tavern-pane
|
||||
.container-fluid
|
||||
.row
|
||||
.col-md-4
|
||||
table
|
||||
tr
|
||||
td
|
||||
@@ -13,115 +13,112 @@
|
||||
.popover-content
|
||||
=env.t('danielText')
|
||||
div
|
||||
button.btn.btn-large.btn-success(ng-class='{active: user.preferences.sleep}', ng-click='User.user.ops.sleep({})')
|
||||
button.btn.btn-lg.btn-success(ng-class='{active: user.preferences.sleep}', ng-click='User.user.ops.sleep({})')
|
||||
span(ng-show='user.preferences.sleep')=env.t('innCheckOut')
|
||||
span(ng-hide='user.preferences.sleep')=env.t('innCheckIn')
|
||||
.alert.alert-info(ng-show='user.preferences.sleep')
|
||||
=env.t('innText')
|
||||
.alert.alert-info(ng-show='user.preferences.sleep')
|
||||
=env.t('innText')
|
||||
|
||||
// Resources
|
||||
.modal(style='position: relative;top: auto;left: auto;right: auto;margin: 0 auto 20px;z-index: 1;max-width: 100%;')
|
||||
.modal-header
|
||||
h3=env.t('resources')
|
||||
.modal-body
|
||||
table.table.table-striped
|
||||
tr
|
||||
td
|
||||
a(target='_blank', href='http://habitrpg.wikia.com/wiki/Board:Looking_for_a_Group_(LFG)')=env.t('lfgPosts')
|
||||
tr
|
||||
td
|
||||
a(target='_blank', href='https://vimeo.com/57654086')=env.t('tutorial')
|
||||
tr
|
||||
td
|
||||
a(target='_blank', href='http://habitrpg.wikia.com/wiki/FAQ')=env.t('FAQ')
|
||||
tr
|
||||
td
|
||||
a(target='_blank', href='http://habitrpg.wikia.com/wiki/Glossary')=env.t('glossary')
|
||||
tr
|
||||
td
|
||||
a(target='_blank', href='https://github.com/HabitRPG/habitrpg/issues')=env.t('reportAP')
|
||||
tr
|
||||
td
|
||||
a(target='_blank', href='https://trello.com/c/8gzGlle8')=env.t('requestAF')
|
||||
tr
|
||||
td
|
||||
a(target='_blank', href='http://habitrpg.wikia.com/wiki/Special:Forum')=env.t('community')
|
||||
// Resources
|
||||
.panel.panel-default
|
||||
.panel-heading
|
||||
h3.panel-title=env.t('resources')
|
||||
.panel-body
|
||||
table.table.table-striped
|
||||
tr
|
||||
td
|
||||
a(target='_blank', href='http://habitrpg.wikia.com/wiki/Board:The_Archery_-_LFG')=env.t('lfgPosts')
|
||||
tr
|
||||
td
|
||||
a(target='_blank', href='https://vimeo.com/57654086')=env.t('tutorial')
|
||||
tr
|
||||
td
|
||||
a(target='_blank', href='http://habitrpg.wikia.com/wiki/FAQ')=env.t('FAQ')
|
||||
tr
|
||||
td
|
||||
a(target='_blank', href='http://habitrpg.wikia.com/wiki/Glossary')=env.t('glossary')
|
||||
tr
|
||||
td
|
||||
a(target='_blank', href='https://github.com/HabitRPG/habitrpg/issues/2760')=env.t('reportAP')
|
||||
tr
|
||||
td
|
||||
a(target='_blank', href='https://trello.com/c/8gzGlle8')= ' ' + env.t('requestAF')
|
||||
tr
|
||||
td
|
||||
a(target='_blank', href='http://habitrpg.wikia.com/wiki/Special:Forum')=env.t('community')
|
||||
|
||||
// Player Tiers
|
||||
.modal(style='position: relative;top: auto;left: auto;right: auto;margin: 0 auto 20px;z-index: 1;max-width: 100%;', popover=env.t('tierPop'), popover-trigger="mouseenter", popover-placement="right")
|
||||
.modal-header
|
||||
h3=env.t('playerTiers')
|
||||
.modal-body
|
||||
small
|
||||
|<a href='/#/options/groups/hall'>
|
||||
=env.t('visitHeroes')
|
||||
|</a> <br />
|
||||
|<a href='http://habitrpg.wikia.com/wiki/Contributor_Rewards' target='_blank'>
|
||||
=env.t('conLearn')
|
||||
|</a> <br />
|
||||
|<a href='http://habitrpg.wikia.com/wiki/Contributing_to_HabitRPG' target='_blank'>
|
||||
=env.t('conLearnHow')
|
||||
|</a>
|
||||
table.table.table-striped
|
||||
tr
|
||||
td
|
||||
a.label.label-contributor-1(ng-click='toggleUserTier($event)')=env.t('friendBadge')
|
||||
div(style='display:none;')
|
||||
p
|
||||
span.achievement.achievement-firefox
|
||||
!=env.t('friendFirst')
|
||||
hr
|
||||
p
|
||||
span.shop-sprite.item-img(class='shop_armor_special_1')
|
||||
!=env.t('friendSecond')
|
||||
tr
|
||||
td
|
||||
a.label.label-contributor-3(ng-click='toggleUserTier($event)')=env.t('eliteBadge')
|
||||
div(style='display:none;')
|
||||
p
|
||||
span.shop-sprite.item-img(class='shop_head_special_1')
|
||||
!=env.t('eliteThird')
|
||||
hr
|
||||
p
|
||||
span.shop-sprite.item-img(class='shop_weapon_special_1')
|
||||
!=env.t('eliteFourth')
|
||||
tr
|
||||
td
|
||||
a.label.label-contributor-5(ng-click='toggleUserTier($event)')=env.t('championBadge')
|
||||
div(style='display:none;')
|
||||
p
|
||||
span.shop-sprite.item-img(class='shop_shield_special_1')
|
||||
!=env.t('championFifth')
|
||||
hr
|
||||
p
|
||||
div(class='Pet-Dragon-Hydra pull-left')
|
||||
!=env.t('championSixth')
|
||||
tr
|
||||
td
|
||||
a.label.label-contributor-7(ng-click='toggleUserTier($event)')=env.t('legendaryBadge')
|
||||
div(style='display:none;')
|
||||
p
|
||||
!=env.t('legSeventh')
|
||||
tr
|
||||
td
|
||||
a.label.label-contributor-8(ng-click='toggleUserTier($event)')=env.t('heroicBadge')
|
||||
div(style='display:none;')
|
||||
p=env.t('heroicText')
|
||||
tr
|
||||
td
|
||||
a.label.label-npc(ng-click='toggleUserTier($event)')=env.t('npc')
|
||||
div(style='display:none;')
|
||||
p=env.t('npcText')
|
||||
// Player Tiers
|
||||
.panel.panel-default(popover=env.t('tierPop'), popover-trigger="mouseenter", popover-placement="right")
|
||||
.panel-heading
|
||||
h3.panel-title=env.t('playerTiers')
|
||||
.panel-body
|
||||
small
|
||||
|<a href='/#/options/groups/hall'>
|
||||
=env.t('visitHeroes')
|
||||
|</a> <br />
|
||||
|<a href='http://habitrpg.wikia.com/wiki/Contributor_Rewards' target='_blank'>
|
||||
=env.t('conLearn')
|
||||
|</a> <br />
|
||||
|<a href='http://habitrpg.wikia.com/wiki/Contributing_to_HabitRPG' target='_blank'>
|
||||
=env.t('conLearnHow')
|
||||
|</a>
|
||||
table.table.table-striped.panel-tiers
|
||||
tr
|
||||
td
|
||||
a.label.label-contributor-1(ng-click='toggleUserTier($event)')=env.t('friend') + ' (1-2)'
|
||||
div
|
||||
p
|
||||
span.achievement.achievement-firefox
|
||||
!=env.t('friendFirst')
|
||||
hr
|
||||
p
|
||||
span.shop-sprite.item-img(class='shop_armor_special_1')
|
||||
!=env.t('friendSecond')
|
||||
tr
|
||||
td
|
||||
a.label.label-contributor-3(ng-click='toggleUserTier($event)')=env.t('elite') + ' (3-4)'
|
||||
div
|
||||
p
|
||||
span.shop-sprite.item-img(class='shop_head_special_1')
|
||||
!=env.t('eliteThird')
|
||||
hr
|
||||
p
|
||||
span.shop-sprite.item-img(class='shop_weapon_special_1')
|
||||
!=env.t('eliteFourth')
|
||||
tr
|
||||
td
|
||||
a.label.label-contributor-5(ng-click='toggleUserTier($event)')=env.t('champion') + ' (5-6)'
|
||||
div
|
||||
p
|
||||
span.shop-sprite.item-img(class='shop_shield_special_1')
|
||||
!=env.t('championFifth')
|
||||
hr
|
||||
p
|
||||
div(class='Pet-Dragon-Hydra pull-left')
|
||||
!=env.t('championSixth')
|
||||
tr
|
||||
td
|
||||
a.label.label-contributor-7(ng-click='toggleUserTier($event)')=env.t('legendary') + ' (7)'
|
||||
div
|
||||
p
|
||||
!=env.t('legSeventh')
|
||||
tr
|
||||
td
|
||||
a.label.label-contributor-8(ng-click='toggleUserTier($event)')=env.t('heroic')
|
||||
div
|
||||
p=env.t('heroicText')
|
||||
tr
|
||||
td
|
||||
a.label.label-npc(ng-click='toggleUserTier($event)')=env.t('npc')
|
||||
div
|
||||
p=env.t('npcText')
|
||||
|
||||
include ./challenge-box
|
||||
include ./challenge-box
|
||||
|
||||
.span8(ng-controller='ChatCtrl')
|
||||
h3=env.t('tavernTalk')
|
||||
include ./chat-box
|
||||
small(style='position: relative; top: -20px; left: 25px;')
|
||||
include ../../shared/formatting-help
|
||||
small(style='position: relative; top: 18px; left: 0px')
|
||||
alert.alert-info
|
||||
!=env.t('tavernAlert1') + ' <a href="https://github.com/HabitRPG/habitrpg/issues" target="_blank">' + env.t('tavernAlert2') + '</a>.'
|
||||
ul.unstyled.tavern-chat
|
||||
include ./chat-message
|
||||
.col-md-8.tavern(ng-controller='ChatCtrl')
|
||||
h3=env.t('tavernTalk')
|
||||
include ./chat-box
|
||||
.alert.alert-info.alert-sm
|
||||
!= ' ' + env.t('tavernAlert1') + ' <a href="https://github.com/HabitRPG/habitrpg/issues/2760" target="_blank">' + env.t('tavernAlert2') + '</a>.'
|
||||
ul.list-unstyled.tavern-chat
|
||||
include ./chat-message
|
||||
|
||||
@@ -1,20 +1,21 @@
|
||||
footer.footer(ng-controller='FooterCtrl')
|
||||
.container
|
||||
.row
|
||||
.span3
|
||||
.col-sm-3
|
||||
h4=env.t('footerMobile')
|
||||
ul.unstyled
|
||||
ul.list-unstyled
|
||||
li
|
||||
a(href='https://itunes.apple.com/us/app/habitrpg/id689569235?mt=8', target='_blank')=env.t('mobileIOS')
|
||||
li
|
||||
a(href='https://play.google.com/store/apps/details?id=com.ocdevel.habitrpg', target='_blank')=env.t('mobileAndroid')
|
||||
.span3
|
||||
.col-sm-3
|
||||
h4=env.t('footerCompany')
|
||||
ul.unstyled
|
||||
if (!env.isFrontPage)
|
||||
ul.list-unstyled
|
||||
if (!env.isStaticPage)
|
||||
li
|
||||
.btn.btn-small.btn-success(ng-click='modals.buyGems = true')
|
||||
i.icon-heart.icon-white
|
||||
.btn.btn-sm.btn-success(ng-click='openModal("buyGems",{track:"Gems > Donate"})')
|
||||
span.glyphicon.glyphicon-heart
|
||||
|
|
||||
=env.t('companyDonate')
|
||||
li
|
||||
a(href='/static/about')=env.t('companyAbout')
|
||||
@@ -28,9 +29,9 @@ footer.footer(ng-controller='FooterCtrl')
|
||||
a(href='/static/privacy')=env.t('companyPrivacy')
|
||||
li
|
||||
a(href='/static/terms')=env.t('companyTerms')
|
||||
.span3
|
||||
.col-sm-3
|
||||
h4=env.t('footerCommunity')
|
||||
ul.unstyled
|
||||
ul.list-unstyled
|
||||
li
|
||||
a(target='_blank', href='https://github.com/HabitRPG/habitrpg/issues')=env.t('communityBug')
|
||||
li
|
||||
@@ -47,8 +48,8 @@ footer.footer(ng-controller='FooterCtrl')
|
||||
a(target='_blank', href='https://www.facebook.com/Habitrpg')=env.t('communityFacebook')
|
||||
li
|
||||
a(target='_blank', href='http://www.reddit.com/r/habitrpg/')=env.t('communityReddit')
|
||||
.span3
|
||||
if (env.NODE_ENV=='production')
|
||||
.col-sm-3
|
||||
if (env.NODE_ENV == 'production' && !env.IS_MOBILE)
|
||||
h4=env.t('footerSocial')
|
||||
.addthis_toolbox.addthis_default_style(addthis:url='https://habitrpg.com', addthis:title=env.t('socialTitle'))
|
||||
table
|
||||
@@ -59,21 +60,17 @@ footer.footer(ng-controller='FooterCtrl')
|
||||
td
|
||||
a.addthis_button_tweet(tw:via='habitrpg')
|
||||
tr
|
||||
td(align='left')
|
||||
td
|
||||
iframe(src='/bower_components/github-buttons/github-btn.html?user=lefnire&repo=habitrpg&type=watch&count=true', allowtransparency='true', frameborder='0', scrolling='0', width='85px', height='20px')
|
||||
tr
|
||||
td
|
||||
a.addthis_button_google_plusone(g:plusone:size='medium')
|
||||
else
|
||||
else if(env.NODE_ENV != 'production' && !env.isStaticPage)
|
||||
h4 Debug
|
||||
ul.unstyled
|
||||
li
|
||||
a.btn(ng-click='addMissedDay()') +1 Missed Day
|
||||
li
|
||||
a.btn(ng-click='addTenGems()') +10 Gems
|
||||
li
|
||||
a.btn(ng-click='addLevelsAndGold()') +Exp +GP
|
||||
li
|
||||
a.btn(ng-click='addOneLevel()') +1 Level
|
||||
.btn-group-vertical
|
||||
a.btn.btn-default(ng-click='addMissedDay()') +1 Missed Day
|
||||
a.btn.btn-default(ng-click='addTenGems()') +10 Gems
|
||||
a.btn.btn-default(ng-click='addLevelsAndGold()') +Exp +GP
|
||||
a.btn.btn-default(ng-click='addOneLevel()') +1 Level
|
||||
|
||||
div(ng-init='deferredScripts()')
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
a.pull-right.gem-wallet(ng-click='modals.buyGems = true', popover-trigger='mouseenter', popover-title=env.t('gems'), popover=env.t('gemsWhatFor'), popover-placement='bottom')
|
||||
a.pull-right.gem-wallet(ng-click='openModal("buyGems",{track:"Gems > Wallet"})', popover-trigger='mouseenter', popover-title=env.t('gems'), popover=env.t('gemsWhatFor'), popover-placement='bottom')
|
||||
span.task-action-btn.tile.flush.bright.add-gems-btn +
|
||||
span.task-action-btn.tile.flush.neutral
|
||||
.Pet_Currency_Gem2x.Gems
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
Removing it will remove the user's name, but will allow more room for mounts & helms. IMO this is the lesser of two evils, revisit
|
||||
//-figure.herobox(ng-click='clickMember(profile._id)', data-name='{{profile.profile.name}}', ng-class='{isUser: profile.id==user.id, hasPet: profile.items.currentPet}', data-level='{{profile.stats.lvl}}', data-uid='{{profile.id}}', rel='popover', data-placement='bottom', data-trigger='hover', data-html='true', data-content="<div ng-hide='profile.id == user.id'> <div class='progress progress-danger' style='height:5px;'> <div class='bar' style='height: 5px; width: {{percent(profile.stats.hp, 50)}}%;'></div> </div> <div class='progress progress-warning' style='height:5px;'> <div class='bar' style='height: 5px; width: {{percent(profile.stats.exp, tnl(profile.stats.lvl))}}%;'></div> </div> <div>Level: {{profile.stats.lvl}}</div> <div>GP: {{profile.stats.gp | number:0}}</div> <div>{{count(profile.items.pets)}} / 90 Pets Found</div> </div>")
|
||||
|
||||
figure.herobox(ng-click='spell ? castEnd(profile, "user", $event) : clickMember(profile._id)', data-name='{{profile.profile.name}}', ng-class='{isUser: (user._id==profile._id && !user.items.currentMount), hasPet: profile.items.currentMount, "cast-target": applyingAction, isLeader: party.leader==profile._id}')
|
||||
figure.herobox(ng-click='spell ? castEnd(profile, "user", $event) : clickMember(profile._id)', data-name='{{profile.profile.name}}', ng-class='{isUser: user._id==profile._id, hasPet:profile.items.currentPet, hasMount:profile.items.currentMount, "cast-target": applyingAction, isLeader: party.leader==profile._id}')
|
||||
.character-sprites
|
||||
// Mount Body
|
||||
span(ng-if='profile.items.currentMount', class='Mount_Body_{{profile.items.currentMount}}')
|
||||
@@ -43,8 +43,10 @@ figure.herobox(ng-click='spell ? castEnd(profile, "user", $event) : clickMember(
|
||||
span(ng-class='{zzz:profile.preferences.sleep}')
|
||||
// FIXME handle @minimal, this might have to be a directive
|
||||
span.current-pet(class='Pet-{{profile.items.currentPet}}', ng-show='profile.items.currentPet && !minimal')
|
||||
.avatar-level(ng-class='userLevelStyle(profile,"label")')
|
||||
i.icon-circle-arrow-up.icon-white(ng-show='profile.stats.buffs.str || profile.stats.buffs.per || profile.stats.buffs.con || profile.stats.buffs.int || profile.stats.buffs.stealth', tooltip=env.t('buffed'), style='margin-right:5px;')
|
||||
.avatar-level.label.label-default(ng-class='userLevelStyle(profile)')
|
||||
span.glyphicon.glyphicon-circle-arrow-up(ng-show='profile.stats.buffs.str || profile.stats.buffs.per || profile.stats.buffs.con || profile.stats.buffs.int || profile.stats.buffs.stealth', tooltip=env.t('buffed'), style='margin-right:5px;')
|
||||
|
|
||||
=env.t('lvl')
|
||||
| {{profile.stats.lvl}}
|
||||
i.icon-plus-sign.icon-white(ng-show='profile.achievements.rebirths', tooltip=env.t('reborn', {reLevel: "{{profile.achievements.rebirthLevel}}"}), style='margin-left:5px')
|
||||
| {{profile.stats.lvl}}
|
||||
|
|
||||
span.glyphicon.glyphicon-plus-sign(ng-show='profile.achievements.rebirths', tooltip=env.t('reborn', {reLevel: "{{profile.achievements.rebirthLevel}}"}))
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
.header-wrap(ng-controller='HeaderCtrl')
|
||||
a.label.undo-button(x-bind='click:undo', ng-show='_undo')=env.t('undo')
|
||||
div(ng-if='!user.preferences.hideHeader')
|
||||
include menu
|
||||
a.label.label-default.undo-button(x-bind='click:undo', ng-show='_undo')=env.t('undo')
|
||||
|
||||
header.site-header(ng-hide='user.preferences.hideHeader', role='banner', data-partysize='{{party.members.length>1 ? truarr(party.members.length) : 0}}')
|
||||
// avatar
|
||||
@@ -13,27 +11,28 @@
|
||||
.meter.health(title=env.t('health'))
|
||||
.bar(style='width: {{Shared.percent(user.stats.hp, 50)}}%;')
|
||||
span.meter-text
|
||||
i.icon-heart
|
||||
span.glyphicon.glyphicon-heart
|
||||
|
|
||||
| {{Math.ceil(user.stats.hp)}} / 50
|
||||
.meter.experience(title=env.t('experience'))
|
||||
.bar(style='width: {{Shared.percent(user.stats.exp,Shared.tnl(user.stats.lvl))}}%;')
|
||||
span.meter-text
|
||||
i.icon-star
|
||||
span.glyphicon.glyphicon-star
|
||||
|
|
||||
| {{Math.floor(user.stats.exp)}} / {{Shared.tnl(user.stats.lvl) | number:0}}
|
||||
// FIXME doesn't look great here, but the "Experience" CSS title rollover covers it where it was before
|
||||
span(ng-show='user.history.exp')
|
||||
a(ng-click='toggleChart("exp")', tooltip=env.t('progress'))
|
||||
i.icon-signal
|
||||
|
|
||||
span.glyphicon.glyphicon-signal
|
||||
.meter.mana(title='Mana', ng-if='user.flags.classSelected && !user.preferences.disableClasses')
|
||||
.bar(style='width: {{user.stats.mp / user._statsComputed.maxMP * 100}}%;')
|
||||
span.meter-text
|
||||
i.icon-fire
|
||||
span.glyphicon.glyphicon-fire
|
||||
|
|
||||
| {{Math.floor(user.stats.mp)}} / {{user._statsComputed.maxMP}}
|
||||
|
||||
// party
|
||||
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='modals.newStuff=true')
|
||||
|
||||
|
||||
@@ -1,36 +1,132 @@
|
||||
.user-menu(ng-controller='AuthCtrl')
|
||||
button.task-action-btn.tile.solid(ng-hide='authenticated()', style='cursor: pointer;', ng-click="modals.login = true")=env.t('loginAndReg')
|
||||
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')
|
||||
i.icon-ok
|
||||
=env.t('tasks')
|
||||
span(ng-show='$state.includes("tasks")', ui-sref='options')
|
||||
i.icon.icon-wrench
|
||||
=env.t('options')
|
||||
li
|
||||
a.task-action-btn.tile.solid(href="http://habitrpg.wikia.com/wiki/FAQ", target='_blank')
|
||||
i.icon.icon-book
|
||||
=env.t('FAQ')
|
||||
li
|
||||
a.task-action-btn.tile.solid(href="https://vimeo.com/57654086", target='_blank')
|
||||
i.icon.icon-film
|
||||
=env.t('tutorials')
|
||||
li
|
||||
a.task-action-btn.tile.solid(ng-click='User.sync()')
|
||||
i.icon.icon-refresh
|
||||
=env.t('sync')
|
||||
li
|
||||
a.task-action-btn.tile.solid(ng-click='logout()')
|
||||
i.icon-share-alt
|
||||
=env.t('logout')
|
||||
// party invitation notification
|
||||
a(ng-show='user.party.invitation', style='cursor: pointer;', x-bind='click:gotoPartyChat')
|
||||
i.icon-user
|
||||
// party chat notification
|
||||
a(ng-show='newChatMessages(_party.chat,user.party.lastMessageSeen)', style='cursor: pointer;', x-bind='click:gotoPartyChat')
|
||||
i.icon-comment(tooltip=env.t('partyNotification'))
|
||||
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
|
||||
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='User',popover-placement='right',popover-trigger='mouseenter')
|
||||
span.glyphicon.glyphicon-user.white
|
||||
span.caret
|
||||
ul.dropdown-menu
|
||||
li
|
||||
a(ui-sref='options.profile.avatar')=env.t('avatar')
|
||||
li
|
||||
a(ui-sref='options.profile.stats')=env.t('stats')
|
||||
li
|
||||
a(ui-sref='options.profile.profile')=env.t('profile')
|
||||
li
|
||||
a(ng-click='logout()')
|
||||
span.glyphicon.glyphicon-share-alt
|
||||
|
|
||||
=env.t('logout')
|
||||
li.dropdown
|
||||
a.dropdown-toggle(popover='Social',popover-placement='right',popover-trigger='mouseenter')
|
||||
span.glyphicon.glyphicon-heart.white
|
||||
span.caret
|
||||
ul.dropdown-menu
|
||||
li
|
||||
a(ui-sref='options.social.tavern')=env.t('tavern')
|
||||
li
|
||||
a(ui-sref='options.social.party')=env.t('party')
|
||||
li
|
||||
a(ui-sref='options.social.guilds')=env.t('guilds')
|
||||
li
|
||||
a(ui-sref='options.social.challenges')=env.t('challenges')
|
||||
li
|
||||
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')=env.t('market')
|
||||
li
|
||||
a(ui-sref='options.inventory.pets')=env.t('mounts')
|
||||
li
|
||||
a(ui-sref='options.inventory.mounts')=env.t('mounts')
|
||||
li
|
||||
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')=env.t('site')
|
||||
li
|
||||
a(ui-sref='options.settings.api')=env.t('API')
|
||||
li
|
||||
a(ui-sref='options.settings.export')=env.t('export')
|
||||
li
|
||||
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
|
||||
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 +
|
||||
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='right', 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')
|
||||
|
||||
|
||||
|
||||
@@ -1,52 +1,53 @@
|
||||
// Streak
|
||||
div(modal='modals.achievements.streak')
|
||||
script(id='modals/achievements/streak.html', type='text/ng-template')
|
||||
.modal-header
|
||||
h3=env.t('modalAchievement')
|
||||
h4=env.t('modalAchievement')
|
||||
.modal-body
|
||||
.achievement.achievement-thermometer
|
||||
=env.t('streakerAchievement')
|
||||
.modal-footer
|
||||
button.btn.btn-default.cancel(ng-click='modals.achievements.streak = false')=env.t('ok')
|
||||
button.btn.btn-default(ng-click='$close()')=env.t('ok')
|
||||
|
||||
// Max Gear
|
||||
div(modal='modals.achievements.ultimateGear')
|
||||
script(id='modals/achievements/ultimateGear.html', type='text/ng-template')
|
||||
.modal-header
|
||||
h3=env.t('modalAchievement')
|
||||
h4=env.t('modalAchievement')
|
||||
.modal-body
|
||||
.achievement.achievement-armor
|
||||
=env.t('gearAchievement')
|
||||
.modal-footer
|
||||
button.btn.btn-default.cancel(ng-click='modals.achievements.ultimateGear = false')=env.t('ok')
|
||||
button.btn.btn-default(ng-click='$close()')=env.t('ok')
|
||||
|
||||
// Beast Master
|
||||
div(modal='modals.achievements.beastMaster')
|
||||
script(id='modals/achievements/beastMaster.html', type='text/ng-template')
|
||||
.modal-header
|
||||
h3=env.t('modalAchievement')
|
||||
h4=env.t('modalAchievement')
|
||||
.modal-body
|
||||
p
|
||||
.achievement.achievement-rat
|
||||
=env.t('beastAchievement')
|
||||
.modal-footer
|
||||
button.btn.btn-default.cancel(ng-click='modals.achievements.beastMaster = false')=env.t('ok')
|
||||
button.btn.btn-default(ng-click='$close()')=env.t('ok')
|
||||
|
||||
// Contributor
|
||||
div(modal='user.flags.contributor')
|
||||
// activated by user.flags.contributor
|
||||
script(id='modals/achievements/contributor.html', type='text/ng-template')
|
||||
.modal-header
|
||||
h3=env.t('modalContribAchievement')
|
||||
h4=env.t('modalContribAchievement')
|
||||
.modal-body
|
||||
.npc_justin.float-left
|
||||
p
|
||||
!=env.t('contribModal', {name: "{{user.profile.name}}", level: "{{user.contributor.level}}"})
|
||||
a(href='http://habitrpg.wikia.com/wiki/Contributor_Rewards' target='_blank')=env.t('contribLink')
|
||||
.modal-footer
|
||||
button.btn.btn-default.cancel(ng-click='set({"flags.contributor":false})')=env.t('ok')
|
||||
button.btn.btn-default(ng-click='set({"flags.contributor":false}); $close()')=env.t('ok')
|
||||
|
||||
//Rebirth
|
||||
div(modal='modals.achievements.rebirth')
|
||||
script(id='modals/achievements/rebirth.html', type='text/ng-template')
|
||||
.modal-header
|
||||
h3=env.t('modalAchievement')
|
||||
h4=env.t('modalAchievement')
|
||||
.modal-body
|
||||
.achievement.achievement-sun
|
||||
=env.t('rebirthAchievement', {number: "{{user.achievements.rebirths}}", level: "{{user.achievements.rebirthLevel}}"})
|
||||
.modal-footer
|
||||
button.btn.btn-default.cancel(ng-click='modals.achievements.rebirth = false')=env.t('ok')
|
||||
button.btn.btn-default(ng-click='$close()')=env.t('ok')
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
div(modal='modals.buyGems')
|
||||
//Why is shown? Because of script here at line 24!!!!!!!!!
|
||||
script(id='modals/buyGems.html', type='text/ng-template')
|
||||
.modal-body
|
||||
.buy-gems
|
||||
include ../gems
|
||||
@@ -18,14 +19,17 @@ div(modal='modals.buyGems')
|
||||
=env.t('USD')
|
||||
tr
|
||||
td
|
||||
.btn.btn-primary(ng-click='showStripe()',style='margin-left:10px;')=env.t('payWithCard')
|
||||
div(style='float:left;')
|
||||
//-script(src='/bower_components/JavaScriptButtons/dist/paypal-button.min.js?merchant=#{env.PAYPAL_MERCHANT}', data-button='buynow', data-name=env.t('paypalText'), data-quantity='1', data-amount='5', data-currency='USD', data-tax='0', data-callback='#{env.BASE_URL}/api/v2/user/buy-gems/paypal-ipn', data-env="#{env.NODE_ENV == 'production' ? '' : 'sandbox'}", data-custom='?uid={{user._id}}&apiToken={{user.apiToken}}', data-return='#{env.BASE_URL}', data-rm='1', data-no_shipping='1')
|
||||
script(src='/bower_components/JavaScriptButtons/dist/paypal-button.min.js?merchant=#{env.PAYPAL_MERCHANT}', data-button='buynow', data-name=env.t('paypalText'), data-quantity='1', data-amount='5', data-currency='USD', data-tax='0', data-callback='#{env.BASE_URL}/api/v2/user/buy-gems/paypal-ipn', data-custom='?uid={{user._id}}&apiToken={{user.apiToken}}', data-return='#{env.BASE_URL}', data-rm='1', data-no_shipping='1')
|
||||
p
|
||||
small.muted(style='line-height:10px;')=env.t('payNote')
|
||||
.row
|
||||
.col-md-6
|
||||
.btn.btn-primary(ng-click='showStripe()')=env.t('payWithCard')
|
||||
.col-md-6
|
||||
//-script(src='/bower_components/JavaScriptButtons/dist/paypal-button.min.js?merchant=#{env.PAYPAL_MERCHANT}', data-button='buynow', data-name=env.t('paypalText'), data-quantity='1', data-amount='5', data-currency='USD', data-tax='0', data-callback='#{env.BASE_URL}/api/v2/user/buy-gems/paypal-ipn', data-custom='?uid={{user._id}}&apiToken={{user.apiToken}}', data-return='#{env.BASE_URL}', data-rm='1', data-no_shipping='1')
|
||||
div#custom-paypal-button.paypal-button(ng-init='initPayPalButton()')
|
||||
.row
|
||||
.col-md-12
|
||||
small.muted=env.t('payNote')
|
||||
|
||||
div(ng-include="'partials/options.settings.subscription.html'")
|
||||
|
||||
.modal-footer
|
||||
button.btn.btn-default.cancel(ng-click='modals.buyGems = false')=env.t('cancel')
|
||||
button.btn.btn-default(ng-click='$close()')=env.t('cancel')
|
||||
|
||||
@@ -1,75 +1,78 @@
|
||||
.modal(ng-if='!user.flags.classSelected && user.stats.lvl >= 10', data-backdrop=true, ng-controller='UserCtrl')
|
||||
script(type='text/ng-template', id='modals/chooseClass.html')
|
||||
.modal-header
|
||||
h3=env.t('chooseClass1')
|
||||
h4
|
||||
|
|
||||
=env.t('chooseClass1')
|
||||
a(href='http://habitrpg.wikia.com/wiki/Class_System' target='_blank')=env.t('chooseClass2')
|
||||
.modal-body.select-class
|
||||
.row-fluid
|
||||
.span3(ng-click='selectedClass = "warrior"')
|
||||
h5
|
||||
a(href='http://habitrpg.wikia.com/wiki/Warrior' target='_blank')=env.t('warrior')
|
||||
figure.herobox(ng-class='{"selected-class": selectedClass=="warrior"}')
|
||||
.character-sprites
|
||||
span(class='skin_{{user.preferences.skin}}')
|
||||
span(class='{{user.preferences.size}}_armor_warrior_5')
|
||||
span(class='head_0')
|
||||
span(class='hair_base_{{user.preferences.hair.base}}_{{user.preferences.hair.color}}')
|
||||
span(class='hair_bangs_{{user.preferences.hair.bangs}}_{{user.preferences.hair.color}}')
|
||||
span(class='hair_beard_{{user.preferences.hair.beard}}_{{user.preferences.hair.color}}')
|
||||
span(class='hair_mustache_{{user.preferences.hair.mustache}}_{{user.preferences.hair.color}}')
|
||||
span(class='head_warrior_5')
|
||||
span(class='shield_warrior_5')
|
||||
span(class='weapon_warrior_6')
|
||||
.span3(ng-click='selectedClass = "wizard"')
|
||||
h5
|
||||
a(href='http://habitrpg.wikia.com/wiki/Mage' target='_blank')=env.t('mage')
|
||||
figure.herobox(ng-class='{"selected-class": selectedClass=="wizard"}')
|
||||
.character-sprites
|
||||
span(class='skin_{{user.preferences.skin}}')
|
||||
span(class='{{user.preferences.size}}_armor_wizard_5')
|
||||
span(class='head_0')
|
||||
span(class='hair_base_{{user.preferences.hair.base}}_{{user.preferences.hair.color}}')
|
||||
span(class='hair_bangs_{{user.preferences.hair.bangs}}_{{user.preferences.hair.color}}')
|
||||
span(class='hair_beard_{{user.preferences.hair.beard}}_{{user.preferences.hair.color}}')
|
||||
span(class='hair_mustache_{{user.preferences.hair.mustache}}_{{user.preferences.hair.color}}')
|
||||
span(class='head_wizard_5')
|
||||
span(class='shield_wizard_5')
|
||||
span(class='weapon_wizard_6')
|
||||
.span3(ng-click='selectedClass = "rogue"')
|
||||
h5
|
||||
a(href='http://habitrpg.wikia.com/wiki/Rogue' target='_blank')=env.t('rogue')
|
||||
figure.herobox(ng-class='{"selected-class": selectedClass=="rogue"}')
|
||||
.character-sprites
|
||||
span(class='skin_{{user.preferences.skin}}')
|
||||
span(class='{{user.preferences.size}}_armor_rogue_5')
|
||||
span(class='head_0')
|
||||
span(class='hair_base_{{user.preferences.hair.base}}_{{user.preferences.hair.color}}')
|
||||
span(class='hair_bangs_{{user.preferences.hair.bangs}}_{{user.preferences.hair.color}}')
|
||||
span(class='hair_beard_{{user.preferences.hair.beard}}_{{user.preferences.hair.color}}')
|
||||
span(class='hair_mustache_{{user.preferences.hair.mustache}}_{{user.preferences.hair.color}}')
|
||||
span(class='head_rogue_5')
|
||||
span(class='shield_rogue_6')
|
||||
span(class='weapon_rogue_6')
|
||||
.span3(ng-click='selectedClass = "healer"')
|
||||
h5
|
||||
a(href='http://habitrpg.wikia.com/wiki/Healer' target='_blank')=env.t('healer')
|
||||
figure.herobox(ng-class='{"selected-class": selectedClass=="healer"}')
|
||||
.character-sprites
|
||||
span(class='skin_{{user.preferences.skin}}')
|
||||
span(class='{{user.preferences.size}}_armor_healer_5')
|
||||
span(class='head_0')
|
||||
span(class='hair_base_{{user.preferences.hair.base}}_{{user.preferences.hair.color}}')
|
||||
span(class='hair_bangs_{{user.preferences.hair.bangs}}_{{user.preferences.hair.color}}')
|
||||
span(class='hair_beard_{{user.preferences.hair.beard}}_{{user.preferences.hair.color}}')
|
||||
span(class='hair_mustache_{{user.preferences.hair.mustache}}_{{user.preferences.hair.color}}')
|
||||
span(class='head_healer_5')
|
||||
span(class='shield_healer_5')
|
||||
span(class='weapon_healer_6')
|
||||
br
|
||||
.well(ng-show='selectedClass=="warrior"')=env.t('warriorText')
|
||||
.well(ng-show='selectedClass=="wizard"')=env.t('mageText')
|
||||
.well(ng-show='selectedClass=="rogue"')=env.t('rogueText')
|
||||
.well(ng-show='selectedClass=="healer"')=env.t('healerText')
|
||||
.container-fluid
|
||||
.row
|
||||
.col-md-3(ng-click='selectedClass = "warrior"')
|
||||
h5
|
||||
a(href='http://habitrpg.wikia.com/wiki/Warrior' target='_blank')=env.t('warrior')
|
||||
figure.herobox(ng-class='{"selected-class": selectedClass=="warrior"}')
|
||||
.character-sprites
|
||||
span(class='skin_{{user.preferences.skin}}')
|
||||
span(class='{{user.preferences.size}}_armor_warrior_5')
|
||||
span(class='head_0')
|
||||
span(class='hair_base_{{user.preferences.hair.base}}_{{user.preferences.hair.color}}')
|
||||
span(class='hair_bangs_{{user.preferences.hair.bangs}}_{{user.preferences.hair.color}}')
|
||||
span(class='hair_beard_{{user.preferences.hair.beard}}_{{user.preferences.hair.color}}')
|
||||
span(class='hair_mustache_{{user.preferences.hair.mustache}}_{{user.preferences.hair.color}}')
|
||||
span(class='head_warrior_5')
|
||||
span(class='shield_warrior_5')
|
||||
span(class='weapon_warrior_6')
|
||||
.col-md-3(ng-click='selectedClass = "wizard"')
|
||||
h5
|
||||
a(href='http://habitrpg.wikia.com/wiki/Mage' target='_blank')=env.t('mage')
|
||||
figure.herobox(ng-class='{"selected-class": selectedClass=="wizard"}')
|
||||
.character-sprites
|
||||
span(class='skin_{{user.preferences.skin}}')
|
||||
span(class='{{user.preferences.size}}_armor_wizard_5')
|
||||
span(class='head_0')
|
||||
span(class='hair_base_{{user.preferences.hair.base}}_{{user.preferences.hair.color}}')
|
||||
span(class='hair_bangs_{{user.preferences.hair.bangs}}_{{user.preferences.hair.color}}')
|
||||
span(class='hair_beard_{{user.preferences.hair.beard}}_{{user.preferences.hair.color}}')
|
||||
span(class='hair_mustache_{{user.preferences.hair.mustache}}_{{user.preferences.hair.color}}')
|
||||
span(class='head_wizard_5')
|
||||
span(class='shield_wizard_5')
|
||||
span(class='weapon_wizard_6')
|
||||
.col-md-3(ng-click='selectedClass = "rogue"')
|
||||
h5
|
||||
a(href='http://habitrpg.wikia.com/wiki/Rogue' target='_blank')=env.t('rogue')
|
||||
figure.herobox(ng-class='{"selected-class": selectedClass=="rogue"}')
|
||||
.character-sprites
|
||||
span(class='skin_{{user.preferences.skin}}')
|
||||
span(class='{{user.preferences.size}}_armor_rogue_5')
|
||||
span(class='head_0')
|
||||
span(class='hair_base_{{user.preferences.hair.base}}_{{user.preferences.hair.color}}')
|
||||
span(class='hair_bangs_{{user.preferences.hair.bangs}}_{{user.preferences.hair.color}}')
|
||||
span(class='hair_beard_{{user.preferences.hair.beard}}_{{user.preferences.hair.color}}')
|
||||
span(class='hair_mustache_{{user.preferences.hair.mustache}}_{{user.preferences.hair.color}}')
|
||||
span(class='head_rogue_5')
|
||||
span(class='shield_rogue_6')
|
||||
span(class='weapon_rogue_6')
|
||||
.col-md-3(ng-click='selectedClass = "healer"')
|
||||
h5
|
||||
a(href='http://habitrpg.wikia.com/wiki/Healer' target='_blank')=env.t('healer')
|
||||
figure.herobox(ng-class='{"selected-class": selectedClass=="healer"}')
|
||||
.character-sprites
|
||||
span(class='skin_{{user.preferences.skin}}')
|
||||
span(class='{{user.preferences.size}}_armor_healer_5')
|
||||
span(class='head_0')
|
||||
span(class='hair_base_{{user.preferences.hair.base}}_{{user.preferences.hair.color}}')
|
||||
span(class='hair_bangs_{{user.preferences.hair.bangs}}_{{user.preferences.hair.color}}')
|
||||
span(class='hair_beard_{{user.preferences.hair.beard}}_{{user.preferences.hair.color}}')
|
||||
span(class='hair_mustache_{{user.preferences.hair.mustache}}_{{user.preferences.hair.color}}')
|
||||
span(class='head_healer_5')
|
||||
span(class='shield_healer_5')
|
||||
span(class='weapon_healer_6')
|
||||
br
|
||||
.well(ng-show='selectedClass=="warrior"')=env.t('warriorText')
|
||||
.well(ng-show='selectedClass=="wizard"')=env.t('mageText')
|
||||
.well(ng-show='selectedClass=="rogue"')=env.t('rogueText')
|
||||
.well(ng-show='selectedClass=="healer"')=env.t('healerText')
|
||||
|
||||
.modal-footer
|
||||
button.btn.btn-small.btn-danger.cancel(ng-click='user.ops.disableClasses({})', popover-placement='top', popover-trigger='mouseenter', popover=env.t('optOutText'))=env.t('optOut')
|
||||
button.btn.btn-primary.cancel(ng-click='selectedClass && changeClass(selectedClass)')=env.t('select')
|
||||
button.btn.btn-sm.btn-danger(ng-click='user.ops.disableClasses({}); $close()', popover-placement='top', popover-trigger='mouseenter', popover=env.t('optOutText'))=env.t('optOut')
|
||||
button.btn.btn-primary(ng-disabled='!selectedClass' ng-click='changeClass(selectedClass); $close()')=env.t('select')
|
||||
@@ -1,14 +1,16 @@
|
||||
div(modal='user.stats.hp <= 0', options='{backdrop:true, keyboard:false, backdropClick:false}')
|
||||
.modal-body
|
||||
.row-fluid
|
||||
.span4
|
||||
figure.notification-character
|
||||
.GrimReaper
|
||||
.span8
|
||||
h2=env.t('youDied')
|
||||
.row-fluid
|
||||
.span4
|
||||
p
|
||||
a.btn.btn-danger.btn-large.notification-action(ng-click='user.ops.revive({})')=env.t('continue')
|
||||
.span8
|
||||
p=env.t('dieText')
|
||||
//div(modal='user.stats.hp <= 0', options='{backdrop:true, keyboard:false, backdropClick:false}')
|
||||
script(type='text/ng-template', id='modals/death.html')
|
||||
.modal-body.death-modal
|
||||
.container-fluid
|
||||
.row
|
||||
.col-md-3
|
||||
figure
|
||||
.GrimReaper
|
||||
.col-md-9
|
||||
h2=env.t('youDied')
|
||||
.row
|
||||
.col-md-3
|
||||
p
|
||||
a.btn.btn-danger.btn-lg(ng-click='user.ops.revive({}); $close()')=env.t('continue')
|
||||
.col-md-9
|
||||
p=env.t('dieText')
|
||||
|
||||
@@ -1,23 +1,15 @@
|
||||
div(modal='modals.dropsEnabled')
|
||||
script(type='text/ng-template', id='modals/dropsEnabled.html')
|
||||
.modal-header
|
||||
h3=env.t('dropsEnabled')
|
||||
h4=env.t('dropsEnabled')
|
||||
.modal-body
|
||||
p
|
||||
span.item-drop-icon(class='Pet_Egg_Wolf', style='margin-left: 0px')
|
||||
figure
|
||||
.item-drop-icon(class='Pet_Egg_Wolf')
|
||||
span!=env.t('firstDrop', {eggText: "{{Content.eggs.Wolf.text}}", eggNotes: "{{Content.eggs.Wolf.notes}}"})
|
||||
br
|
||||
p
|
||||
span.item-drop-icon(class='Pet_Currency_Gem')
|
||||
figure
|
||||
.item-drop-icon(class='Pet_Currency_Gem')
|
||||
span!=env.t('useGems')
|
||||
.modal-footer
|
||||
button.btn.btn-default.cancel(ng-click='modals.dropsEnabled = false')=env.t('close')
|
||||
|
||||
div(modal='modals.drop')
|
||||
.modal-header
|
||||
h3=env.t('itemDrop')
|
||||
.modal-body
|
||||
p
|
||||
span.item-drop-icon(class='Pet_{{user._tmp.drop.type}}_{{user._tmp.drop.key}}')
|
||||
| {{user._tmp.drop.dialog}}
|
||||
.modal-footer
|
||||
button.btn.btn-default.cancel(ng-click='modals.drop = false')=env.t('close')
|
||||
button.btn.btn-default(ng-click='$close()')=env.t('close')
|
||||
@@ -1,5 +1,4 @@
|
||||
include ./achievements
|
||||
include ./login
|
||||
include ./reroll
|
||||
include ./death
|
||||
include ./new-stuff
|
||||
@@ -9,4 +8,5 @@ include ./settings
|
||||
include ./drops
|
||||
include ./classes
|
||||
include ./quests
|
||||
include ./rebirth
|
||||
include ./rebirth
|
||||
include ./limited
|
||||
@@ -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')
|
||||