Merge branch 'develop' into sabe/attributes
This commit is contained in:
+4
-2
@@ -1,8 +1,10 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- '0.10'
|
||||
services:
|
||||
- mongodb
|
||||
before_script:
|
||||
- 'npm install -g bower grunt-cli'
|
||||
- 'bower install'
|
||||
- 'npm install -g grunt-cli'
|
||||
- export DISPLAY=:99.0
|
||||
- sh -e /etc/init.d/xvfb start
|
||||
- cp config.json.example config.json
|
||||
|
||||
+3
-3
@@ -21,7 +21,6 @@
|
||||
"angular-sanitize": "~1.2.1",
|
||||
"angular-resource": "~1.2.1",
|
||||
"angular-ui": "~0.4.0",
|
||||
"angular-ui-utils": "~0.0.4",
|
||||
"angular-bootstrap": "~0.5.0",
|
||||
"angular-ui-router": "ca3b4777a603df8f86cfd653c8f6c38b2ae05d89",
|
||||
"angular-loading-bar": "~0.0.5",
|
||||
@@ -38,13 +37,14 @@
|
||||
"js-emoji": "git://github.com/snicker/js-emoji#master",
|
||||
"gemoji": "git://github.com/github/gemoji",
|
||||
"sticky": "*",
|
||||
"bootstrap-tour": "~0.8.0"
|
||||
"bootstrap-tour": "~0.8.0",
|
||||
"angular-ui-utils": "~0.1.0"
|
||||
},
|
||||
"resolutions": {
|
||||
"jquery": "~2.0.3",
|
||||
"bootstrap": "v2.3.2",
|
||||
"angular": "~1.2.1",
|
||||
"bootstrap-tour": "~0.8.0"
|
||||
"angular-ui-utils": "~0.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"angular-mocks": "~1.2.1"
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
// Karma configuration
|
||||
// http://karma-runner.github.io/0.10/config/configuration-file.html
|
||||
|
||||
module.exports = function(config) {
|
||||
config.set({
|
||||
// base path, that will be used to resolve files and exclude
|
||||
basePath: '',
|
||||
|
||||
// testing framework to use (jasmine/mocha/qunit/...)
|
||||
frameworks: ['ng-scenario'],
|
||||
|
||||
// list of files / patterns to load in the browser
|
||||
files: [
|
||||
'test/e2e/**/*.js'
|
||||
],
|
||||
|
||||
// list of files / patterns to exclude
|
||||
exclude: [],
|
||||
|
||||
// web server port
|
||||
port: 8080,
|
||||
|
||||
// level of logging
|
||||
// possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG
|
||||
logLevel: config.LOG_INFO,
|
||||
|
||||
|
||||
// enable / disable watching file and executing tests whenever any file changes
|
||||
autoWatch: false,
|
||||
|
||||
|
||||
// Start these browsers, currently available:
|
||||
// - Chrome
|
||||
// - ChromeCanary
|
||||
// - Firefox
|
||||
// - Opera
|
||||
// - Safari (only Mac)
|
||||
// - PhantomJS
|
||||
// - IE (only Windows)
|
||||
browsers: ['Chrome'],
|
||||
|
||||
|
||||
// Continuous Integration mode
|
||||
// if true, it capture browsers, run tests and exit
|
||||
singleRun: false
|
||||
|
||||
// Uncomment the following lines if you are using grunt's server to run the tests
|
||||
// proxies: {
|
||||
// '/': 'http://localhost:9000/'
|
||||
// },
|
||||
// URL root prevent conflicts with the site root
|
||||
// urlRoot: '_karma_'
|
||||
});
|
||||
};
|
||||
+2
-2
@@ -58,12 +58,12 @@
|
||||
"npm": "1.2.x"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "grunt karma:continuous",
|
||||
"test": "./test/run_tests.sh",
|
||||
"start": "grunt run:dev",
|
||||
"postinstall": "./node_modules/bower/bin/bower install -f"
|
||||
},
|
||||
"devDependencies": {
|
||||
"karma-ng-scenario": "~0.1.0",
|
||||
"protractor": "~0.14.0",
|
||||
"grunt-karma": "~0.6.2",
|
||||
"karma-script-launcher": "~0.1.0",
|
||||
"karma-chrome-launcher": "~0.1.0",
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
// An example configuration file.
|
||||
exports.config = {
|
||||
// The address of a running selenium server.
|
||||
seleniumAddress: 'http://localhost:4444/wd/hub',
|
||||
|
||||
// Capabilities to be passed to the webdriver instance.
|
||||
capabilities: {
|
||||
'browserName': 'firefox'
|
||||
},
|
||||
|
||||
// Spec patterns are relative to the current working directly when
|
||||
// protractor is called.
|
||||
specs: ['test/e2e/e2e.js'],
|
||||
|
||||
// A base URL for your application under test. Calls to protractor.get()
|
||||
// with relative paths will be prepended with this.
|
||||
baseUrl: 'http://localhost:3001',
|
||||
|
||||
// Options to be passed to Jasmine-node.
|
||||
jasmineNodeOpts: {
|
||||
showColors: true,
|
||||
defaultTimeoutInterval: 30000
|
||||
}
|
||||
};
|
||||
@@ -1,4 +1,5 @@
|
||||
@import "nib/vendor"
|
||||
@import "nib"
|
||||
//@import "nib/vendor"
|
||||
|
||||
// Vendor Includes - include first so we can override
|
||||
// Import only styles that do not have urls to images! Include them directly in the page!
|
||||
|
||||
+31
-1
@@ -407,4 +407,34 @@ form
|
||||
color: #333
|
||||
&:hover
|
||||
border-top: 0
|
||||
margin-top: 2px
|
||||
margin-top: 2px
|
||||
|
||||
// Checklists
|
||||
// --------
|
||||
.checklist-form
|
||||
/* Make an input blend into its parent */
|
||||
input.inline-edit
|
||||
reset-box-model()
|
||||
reset-font()
|
||||
line-height: inherit
|
||||
text-align: inherit
|
||||
background-color:inherit
|
||||
box-shadow: none
|
||||
|
||||
/* Add interaction cues on hover and focus */
|
||||
input.inline-edit:hover,input.inline-edit:focus
|
||||
background-color: #FFD
|
||||
transition: background-color 0.5s
|
||||
|
||||
.checklist-icons
|
||||
opacity:0
|
||||
|
||||
li
|
||||
min-height: 20px
|
||||
padding-left: 10px
|
||||
margin-bottom: 5px
|
||||
|
||||
[type="checkbox"]
|
||||
margin: 0px 10px 3px 0px
|
||||
li:hover .checklist-icons
|
||||
opacity:1
|
||||
|
||||
@@ -33,7 +33,7 @@ habitrpg.controller('NotificationCtrl',
|
||||
|
||||
$rootScope.$watch('user.stats.mp', function(after,before) {
|
||||
if (after == before) return;
|
||||
if (User.user.stats.lvl == 0) return;
|
||||
if (!User.user.flags.classSelected || User.user.preferences.disableClasses) return;
|
||||
var mana = after - before;
|
||||
Notification.mp(mana);
|
||||
});
|
||||
@@ -68,6 +68,11 @@ habitrpg.controller('NotificationCtrl',
|
||||
$rootScope.modals.achievements.beastMaster = true;
|
||||
}, true);
|
||||
|
||||
$rootScope.$watch('user.achievements.rebirths', function(after, before){
|
||||
if(after === before) return;
|
||||
$rootScope.modals.achievements.rebirth = true;
|
||||
});
|
||||
|
||||
/*_.each(['weapon', 'head', 'chest', 'shield'], function(watched){
|
||||
$rootScope.$watch('user.items.' + watched, function(before, after){
|
||||
if (after == before) return;
|
||||
|
||||
@@ -59,6 +59,12 @@ habitrpg.controller('SettingsCtrl',
|
||||
$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");
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use strict";
|
||||
|
||||
habitrpg.controller("TasksCtrl", ['$scope', '$rootScope', '$location', 'User','Notification', '$http', 'API_URL',
|
||||
function($scope, $rootScope, $location, User, Notification, $http, API_URL) {
|
||||
habitrpg.controller("TasksCtrl", ['$scope', '$rootScope', '$location', 'User','Notification', '$http', 'API_URL', '$timeout',
|
||||
function($scope, $rootScope, $location, User, Notification, $http, API_URL, $timeout) {
|
||||
$scope.obj = User.user; // used for task-lists
|
||||
$scope.user = User.user;
|
||||
|
||||
@@ -42,9 +42,11 @@ habitrpg.controller("TasksCtrl", ['$scope', '$rootScope', '$location', 'User','N
|
||||
User.user.ops.deleteTask({params:{id:list[$index].id}})
|
||||
};
|
||||
|
||||
$scope.saveTask = function(task) {
|
||||
$scope.saveTask = function(task, stayOpen) {
|
||||
if (task.checklist && task.checklist[0])
|
||||
task.checklist = _.filter(task.checklist,function(i){return !!i.text});
|
||||
User.user.ops.updateTask({params:{id:task.id},body:task});
|
||||
task._editing = false;
|
||||
if (!stayOpen) task._editing = false;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -68,6 +70,56 @@ habitrpg.controller("TasksCtrl", ['$scope', '$rootScope', '$location', 'User','N
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
------------------------
|
||||
To-Dos
|
||||
------------------------
|
||||
*/
|
||||
$scope._today = moment().add('days',1);
|
||||
|
||||
/*
|
||||
------------------------
|
||||
Checklists
|
||||
------------------------
|
||||
*/
|
||||
function focusChecklist(task,index) {
|
||||
window.setTimeout(function(){
|
||||
$('#task-'+task.id+' .checklist-form .inline-edit')[index].focus();
|
||||
});
|
||||
}
|
||||
$scope.addChecklist = function(task) {
|
||||
task.checklist = [{completed:false,text:""}];
|
||||
focusChecklist(task,0);
|
||||
}
|
||||
$scope.addChecklistItem = function(task,$event,$index) {
|
||||
if ($index == task.checklist.length-1){
|
||||
User.user.ops.updateTask({params:{id:task.id},body:task}); // don't preen the new empty item
|
||||
task.checklist.push({completed:false,text:''});
|
||||
focusChecklist(task,task.checklist.length-1);
|
||||
} else {
|
||||
$scope.saveTask(task,true);
|
||||
focusChecklist(task,$index+1);
|
||||
}
|
||||
}
|
||||
$scope.removeChecklistItem = function(task,$index,force){
|
||||
var backspaced = !force && !task.checklist[$index].text
|
||||
if (force || backspaced) {
|
||||
task.checklist.splice($index,1);
|
||||
$scope.saveTask(task,true);
|
||||
if (backspaced) focusChecklist(task,$index-1);
|
||||
}
|
||||
}
|
||||
$scope.navigateChecklist = function(task,$index,$event){
|
||||
focusChecklist(task, $event.keyCode == '40' ? $index+1 : $index-1);
|
||||
}
|
||||
$scope.checklistCompletion = function(checklist){
|
||||
return _.reduce(checklist,function(m,i){return m+(i.completed ? 1 : 0);},0)
|
||||
}
|
||||
$scope.collapseChecklist = function(task) {
|
||||
task.collapseChecklist = !task.collapseChecklist;
|
||||
$scope.saveTask(task,true);
|
||||
}
|
||||
|
||||
/*
|
||||
------------------------
|
||||
Items
|
||||
|
||||
@@ -8,10 +8,4 @@ angular.module('habitrpg')
|
||||
return function (gp) {
|
||||
return Math.floor((gp - Math.floor(gp))*100);
|
||||
}
|
||||
})
|
||||
.filter('completedFilter', function(){
|
||||
return function(tasks,_showCompleted) {
|
||||
if (!tasks[0] || tasks[0].type != 'todo') return tasks;
|
||||
return _.where(tasks, {completed:!!_showCompleted});
|
||||
}
|
||||
})
|
||||
@@ -139,7 +139,10 @@ angular.module('guideServices', []).
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
$rootScope.$watch('user.flags.rebirthEnabled', function(after, before) {
|
||||
if (alreadyShown(before, after)) return;
|
||||
$rootScope.modals.rebirthEnabled = true;
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
@@ -174,7 +177,7 @@ angular.module('guideServices', []).
|
||||
}, {
|
||||
element: ".meter.mana",
|
||||
title: "Spells",
|
||||
content: "You can now unlock class-specific spells. You'll see your first at level 6. 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>."
|
||||
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>."
|
||||
}, {
|
||||
orphan: true,
|
||||
title: "Read More",
|
||||
|
||||
@@ -6,11 +6,11 @@ angular.module("notificationServices", [])
|
||||
function growl(html, type) {
|
||||
$.bootstrapGrowl(html, {
|
||||
ele: '#notification-area',
|
||||
type: type, //(null, 'info', 'error', 'success', 'gp', 'xp', 'hp', 'lvl','death')
|
||||
type: type, //(null, 'text', 'error', 'success', 'gp', 'xp', 'hp', 'lvl', 'death', 'mp')
|
||||
top_offset: 20,
|
||||
align: 'right', //('left', 'right', or 'center')
|
||||
width: 250, //(integer, or 'auto')
|
||||
delay: 3000,
|
||||
delay: 7000,
|
||||
allow_dismiss: true,
|
||||
stackup_spacing: 10 // spacing between consecutive stacecked growls.
|
||||
});
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"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/modules/keypress/keypress.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",
|
||||
"bower_components/Angular-At-Directive/src/caret.js",
|
||||
|
||||
@@ -371,7 +371,7 @@ api.cast = function(req, res) {
|
||||
|
||||
if (group) {
|
||||
series.push(function(cb2){
|
||||
var message = '`'+user.profile.name+' casts '+spell.text + (type=='user' ? ' on @'+found.profile.name : ' for the party')+'.`';
|
||||
var message = '`'+user.profile.name+' casts '+spell.text + (type=='user' ? ' on '+found.profile.name : ' for the party')+'.`';
|
||||
group.sendChat(message);
|
||||
group.save(cb2);
|
||||
})
|
||||
|
||||
+2
-2
@@ -182,7 +182,7 @@ GroupSchema.statics.collectQuest = function(user, progress, cb) {
|
||||
return m;
|
||||
}, []);
|
||||
foundText = foundText ? foundText.join(', ') : 'nothing';
|
||||
group.sendChat("`<" + user.profile.name + "> found "+foundText+".`");
|
||||
group.sendChat("`" + user.profile.name + " found "+foundText+".`");
|
||||
group.markModified('quest.progress.collect');
|
||||
|
||||
// Still needs completing
|
||||
@@ -210,7 +210,7 @@ GroupSchema.statics.bossQuest = function(user, progress, cb) {
|
||||
var down = progress.down * quest.boss.str; // multiply by boss strength
|
||||
|
||||
group.quest.progress.hp -= progress.up;
|
||||
group.sendChat("`<" + user.profile.name + "> attacks <" + quest.boss.name + "> for " + (progress.up.toFixed(1)) + " damage, <" + quest.boss.name + "> attacks party for " + Math.abs(down).toFixed(1) + " damage.`");
|
||||
group.sendChat("`" + user.profile.name + " attacks " + quest.boss.name + " for " + (progress.up.toFixed(1)) + " damage, " + quest.boss.name + " attacks party for " + Math.abs(down).toFixed(1) + " damage.`");
|
||||
|
||||
// Everyone takes damage
|
||||
var series = [
|
||||
|
||||
+13
-1
@@ -39,6 +39,14 @@ var HabitSchema = new Schema(
|
||||
, { _id: false }
|
||||
);
|
||||
|
||||
var collapseChecklist = {type:Boolean, 'default':false};
|
||||
var checklist = [{
|
||||
completed:{type:Boolean,'default':false},
|
||||
text: String,
|
||||
_id:false,
|
||||
id: {type:String,'default':shared.uuid}
|
||||
}];
|
||||
|
||||
var DailySchema = new Schema(
|
||||
_.defaults({
|
||||
type: {type:String, 'default': 'daily'},
|
||||
@@ -53,6 +61,8 @@ var DailySchema = new Schema(
|
||||
s: {type: Boolean, 'default': true},
|
||||
su: {type: Boolean, 'default': true}
|
||||
},
|
||||
collapseChecklist:collapseChecklist,
|
||||
checklist:checklist,
|
||||
streak: {type: Number, 'default': 0}
|
||||
}, TaskSchema)
|
||||
, { _id: false }
|
||||
@@ -62,7 +72,9 @@ var TodoSchema = new Schema(
|
||||
_.defaults({
|
||||
type: {type:String, 'default': 'todo'},
|
||||
completed: {type: Boolean, 'default': false},
|
||||
date: String // due date for todos // FIXME we're getting parse errors, people have stored as "today" and "3/13". Need to run a migration & put this back to type: Date
|
||||
date: String, // due date for todos // FIXME we're getting parse errors, people have stored as "today" and "3/13". Need to run a migration & put this back to type: Date
|
||||
collapseChecklist:collapseChecklist,
|
||||
checklist:checklist
|
||||
}, TaskSchema)
|
||||
, { _id: false }
|
||||
);
|
||||
|
||||
+5
-2
@@ -46,7 +46,9 @@ var UserSchema = new Schema({
|
||||
snowball: Number,
|
||||
streak: Number,
|
||||
challenges: Array,
|
||||
quests: Schema.Types.Mixed
|
||||
quests: Schema.Types.Mixed,
|
||||
rebirths: Number,
|
||||
rebirthLevel: Number
|
||||
},
|
||||
auth: {
|
||||
facebook: Schema.Types.Mixed,
|
||||
@@ -95,7 +97,8 @@ var UserSchema = new Schema({
|
||||
partyEnabled: Boolean, // FIXME do we need this?
|
||||
contributor: Boolean,
|
||||
classSelected: {type: Boolean, 'default': false},
|
||||
mathUpdates: Boolean
|
||||
mathUpdates: Boolean,
|
||||
rebirthEnabled: {type: Boolean, 'default': false}
|
||||
},
|
||||
history: {
|
||||
exp: Array, // [{date: Date, value: Number}], // big peformance issues if these are defined
|
||||
|
||||
+2
-1
@@ -65,7 +65,8 @@ router['delete']('/user', auth.auth, user['delete']);
|
||||
router.post('/user/revive', auth.auth, cron, user.revive); // Shared.ops
|
||||
router.post('/user/reroll', auth.auth, cron, user.reroll); // Shared.ops
|
||||
router.post('/user/reset', auth.auth, user.reset); // Shared.ops
|
||||
router.post('/user/sleep', auth.auth, cron, user.sleep); //Shared.opss
|
||||
router.post('/user/sleep', auth.auth, cron, user.sleep); //Shared.ops
|
||||
router.post('/user/rebirth', auth.auth, cron, user.rebirth); //Shared.ops
|
||||
|
||||
router.post('/user/class/change', auth.auth, cron, user.changeClass); //Shared.ops | query={class}
|
||||
router.post('/user/class/allocate', auth.auth, cron, user.allocate); //Shared.ops | query={stat}
|
||||
|
||||
+3
-1
@@ -1,6 +1,7 @@
|
||||
require('coffee-script') // for habitrpg-shared
|
||||
var nconf = require('nconf');
|
||||
require('./config');
|
||||
var utils = require('./utils');
|
||||
utils.setupConfig();
|
||||
var async = require('async');
|
||||
var mongoose = require('mongoose');
|
||||
User = require('./models/user').model;
|
||||
@@ -31,4 +32,5 @@ async.waterfall([
|
||||
],function(err){
|
||||
if (err) throw err;
|
||||
console.log("Done initializing database");
|
||||
mongoose.disconnect();
|
||||
})
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
'use strict';
|
||||
|
||||
describe('front page', function() {
|
||||
beforeEach(function(){
|
||||
browser.ignoreSynchronization = true;
|
||||
browser.get('/');
|
||||
browser.sleep(1000);
|
||||
});
|
||||
|
||||
// based on https://github.com/angular/protractor/issues/114#issuecomment-29046939
|
||||
afterEach(function(){
|
||||
var currentSpec = jasmine.getEnv().currentSpec;
|
||||
var passed = currentSpec.results().passed();
|
||||
if(!passed){
|
||||
var filename = 'exception_' + currentSpec.description + '.png';
|
||||
browser.takeScreenshot().then(function(png){
|
||||
var fs = require('fs');
|
||||
var buffer = new Buffer(png, 'base64');
|
||||
var stream = fs.createWriteStream(filename);
|
||||
stream.write(buffer);
|
||||
stream.end();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('shows the front page', function(){
|
||||
var button = element(by.className('btn'));
|
||||
expect(button.getText()).toEqual('Play');
|
||||
});
|
||||
|
||||
it("don't login when using wrong credentials", function(){
|
||||
var button = element(by.className('btn'));
|
||||
button.click();
|
||||
browser.sleep(1000);
|
||||
element(by.model('loginUsername')).sendKeys('username');
|
||||
element(by.model('loginPassword')).sendKeys('pass');
|
||||
var login = element(by.css("#login-tab input[value='Login']"));
|
||||
login.click();
|
||||
var alertDialog = browser.switchTo().alert();
|
||||
expect(alertDialog.getText()).toMatch(/Username 'username' not found/);
|
||||
alertDialog.accept();
|
||||
});
|
||||
|
||||
it('registers a new user', function(){
|
||||
var button = element(by.className('btn'));
|
||||
button.click();
|
||||
browser.sleep(1000);
|
||||
var registerTab = element(by.linkText('Register'));
|
||||
registerTab.click();
|
||||
element(by.model('registerVals.username')).sendKeys('user');
|
||||
element(by.model('registerVals.email')).sendKeys('user@example.com');
|
||||
element(by.model('registerVals.password')).sendKeys('pass');
|
||||
element(by.model('registerVals.confirmPassword')).sendKeys('pass');
|
||||
var register = element(by.css("#register-tab input[value='Register']"));
|
||||
register.click();
|
||||
browser.sleep(1000);
|
||||
browser.getCurrentUrl().then(function(url){
|
||||
expect(url).not.toMatch(/static\/front/);
|
||||
});
|
||||
});
|
||||
});
|
||||
Executable
+20
@@ -0,0 +1,20 @@
|
||||
#!/bin/bash
|
||||
# Configuration
|
||||
TEST_DB=habitrpg_test
|
||||
TEST_DB_URI="mongodb://localhost/$TEST_DB"
|
||||
TEST_SERVER_PORT=3001
|
||||
|
||||
# Build assets
|
||||
grunt build:dev
|
||||
|
||||
# Launch Node server and Selenium
|
||||
echo "Recreating test database"
|
||||
mongo "$TEST_DB" --eval "db.dropDatabase()"
|
||||
./node_modules/protractor/bin/webdriver-manager update
|
||||
./node_modules/protractor/bin/webdriver-manager start > /dev/null &
|
||||
NODE_DB_URI="$TEST_DB_URI" PORT=$TEST_SERVER_PORT node ./src/server.js > /dev/null &
|
||||
NODE_PID=$!
|
||||
trap "kill $NODE_PID && curl http://localhost:4444/selenium-server/driver/?cmd=shutDownSeleniumServer" EXIT
|
||||
|
||||
sleep 3 # Wait for Selenium
|
||||
grunt karma:continuous && ./node_modules/protractor/bin/protractor protractor.conf.js
|
||||
@@ -137,3 +137,8 @@ script(type='text/ng-template', id='partials/options.inventory.drops.html')
|
||||
p
|
||||
| {{Content.spells.special.snowball.value}}
|
||||
span.Pet_Currency_Gem1x.inline-gems
|
||||
div(ng-show='user.flags.rebirthEnabled')
|
||||
button.customize-option(popover='Begin a new character at Level 1 while retaining achievements, collectibles, and tasks with history.', popover-title='Orb of Rebirth', popover-trigger='mouseenter', popover-placement='left', ng-click='modals.rebirth = true', class='rebirth_orb')
|
||||
p
|
||||
| 8
|
||||
span.Pet_Currency_Gem1x.inline-gems
|
||||
|
||||
@@ -167,25 +167,25 @@ script(id='partials/options.profile.stats.html', type='text/ng-template')
|
||||
table.table.table-striped
|
||||
tr
|
||||
td
|
||||
i.icon-question-sign(popover-title='Strength', popover='Strength increases damage you inflict to tasks (reducing redness), and increases critical hit chance.', popover-trigger='mouseenter')
|
||||
i.icon-question-sign(popover-title='Strength', popover='Strength reduces task threat (redness), increases the Gold and Experience boost from random "critical hits," and helps deal damage to boss monsters.', popover-trigger='mouseenter')
|
||||
| STR: {{user.stats.str}}
|
||||
td
|
||||
a.btn.btn-primary(ng-show='user.stats.points', ng-click='allocate("str")') +
|
||||
tr
|
||||
td
|
||||
i.icon-question-sign(popover-title='Constitution', popover='Constitution decreases damage inflicted by tasks, and increases the effectiveness of healing and buff spells.', popover-trigger='mouseenter')
|
||||
i.icon-question-sign(popover-title='Constitution', popover='Constitution reduces the damage you take, whether from negative Habits, missed Dailies, or the attacks of boss monsters.', popover-trigger='mouseenter')
|
||||
| CON: {{user.stats.con}}
|
||||
td
|
||||
a.btn.btn-primary(ng-show='user.stats.points', ng-click='allocate("con")') +
|
||||
tr
|
||||
td
|
||||
i.icon-question-sign(popover-title='Perception', popover='Perception increases drops and gold, and can help with critical hits by spells.', popover-trigger='mouseenter')
|
||||
i.icon-question-sign(popover-title='Perception', popover='Perception increases how much Gold you earn, and increases the chance of finding items when scoring tasks.', popover-trigger='mouseenter')
|
||||
| PER: {{user.stats.per}}
|
||||
td
|
||||
a.btn.btn-primary(ng-show='user.stats.points', ng-click='allocate("per")') +
|
||||
tr
|
||||
td
|
||||
i.icon-question-sign(popover-title='Intelligence', popover='Intelligence increases your overall mana, spell effectiveness, and experience gain.', popover-trigger='mouseenter')
|
||||
i.icon-question-sign(popover-title='Intelligence', popover='Intelligence increases how much Experience you earn, and determines your maximum Mana available for class abilities.', popover-trigger='mouseenter')
|
||||
| INT: {{user.stats.int}}
|
||||
td
|
||||
a.btn.btn-primary(ng-show='user.stats.points', ng-click='allocate("int")') +
|
||||
|
||||
@@ -48,7 +48,8 @@ script(type='text/ng-template', id='partials/options.settings.settings.html')
|
||||
div(ng-if='!user.preferences.disableClasses')
|
||||
button.btn(ng-click='showClassesTour()', popover-trigger='mouseenter', popover-placement='right', popover="Show the tour for using the class system.") Show Classes Tour
|
||||
|
||||
div(ng-show='user.auth.local')
|
||||
//- 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 Change Password
|
||||
form(ng-submit='changePassword(changePass)', ng-show='user.auth.local')
|
||||
|
||||
@@ -46,3 +46,4 @@ figure.herobox(ng-click='spell ? castEnd(profile, "user", $event) : clickMember(
|
||||
.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='Buffed', style='margin-right:5px;')
|
||||
| Lvl {{profile.stats.lvl}}
|
||||
i.icon-plus-sign.icon-white(ng-show='profile.achievements.rebirths', tooltip='Reborn, max level {{profile.achievements.rebirthLevel}}', style='margin-left:5px')
|
||||
|
||||
@@ -7,7 +7,7 @@ div(modal='modals.achievements.streak')
|
||||
.achievement.achievement-thermometer
|
||||
| You have stacked your "Streaker" Achievement! Every 21 days of streak, you gain 1 achievement point here.
|
||||
.modal-footer
|
||||
button.btn.btn-default.cancel(ng-click='modals.achievements.streak = false') Ok
|
||||
button.btn.btn-default.cancel(ng-click='modals.achievements.streak = false') OK
|
||||
|
||||
// Max Gear
|
||||
div(modal='modals.achievements.ultimateGear')
|
||||
@@ -17,7 +17,7 @@ div(modal='modals.achievements.ultimateGear')
|
||||
.achievement.achievement-armor
|
||||
| You have earned the "Ultimate Gear" Achievement for upgrading to the maximum gear set!
|
||||
.modal-footer
|
||||
button.btn.btn-default.cancel(ng-click='modals.achievements.ultimateGear = false') Ok
|
||||
button.btn.btn-default.cancel(ng-click='modals.achievements.ultimateGear = false') OK
|
||||
|
||||
// Beast Master
|
||||
div(modal='modals.achievements.beastMaster')
|
||||
@@ -28,7 +28,7 @@ div(modal='modals.achievements.beastMaster')
|
||||
.achievement.achievement-rat
|
||||
| You have earned the "Beast Master" Achievement for collecting all the pets!
|
||||
.modal-footer
|
||||
button.btn.btn-default.cancel(ng-click='modals.achievements.beastMaster = false') Ok
|
||||
button.btn.btn-default.cancel(ng-click='modals.achievements.beastMaster = false') OK
|
||||
|
||||
// Contributor
|
||||
div(modal='user.flags.contributor')
|
||||
@@ -40,7 +40,15 @@ div(modal='user.flags.contributor')
|
||||
{{user.profile.name}}, you awesome person! You're now a level {{user.contributor.level}} contributor for helping HabitRPG. See <a href='http://habitrpg.wikia.com/wiki/Contributor_Rewards' target='_blank'>what prizes you've earned for your contribution!</a>
|
||||
|
||||
.modal-footer
|
||||
button.btn.btn-default.cancel(ng-click='set({"flags.contributor":false})') Ok
|
||||
|
||||
button.btn.btn-default.cancel(ng-click='set({"flags.contributor":false})') OK
|
||||
|
||||
//Rebirth
|
||||
div(modal='modals.achievements.rebirth')
|
||||
.modal-header
|
||||
h3 Achievement!
|
||||
.modal-body
|
||||
.achievement.achievement-sun
|
||||
| You've begun a new adventure! This is Rebirth {{user.achievements.rebirths}} for you, and the highest Level you've attained is {{user.achievements.rebirthLevel}}. To stack this Achievement, begin your next new adventure when you've reached an even higher Level!
|
||||
.modal-footer
|
||||
button.btn.btn-default.cancel(ng-click='modals.achievements.rebirth = false') OK
|
||||
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
.modal(ng-if='!user.flags.classSelected && user.stats.lvl >= 10', data-backdrop=true, ng-controller='UserCtrl')
|
||||
.modal-header
|
||||
h3 Choose Your Class!
|
||||
h3 Choose Your <a href='http://habitrpg.wikia.com/wiki/Class_System' target='_blank'>Class</a>!
|
||||
.modal-body.select-class
|
||||
p Select your class. Click each class for more information. See <a href="http://habitrpg.wikia.com/wiki/Class_System" target="_blank">Wikia</a> for thorough details.
|
||||
.row-fluid
|
||||
.span3(ng-click='selectedClass = "warrior"')
|
||||
h5 Warrior
|
||||
h5 <a href='http://habitrpg.wikia.com/wiki/Warrior' target='_blank'>Warrior</a>
|
||||
figure.herobox(ng-class='{"selected-class": selectedClass=="warrior"}')
|
||||
.character-sprites
|
||||
span(class='skin_{{user.preferences.skin}}')
|
||||
@@ -19,7 +18,7 @@
|
||||
span(class='shield_warrior_5')
|
||||
span(class='weapon_warrior_6')
|
||||
.span3(ng-click='selectedClass = "wizard"')
|
||||
h5 Mage
|
||||
h5 <a href='http://habitrpg.wikia.com/wiki/Mage' target='_blank'>Mage</a>
|
||||
figure.herobox(ng-class='{"selected-class": selectedClass=="wizard"}')
|
||||
.character-sprites
|
||||
span(class='skin_{{user.preferences.skin}}')
|
||||
@@ -33,7 +32,7 @@
|
||||
span(class='shield_wizard_5')
|
||||
span(class='weapon_wizard_6')
|
||||
.span3(ng-click='selectedClass = "rogue"')
|
||||
h5 Rogue
|
||||
h5 <a href='http://habitrpg.wikia.com/wiki/Rogue' target='_blank'>Rogue</a>
|
||||
figure.herobox(ng-class='{"selected-class": selectedClass=="rogue"}')
|
||||
.character-sprites
|
||||
span(class='skin_{{user.preferences.skin}}')
|
||||
@@ -47,7 +46,7 @@
|
||||
span(class='shield_rogue_6')
|
||||
span(class='weapon_rogue_6')
|
||||
.span3(ng-click='selectedClass = "healer"')
|
||||
h5 Healer
|
||||
h5 <a href='http://habitrpg.wikia.com/wiki/Healer' target='_blank'>Healer</a>
|
||||
figure.herobox(ng-class='{"selected-class": selectedClass=="healer"}')
|
||||
.character-sprites
|
||||
span(class='skin_{{user.preferences.skin}}')
|
||||
@@ -61,10 +60,10 @@
|
||||
span(class='shield_healer_5')
|
||||
span(class='weapon_healer_6')
|
||||
br
|
||||
.well(ng-show='selectedClass=="warrior"') Warriors deal damage to tasks (reducing redness), have moderate defense, and improved critical hits.
|
||||
.well(ng-show='selectedClass=="wizard"') Mages deal damage to tasks (reducing redness), can debuff tasks, and they gain experience rapidly.
|
||||
.well(ng-show='selectedClass=="rogue"') Rogues finds more drops and gold. They can also "go stealth" to avoid damage at the end of a day.
|
||||
.well(ng-show='selectedClass=="healer"') Healers have high defense against damage, and can heal themselves and other players in the party, as well as buff players.
|
||||
.well(ng-show='selectedClass=="warrior"') Warriors keep tasks in line, each success making later slip-ups less harsh. They also score impressive "critical hits," which randomly give bonus Gold and Experience for scoring a task. Play a Warrior if you don't want to be punished too hard for inconsistency, or if you find strong motivation from unpredictable jackpot-style rewards!
|
||||
.well(ng-show='selectedClass=="wizard"') Mages learn swiftly, gaining Experience and Levels faster than other classes. They also get a great deal of Mana for using special abilities. Play a Mage if you enjoy the tactical game aspects of Habit, or if you are strongly motivated by leveling up and unlocking advanced features!
|
||||
.well(ng-show='selectedClass=="rogue"') Rogues love to accumulate wealth, gaining more Gold than anyone else, and are adept at finding random items. Their iconic Stealth ability lets them duck the consequences of missed Dailies. Play a Rogue if you find strong motivation from Rewards and Achievements, striving for loot and badges!
|
||||
.well(ng-show='selectedClass=="healer"') Healers stand impervious against harm, and extend that protection to others. Missed Dailies and bad Habits don't faze them much, and they have ways to recover Health from failure. Play a Healer if you enjoy assisting others in your Party, or if the idea of cheating Death through hard work inspires you!
|
||||
|
||||
.modal-footer
|
||||
button.btn.btn-small.btn-danger.cancel(ng-click='user.ops.disableClasses({})', popover-placement='top', popover-trigger='mouseenter', popover="Can't be bothered with classes? Opt out - you'll be a warrior and your points handled automatically. You can enable classes later under Settings") Opt Out
|
||||
|
||||
@@ -8,4 +8,5 @@ include ./members
|
||||
include ./settings
|
||||
include ./drops
|
||||
include ./classes
|
||||
include ./quests
|
||||
include ./quests
|
||||
include ./rebirth
|
||||
@@ -26,48 +26,73 @@ div(modal='modals.newStuff')
|
||||
a(target='_blank', href='https://twitter.com/Mihakuu') Bailey
|
||||
.popover-content
|
||||
|
||||
h3 Winter Wonderland Event!
|
||||
|
||||
h4 Part 2: Rescue the Bears
|
||||
h4 Winter Wonderland Event Part 3: Party!
|
||||
table.table.table-striped
|
||||
tr
|
||||
td
|
||||
h5 Quests & Bosses!
|
||||
p A beast is roaring in the distant mountains, mysterious tracks have appeared in the snow. A new feature has been unlocked, <a href='https://trello.com/c/VPPjVRlF/212-quests-bosses' target='_blank'>Quests & Bosses</a>. As a holiday present, HabitRPG gives you your first quest: "Trapper Santa". Check your inventory, you have until Jan 31 to complete it!
|
||||
h5 Happy New Year!
|
||||
p Happy New Year! Join the NPCs and Staff in showing off your new Absurd party hat.... and have a great night!
|
||||
small.muted by @lemoness
|
||||
tr
|
||||
td
|
||||
h5 Rebirth
|
||||
p Nothing says New Year like a fresh start. Now when you reach level 50, Ultimate Gear, or BeastMaster, you can begin anew with the most prestigious of achievements: Rebirth. <a href='https://trello.com/c/SLiq4enr/333-rebirth-new-game' target='_blank'>Read more here</a>. But take heed! Scouts have reported <a href='https://github.com/HabitRPG/habitrpg/issues/945#issuecomment-31355229' target='_blank'>monster sightings</a>, harbinged by Trapper Santa. You may need all the strength you can muster come late January, Rebirth is for the hard-core.
|
||||
small.muted by @SabreCat
|
||||
tr
|
||||
td
|
||||
h5 Checklists
|
||||
p <a href='https://trello.com/c/PJ1iJ413/65-checklists' target='_blank'>Checklists</a> are here! You can break your Dailies and To-Dos down into bite-size chunks. Their game mechanic takes some learning, so <a href='http://habitrpg.wikia.com/wiki/Checklist' target='_blank'>read more here</a>.
|
||||
small.muted by @lefnire
|
||||
tr
|
||||
td
|
||||
h5 Task Icons & Markdown
|
||||
p Task titles now support Markdown and Emoji, so you can create something <a href='http://gyazo.com/f2021674925a79a1dec22101ef74a63c' target='_blank'>like this</a>. Read more <a href='https://trello.com/c/FCVdjdUd/102-task-reward-icons' target='_blank'>here</a>.
|
||||
small.muted by @lefnire
|
||||
|
||||
p By @lefnire, @pandoro, @Shaners
|
||||
small.muted 12/25/2013
|
||||
small.muted 12/31/2013
|
||||
|
||||
div.muted
|
||||
hr
|
||||
p It's time for HabitRPG's biggest event yet - Winter Wonderland! The fun starts today, on the first day of winter, and ends on January 31st - HabitRPG's birthday.
|
||||
p Get prepared to build new habits, earn fun drops, hold your party members accountable for their tasks, and decorate your avatar. Various features will be rolling out over the course of the event, so expect many updates! For starters...
|
||||
h4 Part 1: The Great Snowball Fight
|
||||
table.table.table-striped
|
||||
tr
|
||||
td
|
||||
h5 NPC Decorations
|
||||
p Looks like everyone is really getting into the winter spirit! Check out the new NPC sprites. (And I heard a rumor that the final NPC might show up, just in time for the new year...)
|
||||
tr
|
||||
td
|
||||
.customize-option.hair_bangs_1_winternight.pull-right
|
||||
h5 Limited-Edition Holiday Hair-Colors
|
||||
p Now your avatar can dye their hair Candy Cane, Frost, Winter Sky, or Holly! You'll only be able to purchase these hair colors until January 31st, when they will be retired.
|
||||
tr
|
||||
td
|
||||
.shop_snowball.pull-right
|
||||
h5 The Great HabitRPG Snowball Fight
|
||||
p Yes, you can now buy snowballs and hurl them at all your friends... to, uh, help them improve their habits. How? Weeeeellll, let's just say that after getting walloped, they might find themselves needing some extra gold to escape their predicament...
|
||||
//-span.shop_head_special_candycane.item-img.shop-sprite
|
||||
tr
|
||||
td
|
||||
h5 More to Come
|
||||
p A beast is roaring in the distant mountains, mysterious tracks have appeared in the snow, and Lemoness is furiously crocheting something sparkly.
|
||||
p It's going to be a wild winter.
|
||||
|
||||
p By @lemoness
|
||||
small.muted 12/20/2013
|
||||
hr
|
||||
h5 12/25/2013
|
||||
h4 Winter Wonderland Event Part 2: Rescue the Bears
|
||||
table.table.table-striped
|
||||
tr
|
||||
td
|
||||
h5 Quests & Bosses!
|
||||
p A beast is roaring in the distant mountains, mysterious tracks have appeared in the snow. A new feature has been unlocked, <a href='https://trello.com/c/VPPjVRlF/212-quests-bosses' target='_blank'>Quests & Bosses</a>. As a holiday present, HabitRPG gives you your first quest: "Trapper Santa". Check your inventory, you have until Jan 31 to complete it!
|
||||
|
||||
p By @lefnire, @pandoro, @Shaners
|
||||
|
||||
hr
|
||||
|
||||
|
||||
h5 12/20/2013
|
||||
h4 Winter Wonderland Event Part 1: The Great Snowball Fight
|
||||
p It's time for HabitRPG's biggest event yet - Winter Wonderland! The fun starts today, on the first day of winter, and ends on January 31st - HabitRPG's birthday.
|
||||
p Get prepared to build new habits, earn fun drops, hold your party members accountable for their tasks, and decorate your avatar. Various features will be rolling out over the course of the event, so expect many updates! For starters...
|
||||
table.table.table-striped
|
||||
tr
|
||||
td
|
||||
h5 NPC Decorations
|
||||
p Looks like everyone is really getting into the winter spirit! Check out the new NPC sprites. (And I heard a rumor that the final NPC might show up, just in time for the new year...)
|
||||
tr
|
||||
td
|
||||
.customize-option.hair_bangs_1_winternight.pull-right
|
||||
h5 Limited-Edition Holiday Hair-Colors
|
||||
p Now your avatar can dye their hair Candy Cane, Frost, Winter Sky, or Holly! You'll only be able to purchase these hair colors until January 31st, when they will be retired.
|
||||
tr
|
||||
td
|
||||
.shop_snowball.pull-right
|
||||
h5 The Great HabitRPG Snowball Fight
|
||||
p Yes, you can now buy snowballs and hurl them at all your friends... to, uh, help them improve their habits. How? Weeeeellll, let's just say that after getting walloped, they might find themselves needing some extra gold to escape their predicament...
|
||||
//-span.shop_head_special_candycane.item-img.shop-sprite
|
||||
tr
|
||||
td
|
||||
h5 More to Come
|
||||
p A beast is roaring in the distant mountains, mysterious tracks have appeared in the snow, and Lemoness is furiously crocheting something sparkly.
|
||||
p It's going to be a wild winter.
|
||||
|
||||
p By @lemoness
|
||||
|
||||
hr
|
||||
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
// Created by Sabe on 12/22/13.
|
||||
|
||||
div(modal='modals.rebirthEnabled')
|
||||
.modal-header
|
||||
h3 Rebirth: New Adventure Available!
|
||||
.modal-body
|
||||
.rebirth_orb.pull-left(style='margin-right: 5px')
|
||||
p
|
||||
span.
|
||||
You've unlocked Rebirth! This special Market item allows you to begin a new game at level 1 while keeping your tasks, achievements, pets, and more. Use it to breathe new life into HabitRPG if you feel you've achieved it all, or to experience new features with the fresh eyes of a beginning character!
|
||||
.modal-footer
|
||||
button.btn.btn-default.cancel(ng-click='modals.rebirthEnabled = false') Close
|
||||
|
||||
div(modal='modals.rebirth')
|
||||
.modal-header
|
||||
h3 Rebirth: Begin a New Adventure
|
||||
.modal-body
|
||||
include ../gems
|
||||
.rebirth_orb.pull-left(style='margin-right: 5px')
|
||||
p Rebirth starts your character over from Level 1, as if you had created a new account.
|
||||
br
|
||||
p Your adventure begins anew with a clean slate:
|
||||
.unordered
|
||||
li You return to full Health.
|
||||
li You have no Experience, Gold, or equipment.
|
||||
li Your Habits, Dailies, and To-Dos reset to yellow, and streaks reset.
|
||||
li You have the starting class of Warrior until you earn a new class.
|
||||
br
|
||||
p Your new character inherits a few things from their predecessor:
|
||||
.unordered
|
||||
li Tasks, history, and settings remain.
|
||||
li Challenge, Guild, and Party memberships remain.
|
||||
li Gems, backer tiers, and contributor levels remain.
|
||||
li Items obtained from Gems or drops (such as pets and mounts) remain, though you cannot access them until you unlock them again.
|
||||
br
|
||||
.achievement-sun.pull-left(style='margin-right: 5px')
|
||||
p You also earn an Achievement for beginning a new adventure!
|
||||
.modal-footer
|
||||
button.btn.btn-large.cancel(ng-click='modals.rebirth = false') Never mind
|
||||
span(ng-if='user.balance < 2')
|
||||
a.btn.btn-success.btn-large(ng-click="modals.buyGems = true") Buy More Gems
|
||||
span.gem-cost Not enough Gems
|
||||
span(ng-if='user.balance >= 2', ng-controller='SettingsCtrl')
|
||||
a.btn.btn-danger.btn-large(ng-click='rebirth()') Be Reborn
|
||||
span.gem-cost 8 Gems
|
||||
@@ -3,7 +3,6 @@
|
||||
// <div class='achievement achievement-tree'></div>
|
||||
// <div class='achievement achievement-comment'></div>
|
||||
// <div class='achievement achievement-cave'></div>
|
||||
// <div class='achievement achievement-sun'></div>
|
||||
// <div class='achievement achievement-boot'></div>
|
||||
// <div class='achievement achievement-coffin'></div>
|
||||
// <div class='achievement achievement-alien'></div>
|
||||
@@ -57,6 +56,14 @@
|
||||
small Has found all 90 pets (insanely difficult, give this user props!)
|
||||
hr
|
||||
|
||||
div(ng-if='profile.achievements.rebirths')
|
||||
.achievement.achievement-sun
|
||||
h5(ng-if='profile.achievements.rebirths == 1') Began a New Adventure
|
||||
h5(ng-if='profile.achievements.rebirths > 1') Began {{profile.achievements.rebirths}} New Adventures
|
||||
small.
|
||||
Used an Orb of Rebirth to start over after attaining Level {{profile.achievements.rebirthLevel}}.
|
||||
hr
|
||||
|
||||
div(ng-if='profile.achievements.helpedHabit')
|
||||
.achievement.achievement-tree
|
||||
h5 Helped Habit Grow
|
||||
@@ -100,4 +107,4 @@
|
||||
.achievement.achievement-snowball
|
||||
h5 Annoying Friends
|
||||
small Got snowballed {{profile.achievements.snowball}} times by party members.
|
||||
hr
|
||||
hr
|
||||
|
||||
@@ -46,10 +46,10 @@ script(id='templates/habitrpg-tasks.html', type="text/ng-template")
|
||||
|
||||
// Static Rewards
|
||||
ul.items.rewards(ng-if='main && list.type=="reward" && user.flags.itemsEnabled')
|
||||
li.task.reward-item(ng-repeat='item in itemStore')
|
||||
li.task.reward-item(ng-repeat='item in itemStore',popover-trigger='mouseenter', popover-placement='top', popover='{{item.notes}}')
|
||||
// right-hand side control buttons
|
||||
.task-meta-controls
|
||||
span.task-notes(popover-trigger='mouseenter', popover-placement='left', popover='{{item.notes}}', popover-title='{{item.text}}')
|
||||
span.task-notes
|
||||
i.icon-comment
|
||||
//left-hand size commands
|
||||
.task-controls
|
||||
@@ -62,9 +62,9 @@ script(id='templates/habitrpg-tasks.html', type="text/ng-template")
|
||||
|
||||
// Winter Event
|
||||
ul.items.rewards(ng-if='main && list.type=="reward" && (user.items.special.snowball>0 || user.stats.buffs.snowball)')
|
||||
li.task.reward-item(ng-if='user.items.special.snowball>0')
|
||||
li.task.reward-item(ng-if='user.items.special.snowball>0',popover-trigger='mouseenter', popover-placement='top', popover='{{Content.spells.special.snowball.notes}}')
|
||||
.task-meta-controls
|
||||
span.task-notes(popover-trigger='mouseenter', popover-placement='left', popover='{{Content.spells.special.snowball.notes}}', popover-title='{{Content.spells.special.snowball.text}}')
|
||||
span.task-notes
|
||||
i.icon-comment
|
||||
//left-hand size commands
|
||||
.task-controls
|
||||
@@ -73,9 +73,9 @@ script(id='templates/habitrpg-tasks.html', type="text/ng-template")
|
||||
span.shop_snowball(style='display:inline-block;vertical-align:top;')
|
||||
// main content
|
||||
p.task-text {{Content.spells.special.snowball.text}}
|
||||
li.task.reward-item(ng-if='user.stats.buffs.snowball')
|
||||
li.task.reward-item(ng-if='user.stats.buffs.snowball',popover-trigger='mouseenter', popover-placement='top', popover='{{Content.spells.special.salt.notes}}')
|
||||
.task-meta-controls
|
||||
span.task-notes(popover-trigger='mouseenter', popover-placement='left', popover='{{Content.spells.special.salt.notes}}', popover-title='{{Content.spells.special.salt.text}}')
|
||||
span.task-notes
|
||||
i.icon-comment
|
||||
//left-hand size commands
|
||||
.task-controls
|
||||
@@ -88,9 +88,9 @@ script(id='templates/habitrpg-tasks.html', type="text/ng-template")
|
||||
|
||||
// Spells
|
||||
ul.items(ng-if='main && list.type=="reward" && user.stats.class && !user.preferences.disableClasses')
|
||||
li.task.reward-item(ng-repeat='(k,spell) in Content.spells[user.stats.class]', ng-show='user.stats.lvl >= spell.lvl')
|
||||
li.task.reward-item(ng-repeat='(k,spell) in Content.spells[user.stats.class]', ng-if='user.stats.lvl >= spell.lvl',popover-trigger='mouseenter', popover-placement='top', popover='{{spell.notes}}')
|
||||
.task-meta-controls
|
||||
span.task-notes(popover-trigger='mouseenter', popover-placement='left', popover='{{spell.notes}}', popover-title='{{spell.text}}')
|
||||
span.task-notes
|
||||
i.icon-comment
|
||||
//left-hand size commands
|
||||
.task-controls
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
li(bindonce='list', ng-repeat='task in obj[list.type+"s"] | completedFilter: list.showCompleted', class='task {{Shared.taskClasses(task, user.filters, user.preferences.dayStart, user.lastCron, list.showCompleted, main)}}', ng-click='spell && castEnd(task, "task", $event)', ng-class='{"cast-target":spell}')
|
||||
li(bindonce='list', bo-id='"task-"+task.id', ng-repeat='task in obj[list.type+"s"]', class='task {{Shared.taskClasses(task, user.filters, user.preferences.dayStart, user.lastCron, list.showCompleted, main)}}', ng-click='spell && castEnd(task, "task", $event)', ng-class='{"cast-target":spell}', popover-trigger='mouseenter', popover-placement='top', popover='{{task.notes}}')
|
||||
// right-hand side control buttons
|
||||
.task-meta-controls
|
||||
|
||||
// Due Date
|
||||
span.task-date(ng-if='task.type=="todo" && task.date')
|
||||
| {{task.date}}
|
||||
span(ng-class='{"label label-important":moment(task.date).isBefore(_today)}') {{moment(task.date).format('MM/DD')}}
|
||||
// Streak
|
||||
span(ng-show='task.streak') {{task.streak}}
|
||||
span(tooltip='Streak Counter')
|
||||
@@ -12,6 +12,9 @@ li(bindonce='list', ng-repeat='task in obj[list.type+"s"] | completedFilter: lis
|
||||
|
||||
// Icons only available if you own the tasks (aka, hidden from challenge stats)
|
||||
span(ng-if='!obj._locked')
|
||||
a.badge(ng-if='task.checklist[0]', ng-class='{"badge-success":checklistCompletion(task.checklist) == task.checklist.length}', ng-click='collapseChecklist(task)')
|
||||
{{checklistCompletion(task.checklist)}}/{{task.checklist.length}}
|
||||
|
||||
i.icon-tags(tooltip='{{appliedTags(user.tags, task.tags)}}', ng-hide='Shared.noTags(task.tags)')
|
||||
// edit
|
||||
a(ng-hide='task._editing', ng-click='editTask(task)', tooltip='Edit')
|
||||
@@ -36,7 +39,7 @@ li(bindonce='list', ng-repeat='task in obj[list.type+"s"] | completedFilter: lis
|
||||
a(ng-show='task.history', ng-click='toggleChart(obj._id+task.id, task)', tooltip='Progress')
|
||||
i.icon-signal
|
||||
// notes
|
||||
span.task-notes(ng-show='task.notes && !task._editing', popover-trigger='mouseenter', popover-placement='left', popover='{{task.notes}}', popover-title='{{task.text}}')
|
||||
span.task-notes(ng-show='task.notes && !task._editing')
|
||||
i.icon-comment
|
||||
|
||||
// left-hand side checkbox
|
||||
@@ -60,10 +63,16 @@ li(bindonce='list', ng-repeat='task in obj[list.type+"s"] | completedFilter: lis
|
||||
input.visuallyhidden.focusable(ng-if='!$state.includes("tasks")', id='box-{{obj._id}}_{{task.id}}', type='checkbox')
|
||||
label(for='box-{{obj._id}}_{{task.id}}')
|
||||
// main content
|
||||
p.task-text
|
||||
div.task-text(ng-dblclick='task._editing ? saveTask(task) : editTask(task)')
|
||||
markdown(ng-model='task.text',target='_blank')
|
||||
//-| {{task.text}}
|
||||
|
||||
div(ng-if='task.checklist && !$state.includes("options.social.challenges") && !task.collapseChecklist && !task._editing')
|
||||
fieldset.option-group
|
||||
label.checkbox(ng-repeat='item in task.checklist')
|
||||
input(type='checkbox',ng-model='item.completed',ng-change='saveTask(task,true)')
|
||||
| {{item.text}}
|
||||
|
||||
// edit/options dialog
|
||||
div(ng-if='task._editing')
|
||||
.task-options
|
||||
@@ -96,6 +105,23 @@ li(bindonce='list', ng-repeat='task in obj[list.type+"s"] | completedFilter: lis
|
||||
| |
|
||||
a(ng-click="unlink(task, 'remove-all')") Remove Them
|
||||
|
||||
// Checklists
|
||||
a.btn.btn-small(ng-if='!task.checklist[0] && (task.type=="daily" || task.type=="todo")',ng-click='addChecklist(task)')
|
||||
i.icon-tasks
|
||||
| Add Checklist
|
||||
form.checklist-form(ng-if='task.checklist')
|
||||
fieldset.option-group.task-checklist(ng-if='!$state.includes("options.social.challenges")')
|
||||
legend.option-title
|
||||
| Checklist
|
||||
i.icon.icon-question-sign(popover='For Dailies, partially-completed Dailies will cut damage (eg, a 4-item checklist with 3 completed, your Daily will hurt you 25% of the damage). For To-Dos, when completed, your points will be multiplied by the number of checklist-items (eg, a 4-item To-Do will be 4x the Exp & GP).',popover-trigger='mouseenter',popover-placement='bottom')
|
||||
ul.unstyled
|
||||
li(ng-repeat='item in task.checklist')
|
||||
a.pull-right.checklist-icons(ng-click='removeChecklistItem(task,$index,true)')
|
||||
i.icon-trash(tooltip='Delete')
|
||||
input(type='checkbox',ng-model='item.completed',ng-change='saveTask(task,true)')
|
||||
input.inline-edit(type='text',ng-model='item.text',ui-keyup="{13:'addChecklistItem(task,$event,$index)','8 49':'removeChecklistItem(task,$index)','38 40':'navigateChecklist(task,$index,$event)'}")//-,ng-blur='saveTask(task,true)')
|
||||
|
||||
|
||||
form(ng-submit='saveTask(task)')
|
||||
// text & notes
|
||||
fieldset.option-group
|
||||
@@ -138,7 +164,7 @@ li(bindonce='list', ng-repeat='task in obj[list.type+"s"] | completedFilter: lis
|
||||
// if Todos, the due date
|
||||
fieldset.option-group(ng-if='task.type=="todo" && !task.challenge.id')
|
||||
legend.option-title Due Date
|
||||
input.option-content.datepicker(type='text', data-date-format='mm/dd/yyyy', ng-model='task.date')
|
||||
input.option-content.datepicker(type='text', datepicker-popup='MM/dd/yyyy', ng-model='task.date')
|
||||
|
||||
fieldset.option-group(ng-if='!$state.includes("options.social.challenges")')
|
||||
legend.option-title Tags
|
||||
@@ -159,9 +185,8 @@ li(bindonce='list', ng-repeat='task in obj[list.type+"s"] | completedFilter: lis
|
||||
button.task-action-btn.tile(type='button', ng-class='{active: task.priority==1.5}', ng-click='task.challenge.id || (task.priority=1.5)') Medium
|
||||
button.task-action-btn.tile(type='button', ng-class='{active: task.priority==2}', ng-click='task.challenge.id || (task.priority=2)') Hard
|
||||
//span(ng-if='task.type=="daily" && !task.challenge.id')
|
||||
br
|
||||
span(ng-if='task.type=="daily"')
|
||||
legend.option-title Restore Streak
|
||||
legend.option-title.pull-left Restore Streak
|
||||
input.option-content(type='number', ng-model='task.streak')
|
||||
|
||||
legend.option-title Attributes
|
||||
|
||||
Reference in New Issue
Block a user