Merge branch 'develop' into nthomsn-develop

This commit is contained in:
Blade Barringer 2015-06-14 01:27:35 -05:00
commit 831f5b89bd
103 changed files with 1465 additions and 1432 deletions

2
.gitignore vendored
View file

@ -27,4 +27,4 @@ coverage
coverage.html
common/dist/scripts/habitrpg-shared.js
test/spec/translations.js
test/spec/mocks/translations.js

View file

@ -220,7 +220,7 @@ module.exports = function(grunt) {
require('coffee-script');
var i18n = require('./website/src/i18n'),
fs = require('fs');
fs.writeFileSync('test/spec/translations.js',
fs.writeFileSync('test/spec/mocks/translations.js',
"if(!window.env) window.env = {};\n" +
"window.env.translations = " + JSON.stringify(i18n.translations['en']) + ';');
});

Binary file not shown.

Before

Width:  |  Height:  |  Size: 153 KiB

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 697 B

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 664 B

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 705 B

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 693 B

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 667 B

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 704 B

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 542 B

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

View file

@ -48,5 +48,9 @@
"removeTasks": "Remove Tasks",
"keepTasks": "Keep Tasks",
"closeCha": "Close challenge and...",
"leaveCha": "Leave challenge and..."
"leaveCha": "Leave challenge and...",
"challengedOwnedFilterHeader": "Ownership",
"challengedOwnedFilter": "Owned",
"challengedNotOwnedFilter": "Not Owned",
"challengedEitherOwnedFilter": "Either"
}

View file

@ -36,6 +36,11 @@
"newDailyBulk": "New Dailies (one per line)",
"streakCounter": "Streak Counter",
"repeat": "Repeat",
"repeatEvery": "Repeat Every",
"repeatDays": "Every X Days",
"repeatWeek": "On Certain Days of the Week",
"day": "Day",
"days": "Days",
"restoreStreak": "Restore Streak",
"todos": "To-Dos",
"newTodo": "New To-Do",
@ -60,6 +65,9 @@
"clearTags": "Clear",
"hideTags": "Hide",
"showTags": "Show",
"startDate": "Start Date",
"startDateHelpTitle": "When should this task start?",
"startDateHelp": "Set the date for which this task takes effect. Will not be due on earlier days.",
"streakName": "Streak Achievements",
"streakText": "Has performed <%= streaks %> 21-day streaks on Dailies",
"streakSingular": "Streaker",
@ -95,5 +103,6 @@
"rewardHelp1": "The Equipment you buy for your avatar is stored in <%= linkStart %>Inventory > Equipment<%= linkEnd %>.",
"rewardHelp2": "Equipment affects your stats (<%= linkStart %>Avatar > Stats<%= linkEnd %>).",
"rewardHelp3": "Special equipment will appear here during World Events.",
"rewardHelp4": "Don't be afraid to set custom Rewards! Check out <a href='http://habitrpg.wikia.com/wiki/Sample_Custom_Rewards' target='_blank'>some samples here</a>."
"rewardHelp4": "Don't be afraid to set custom Rewards! Check out <a href='http://habitrpg.wikia.com/wiki/Sample_Custom_Rewards' target='_blank'>some samples here</a>.",
"clickForHelp": "Click for help"
}

View file

@ -54,6 +54,7 @@
"newReward": "New Reward",
"newRewardBulk": "New Rewards (one per line)",
"price": "Price",
"search": "Search",
"tags": "Tags",
"editTags": "Edit",
"newTag": "New Tag",
@ -79,4 +80,4 @@
"pushTaskToBottom": "Push task to bottom",
"emptyTask": "Enter the task's title first.",
"dailiesRestingInInn": "You're Resting in the Inn! Your Dailies will NOT hurt you tonight, but they WILL still refresh every day. If you're in a quest, you won't deal damage/collect items until you check out of the Inn, but you can still be injured by a Boss if your Party mates skip their own Dailies."
}
}

View file

@ -72,13 +72,37 @@ api.daysSince = (yesterday, options = {}) ->
Math.abs api.startOfDay(_.defaults {now:yesterday}, o).diff(api.startOfDay(_.defaults {now:o.now}, o), 'days')
###
Should the user do this taks on this date, given the task's repeat options and user.preferences.dayStart?
Should the user do this task on this date, given the task's repeat options and user.preferences.dayStart?
###
api.shouldDo = (day, repeat, options={}) ->
return false unless repeat
api.shouldDo = (day, dailyTask, options = {}) ->
return false unless dailyTask.type == 'daily' && dailyTask.repeat
if !dailyTask.startDate
dailyTask.startDate = moment().toDate()
if dailyTask.startDate instanceof String
dailyTask.startDate = moment(dailyTask.startDate).toDate()
o = sanitizeOptions options
selected = repeat[api.dayMapping[api.startOfDay(_.defaults {now:day}, o).day()]]
return selected
day = api.startOfDay(_.defaults {now:day}, o)
dayOfWeekNum = day.day() # e.g. 1 for Monday if week starts on Mon
# check if event is today or in the future
hasStartedCheck = day >= api.startOfDay(_.defaults {now:dailyTask.startDate}, o)
if dailyTask.frequency == 'daily'
daysSinceTaskStart = api.numDaysApart(day.startOf('day'), dailyTask.startDate, o)
everyXCheck = (daysSinceTaskStart % dailyTask.everyX == 0)
return everyXCheck && hasStartedCheck
else if dailyTask.frequency == 'weekly'
dayOfWeekCheck = dailyTask.repeat[api.dayMapping[dayOfWeekNum]]
return dayOfWeekCheck && hasStartedCheck
else
# unexpected frequency string
return false
api.numDaysApart = (day1, day2, o) ->
startOfDay1 = api.startOfDay(_.defaults {now:day1}, o)
startOfDay2 = api.startOfDay(_.defaults {now:day2}, o)
numDays = Math.abs(startOfDay1.diff(startOfDay2, 'days'))
return numDays
###
------------------------------------------------------
@ -211,7 +235,7 @@ api.taskDefaults = (task={}) ->
_.defaults(task, {up:true,down:true}) if task.type is 'habit'
_.defaults(task, {history: []}) if task.type in ['habit', 'daily']
_.defaults(task, {completed:false}) if task.type in ['daily', 'todo']
_.defaults(task, {streak:0, repeat: {su:1,m:1,t:1,w:1,th:1,f:1,s:1}}) if task.type is 'daily'
_.defaults(task, {streak:0, repeat: {su:1,m:1,t:1,w:1,th:1,f:1,s:1}}, startDate: new Date(), everyX: 1, frequency: 'weekly') if task.type is 'daily'
task._id = task.id # may need this for TaskSchema if we go back to using it, see http://goo.gl/a5irq4
task.value ?= if task.type is 'reward' then 10 else 0
task.priority = 1 unless _.isNumber(task.priority) # hotfix for apiv1. once we're off apiv1, we can remove this
@ -281,7 +305,7 @@ api.taskClasses = (task, filters=[], dayStart=0, lastCron=+new Date, showComplet
# show as completed if completed (naturally) or not required for today
if type in ['todo', 'daily']
if completed or (type is 'daily' and !api.shouldDo(+new Date, task.repeat, {dayStart}))
if completed or (type is 'daily' and !api.shouldDo(+new Date, task, {dayStart}))
classes += " completed"
else
classes += " uncompleted"
@ -534,7 +558,7 @@ api.wrap = (user, main=true) ->
user.preferences.costume = false
# Remove unlocked features
flags = user.flags
if not (user.achievements.ultimateGear or user.achievements.beastMaster)
if not user.achievements.beastMaster
flags.rebirthEnabled = false
flags.itemsEnabled = false
flags.dropsEnabled = false
@ -1489,7 +1513,7 @@ api.wrap = (user, main=true) ->
user._tmp.drop = _.defaults content.quests[k],
type: 'Quest'
dialog: i18n.t('messageFoundQuest', {questText: content.quests[k].text(req.language)}, req.language)
if !user.flags.rebirthEnabled and (user.stats.lvl >= 50 or user.achievements.ultimateGear or user.achievements.beastMaster)
if !user.flags.rebirthEnabled and (user.stats.lvl >= 50 or user.achievements.beastMaster)
user.flags.rebirthEnabled = true
if user.stats.lvl >= api.maxLevel and !user.flags.freeRebirth
user.flags.freeRebirth = true
@ -1565,7 +1589,7 @@ api.wrap = (user, main=true) ->
{completed, repeat} = daily
thatDay = moment(now).subtract({days: 1})
if api.shouldDo(thatDay, repeat, user.preferences) || completed
if api.shouldDo(thatDay.toDate(), daily, user.preferences) || completed
_.each daily.checklist, ((box)->box.completed=false;true)
daily.completed = false
return
@ -1592,7 +1616,7 @@ api.wrap = (user, main=true) ->
scheduleMisses = 0
_.times daysMissed, (n) ->
thatDay = moment(now).subtract({days: n + 1})
if api.shouldDo(thatDay, repeat, user.preferences)
if api.shouldDo(thatDay.toDate(), task, user.preferences)
scheduleMisses++
if user.stats.buffs.stealth
user.stats.buffs.stealth--

View file

@ -35,7 +35,7 @@ module.exports = function(config) {
'website/public/bower_components/js-emoji/emoji.js',
'common/dist/scripts/habitrpg-shared.js',
"test/spec/translations.js",
"test/spec/mocks/translations.js",
"website/public/js/env.js",
@ -51,7 +51,9 @@ module.exports = function(config) {
"website/public/js/services/challengeServices.js",
"website/public/js/services/paymentServices.js",
"website/public/js/filters/filters.js",
"website/public/js/filters/money.js",
"website/public/js/filters/roundLargeNumbers.js",
"website/public/js/filters/taskOrdering.js",
"website/public/js/directives/focus-me.directive.js",
"website/public/js/directives/from-now.directive.js",
@ -77,7 +79,7 @@ module.exports = function(config) {
"website/public/js/controllers/footerCtrl.js",
"website/public/js/controllers/challengesCtrl.js",
"website/public/js/controllers/hallCtrl.js",
'test/spec/mock/**/*.js',
'test/spec/mocks/**/*.js',
'test/spec/specHelper.js',
'test/spec/**/*.js'
],

View file

@ -159,7 +159,7 @@ describe 'User', ->
it 'handles perfect days', ->
user = newUser()
user.dailys = []
_.times 3, ->user.dailys.push shared.taskDefaults({type:'daily'})
_.times 3, ->user.dailys.push shared.taskDefaults({type:'daily', startDate: moment().subtract(7, 'days')})
cron = -> user.lastCron = moment().subtract(1,'days');user.fns.cron()
cron()
@ -193,7 +193,7 @@ describe 'User', ->
user.preferences.sleep = true
cron = -> user.lastCron = moment().subtract(1, 'days');user.fns.cron()
user.dailys = []
_.times 2, -> user.dailys.push shared.taskDefaults({type:'daily'})
_.times 2, -> user.dailys.push shared.taskDefaults({type:'daily', startDate: moment().subtract(7, 'days')})
it 'remains in the inn on cron', ->
cron()
@ -883,8 +883,9 @@ describe 'Cron', ->
before.dailys[0].repeat = after.dailys[0].repeat = options.repeat if options.repeat
before.dailys[0].streak = after.dailys[0].streak = 10
before.dailys[0].completed = after.dailys[0].completed = true if options.checked
before.dailys[0].startDate = after.dailys[0].startDate = moment().subtract(30, 'days')
if options.shouldDo
expect(shared.shouldDo(now, options.repeat, {timezoneOffset, dayStart:options.dayStart, now})).to.be.ok()
expect(shared.shouldDo(now.toDate(), after.dailys[0], {timezoneOffset, dayStart:options.dayStart, now})).to.be.ok()
after.fns.cron {now}
before.stats.mp=after.stats.mp #FIXME
switch options.expect

330
test/common/dailies.coffee Normal file
View file

@ -0,0 +1,330 @@
_ = require 'lodash'
expect = require 'expect.js'
sinon = require 'sinon'
moment = require 'moment'
shared = require '../../common/script/index.coffee'
shared.i18n.translations = require('../../website/src/i18n.js').translations
repeatWithoutLastWeekday = ()->
repeat = {su:1,m:1,t:1,w:1,th:1,f:1,s:1}
if shared.startOfWeek(moment().zone(0)).isoWeekday() == 1 # Monday
repeat.su = false
else
repeat.s = false
{repeat: repeat}
### Helper Functions ####
# @TODO: Refactor into helper file
newUser = (addTasks=true)->
buffs = {per:0, int:0, con:0, str:0, stealth: 0, streaks: false}
user =
auth:
timestamps: {}
stats: {str:1, con:1, per:1, int:1, mp: 32, class: 'warrior', buffs: buffs}
items:
lastDrop:
count: 0
hatchingPotions: {}
eggs: {}
food: {}
gear:
equipped: {}
costume: {}
party:
quest:
progress:
down: 0
preferences: {}
dailys: []
todos: []
rewards: []
flags: {}
achievements: {}
contributor:
level: 2
shared.wrap(user)
user.ops.reset(null, ->)
if addTasks
_.each ['habit', 'todo', 'daily'], (task)->
user.ops.addTask {body: {type: task, id: shared.uuid()}}
user
cron = (usr) ->
usr.lastCron = moment().subtract(1,'days')
usr.fns.cron()
describe 'daily/weekly that repeats everyday (default)', ->
user = null
daily = null
weekly = null
describe 'when startDate is in the future', ->
beforeEach ->
user = newUser()
user.dailys = [
shared.taskDefaults({type:'daily', startDate: moment().add(7, 'days'), frequency: 'daily'})
shared.taskDefaults({type:'daily', startDate: moment().add(7, 'days'), frequency: 'weekly', repeat: {su:1,m:1,t:1,w:1,th:1,f:1,s:1}})
]
daily = user.dailys[0]
weekly = user.dailys[1]
it 'does not damage user for not completing it', ->
cron(user)
expect(user.stats.hp).to.be 50
it 'does not change value on cron if daily is incomplete', ->
cron(user)
expect(daily.value).to.be 0
expect(weekly.value).to.be 0
it 'does not reset checklists if daily is not marked as complete', ->
checklist = [
{
'text' : '1',
'id' : 'checklist-one',
'completed' : true
},
{
'text' : '2',
'id' : 'checklist-two',
'completed' : true
},
{
'text' : '3',
'id' : 'checklist-three',
'completed' : false
}
]
daily.checklist = checklist
weekly.checklist = checklist
cron(user)
expect(daily.checklist[0].completed).to.be true
expect(daily.checklist[1].completed).to.be true
expect(daily.checklist[2].completed).to.be false
expect(weekly.checklist[0].completed).to.be true
expect(weekly.checklist[1].completed).to.be true
expect(weekly.checklist[2].completed).to.be false
it 'resets checklists if daily is marked as complete', ->
checklist = [
{
'text' : '1',
'id' : 'checklist-one',
'completed' : true
},
{
'text' : '2',
'id' : 'checklist-two',
'completed' : true
},
{
'text' : '3',
'id' : 'checklist-three',
'completed' : false
}
]
daily.checklist = checklist
weekly.checklist = checklist
daily.completed = true
weekly.completed = true
cron(user)
_.each daily.checklist, (box)->
expect(box.completed).to.be false
_.each weekly.checklist, (box)->
expect(box.completed).to.be false
it 'is due on startDate', ->
daily_due_today = shared.shouldDo moment(), daily
daily_due_on_start_date = shared.shouldDo moment().add(7, 'days'), daily
expect(daily_due_today).to.be false
expect(daily_due_on_start_date).to.be true
weekly_due_today = shared.shouldDo moment(), weekly
weekly_due_on_start_date = shared.shouldDo moment().add(7, 'days'), weekly
expect(weekly_due_today).to.be false
expect(weekly_due_on_start_date).to.be true
describe 'when startDate is in the past', ->
completeDaily = null
beforeEach ->
user = newUser()
user.dailys = [
shared.taskDefaults({type:'daily', startDate: moment().subtract(7, 'days'), frequency: 'daily'})
shared.taskDefaults({type:'daily', startDate: moment().subtract(7, 'days'), frequency: 'weekly'})
]
daily = user.dailys[0]
weekly = user.dailys[1]
it 'does damage user for not completing it', ->
cron(user)
expect(user.stats.hp).to.be.lessThan 50
it 'decreases value on cron if daily is incomplete', ->
cron(user)
expect(daily.value).to.be.lessThan 0
expect(weekly.value).to.be.lessThan 0
it 'resets checklists if daily is not marked as complete', ->
checklist = [
{
'text' : '1',
'id' : 'checklist-one',
'completed' : true
},
{
'text' : '2',
'id' : 'checklist-two',
'completed' : true
},
{
'text' : '3',
'id' : 'checklist-three',
'completed' : false
}
]
daily.checklist = checklist
weekly.checklist = checklist
cron(user)
_.each daily.checklist, (box)->
expect(box.completed).to.be false
_.each weekly.checklist, (box)->
expect(box.completed).to.be false
it 'resets checklists if daily is marked as complete', ->
checklist = [
{
'text' : '1',
'id' : 'checklist-one',
'completed' : true
},
{
'text' : '2',
'id' : 'checklist-two',
'completed' : true
},
{
'text' : '3',
'id' : 'checklist-three',
'completed' : false
}
]
daily.checklist = checklist
daily.completed = true
weekly.checklist = checklist
weekly.completed = true
cron(user)
_.each daily.checklist, (box)->
expect(box.completed).to.be false
_.each weekly.checklist, (box)->
expect(box.completed).to.be false
describe 'when startDate is today', ->
completeDaily = null
beforeEach ->
user = newUser()
user.dailys = [
# Must set start date to yesterday, because cron mock sets last cron to yesterday
shared.taskDefaults({type:'daily', startDate: moment().subtract(1, 'days'), frequency: 'daily'})
shared.taskDefaults({type:'daily', startDate: moment().subtract(1, 'days'), frequency: 'weekly'})
]
daily = user.dailys[0]
weekly = user.dailys[1]
it 'does damage user for not completing it', ->
cron(user)
expect(user.stats.hp).to.be.lessThan 50
it 'decreases value on cron if daily is incomplete', ->
cron(user)
expect(daily.value).to.be.lessThan 0
expect(weekly.value).to.be.lessThan 0
it 'resets checklists if daily is not marked as complete', ->
checklist = [
{
'text' : '1',
'id' : 'checklist-one',
'completed' : true
},
{
'text' : '2',
'id' : 'checklist-two',
'completed' : true
},
{
'text' : '3',
'id' : 'checklist-three',
'completed' : false
}
]
daily.checklist = checklist
weekly.checklist = checklist
cron(user)
_.each daily.checklist, (box)->
expect(box.completed).to.be false
_.each weekly.checklist, (box)->
expect(box.completed).to.be false
it 'resets checklists if daily is marked as complete', ->
checklist = [
{
'text' : '1',
'id' : 'checklist-one',
'completed' : true
},
{
'text' : '2',
'id' : 'checklist-two',
'completed' : true
},
{
'text' : '3',
'id' : 'checklist-three',
'completed' : false
}
]
daily.checklist = checklist
daily.completed = true
weekly.checklist = checklist
weekly.completed = true
cron(user)
_.each daily.checklist, (box)->
expect(box.completed).to.be false
_.each weekly.checklist, (box)->
expect(box.completed).to.be false
describe 'daily that repeats every x days', ->
user = null
daily = null
beforeEach ->
user = newUser()
user.dailys = [ shared.taskDefaults({type:'daily', startDate: moment(), frequency: 'daily'}) ]
daily = user.dailys[0]
_.times 11, (due) ->
it 'where x equals ' + due, ->
daily.everyX = due
_.times 30, (day) ->
isDue = shared.shouldDo moment().add(day, 'days'), daily
expect(isDue).to.be true if day % due == 0
expect(isDue).to.be false if day % due != 0

View file

@ -0,0 +1,177 @@
'use strict';
describe('Challenges Controller', function() {
var $rootScope, scope, user, ctrl, challenges, groups;
beforeEach(function() {
module(function($provide) {
$provide.value('User', {});
});
inject(function($rootScope, $controller, Challenges, Groups){
user = specHelper.newUser();
user._id = "unique-user-id";
scope = $rootScope.$new();
// Load RootCtrl to ensure shared behaviors are loaded
$controller('RootCtrl', {$scope: scope, User: {user: user}});
ctrl = $controller('ChallengesCtrl', {$scope: scope, User: {user: user}});
challenges = Challenges;
groups = Groups;
});
});
describe('filterChallenges', function() {
var ownMem, ownNotMem, notOwnMem, notOwnNotMem;
beforeEach(function() {
ownMem = new challenges.Challenge({
name: 'test',
description: 'You are the owner and member',
habits: [],
dailys: [],
todos: [],
rewards: [],
leader: user._id,
group: "test",
timestamp: +(new Date),
members: [user],
official: false,
_isMember: true
});
ownNotMem = new challenges.Challenge({
name: 'test',
description: 'You are the owner, but not a member',
habits: [],
dailys: [],
todos: [],
rewards: [],
leader: user._id,
group: "test",
timestamp: +(new Date),
members: [],
official: false,
_isMember: false
});
notOwnMem = new challenges.Challenge({
name: 'test',
description: 'Not owner but a member',
habits: [],
dailys: [],
todos: [],
rewards: [],
leader: {_id:"test"},
group: "test",
timestamp: +(new Date),
members: [user],
official: false,
_isMember: true
});
notOwnNotMem = new challenges.Challenge({
name: 'test',
description: 'Not owner or member',
habits: [],
dailys: [],
todos: [],
rewards: [],
leader: {_id:"test"},
group: "test",
timestamp: +(new Date),
members: [],
official: false,
_isMember: false
});
scope.search = {
group: _.transform(groups, function(m,g){m[g._id]=true;})
};
});
it('displays challenges that match membership: either and owner: either', function() {
scope.search._isMember = 'either';
scope.search._isOwner = 'either';
expect(scope.filterChallenges(ownMem)).to.eql(true);
expect(scope.filterChallenges(ownNotMem)).to.eql(true);
expect(scope.filterChallenges(notOwnMem)).to.eql(true);
expect(scope.filterChallenges(notOwnNotMem)).to.eql(true);
});
it('displays challenges that match membership: either and owner: true', function() {
scope.search._isMember = 'either';
scope.search._isOwner = true;
expect(scope.filterChallenges(ownMem)).to.eql(true);
expect(scope.filterChallenges(ownNotMem)).to.eql(true);
expect(scope.filterChallenges(notOwnMem)).to.eql(false);
expect(scope.filterChallenges(notOwnNotMem)).to.eql(false);
});
it('displays challenges that match membership: either and owner: false', function() {
scope.search._isMember = 'either';
scope.search._isOwner = false;
expect(scope.filterChallenges(ownMem)).to.eql(false);
expect(scope.filterChallenges(ownNotMem)).to.eql(false);
expect(scope.filterChallenges(notOwnMem)).to.eql(true);
expect(scope.filterChallenges(notOwnNotMem)).to.eql(true);
});
it('displays challenges that match membership: true and owner: either', function() {
scope.search._isMember = true;
scope.search._isOwner = 'either';
expect(scope.filterChallenges(ownMem)).to.eql(true);
expect(scope.filterChallenges(ownNotMem)).to.eql(false);
expect(scope.filterChallenges(notOwnMem)).to.eql(true);
expect(scope.filterChallenges(notOwnNotMem)).to.eql(false);
});
it('displays challenges that match membership: true and owner: true', function() {
scope.search._isMember = true;
scope.search._isOwner = true;
expect(scope.filterChallenges(ownMem)).to.eql(true);
expect(scope.filterChallenges(ownNotMem)).to.eql(false);
expect(scope.filterChallenges(notOwnMem)).to.eql(false);
expect(scope.filterChallenges(notOwnNotMem)).to.eql(false);
});
it('displays challenges that match membership: true and owner: false', function() {
scope.search._isMember = true;
scope.search._isOwner = false;
expect(scope.filterChallenges(ownMem)).to.eql(false);
expect(scope.filterChallenges(ownNotMem)).to.eql(false);
expect(scope.filterChallenges(notOwnMem)).to.eql(true);
expect(scope.filterChallenges(notOwnNotMem)).to.eql(false);
});
it('displays challenges that match membership: false and owner: either', function() {
scope.search._isMember = false;
scope.search._isOwner = 'either';
expect(scope.filterChallenges(ownMem)).to.eql(false);
expect(scope.filterChallenges(ownNotMem)).to.eql(true);
expect(scope.filterChallenges(notOwnMem)).to.eql(false);
expect(scope.filterChallenges(notOwnNotMem)).to.eql(true);
});
it('displays challenges that match membership: false and owner: true', function() {
scope.search._isMember = false;
scope.search._isOwner = true;
expect(scope.filterChallenges(ownMem)).to.eql(false);
expect(scope.filterChallenges(ownNotMem)).to.eql(true);
expect(scope.filterChallenges(notOwnMem)).to.eql(false);
expect(scope.filterChallenges(notOwnNotMem)).to.eql(false);
});
it('displays challenges that match membership: false and owner: false', function() {
scope.search._isMember = false;
scope.search._isOwner = false;
expect(scope.filterChallenges(ownMem)).to.eql(false);
expect(scope.filterChallenges(ownNotMem)).to.eql(false);
expect(scope.filterChallenges(notOwnMem)).to.eql(false);
expect(scope.filterChallenges(notOwnNotMem)).to.eql(true);
});
});
});

View file

@ -0,0 +1,39 @@
'use strict';
describe('Filters Controller', function() {
var scope, user;
beforeEach(inject(function($rootScope, $controller, Shared) {
user = specHelper.newUser();
Shared.wrap(user);
scope = $rootScope.$new();
$controller('FiltersCtrl', {$scope: scope, User: {user: user}});
}));
describe('tags', function(){
it('creates a tag', function(){
scope._newTag = {name:'tagName'}
scope.createTag();
expect(user.tags).to.have.length(1);
expect(user.tags[0].name).to.eql('tagName');
expect(user.tags[0]).to.have.property('id');
});
it('toggles tag filtering', inject(function(Shared){
var tag = {id: Shared.uuid(), name: 'myTag'};
scope.toggleFilter(tag);
expect(user.filters[tag.id]).to.eql(true);
scope.toggleFilter(tag);
expect(user.filters[tag.id]).to.eql(false);
}));
});
describe('updateTaskFilter', function(){
it('updatest user\'s filter query with the value of filterQuery', function () {
scope.filterQuery = 'task';
scope.updateTaskFilter();
expect(user.filterQuery).to.eql(scope.filterQuery);
});
});
});

View file

@ -0,0 +1,33 @@
describe('roundLargeNumbers', function() {
beforeEach(module('habitrpg'));
it('returns same number if less than 1000', inject(function(roundLargeNumbersFilter) {
for(var num = 0; num < 1000; num++) {
expect(roundLargeNumbersFilter(num)).to.eql(num);
};
}));
it('truncates number and appends "k" if number is 1000-999999', inject(function(roundLargeNumbersFilter) {
expect(roundLargeNumbersFilter(999.01)).to.eql("1.0k");
expect(roundLargeNumbersFilter(1000)).to.eql("1.0k");
expect(roundLargeNumbersFilter(3284.12)).to.eql("3.3k");
expect(roundLargeNumbersFilter(52983.99)).to.eql("53.0k");
expect(roundLargeNumbersFilter(452983.99)).to.eql("453.0k");
expect(roundLargeNumbersFilter(999999)).to.eql("1000.0k");
}));
it('truncates number and appends "m" if number is 1000000-999999999', inject(function(roundLargeNumbersFilter) {
expect(roundLargeNumbersFilter(999999.01)).to.eql("1.0m");
expect(roundLargeNumbersFilter(1000000)).to.eql("1.0m");
expect(roundLargeNumbersFilter(3284124.12)).to.eql("3.3m");
expect(roundLargeNumbersFilter(52983105.99)).to.eql("53.0m");
expect(roundLargeNumbersFilter(452983410.99)).to.eql("453.0m");
expect(roundLargeNumbersFilter(999999999)).to.eql("1000.0m");
}));
it('truncates number and appends b" if number is greater than 999999999', inject(function(roundLargeNumbersFilter) {
expect(roundLargeNumbersFilter(999999999.01)).to.eql("1.0b");
expect(roundLargeNumbersFilter(1423985738.54)).to.eql("1.4b");
}));
});

View file

@ -0,0 +1,35 @@
describe('filter', function() {
beforeEach(module('habitrpg'));
describe('gold', function() {
it('rounds down decimal values', inject(function(goldFilter) {
expect(goldFilter(10)).to.eql(10);
expect(goldFilter(10.0)).to.eql(10);
expect(goldFilter(10.1)).to.eql(10);
expect(goldFilter(10.2)).to.eql(10);
expect(goldFilter(10.3)).to.eql(10);
expect(goldFilter(10.4)).to.eql(10);
expect(goldFilter(10.5)).to.eql(10);
expect(goldFilter(10.6)).to.eql(10);
expect(goldFilter(10.7)).to.eql(10);
expect(goldFilter(10.8)).to.eql(10);
expect(goldFilter(10.9)).to.eql(10);
expect(goldFilter(11)).to.eql(11);
}));
});
describe('silver', function() {
it('converts decimal value of gold to silver', inject(function(silverFilter) {
expect(silverFilter(10)).to.be.closeTo(0, 1);
expect(silverFilter(10.01)).to.be.closeTo(1, 1);
expect(silverFilter(10.05)).to.be.closeTo(5, 1);
expect(silverFilter(10.17)).to.be.closeTo(17, 1);
expect(silverFilter(10.23)).to.be.closeTo(23, 1);
expect(silverFilter(10.25)).to.be.closeTo(25, 1);
expect(silverFilter(10.53)).to.be.closeTo(53, 1);
expect(silverFilter(10.75)).to.be.closeTo(75, 1);
expect(silverFilter(10.99)).to.be.closeTo(99, 1);
}));
});
});

View file

@ -0,0 +1,54 @@
'use strict';
describe('Task Ordering Filters', function() {
var filter
, orderBySpy = sinon.spy();
beforeEach(function() {
module(function($provide) {
$provide.value('orderByFilter', orderBySpy);
});
inject(function($rootScope, $filter) {
filter = $filter;
});
});
describe('conditionalOrderBy', function() {
describe('when the predicate is true', function() {
it('delegates the arguments to the orderBy filter', function() {
filter('conditionalOrderBy')('array', true, 'sortPredicate', 'reverseOrder');
expect(orderBySpy).to.have.been.calledWith('array','sortPredicate','reverseOrder');
});
});
describe('when the predicate is false', function() {
it('returns the initial array', function() {
expect(filter('conditionalOrderBy')([1,2,3], false)).to.eql([1,2,3]);
});
});
});
describe('filterByTextAndNotes', function () {
it('returns undefined when no input given', function () {
expect(filter('filterByTextAndNotes')()).to.eql(undefined);
});
it('returns input if term is not a string', function () {
var input = [1, 2, 3];
expect(filter('filterByTextAndNotes')(input, '')).to.eql(input);
expect(filter('filterByTextAndNotes')(input, undefined)).to.eql(input);
expect(filter('filterByTextAndNotes')(input, [])).to.eql(input);
expect(filter('filterByTextAndNotes')(input, new Date())).to.eql(input);
});
it('filters items by notes and text', function () {
var tasks = [
{ text: 'foo' },
{ text: 'foo', notes: 'bar' }
];
expect(filter('filterByTextAndNotes')(tasks, 'bar')).to.eql([tasks[1]]);
expect(filter('filterByTextAndNotes')(tasks, 'foo')).to.eql([tasks[0], tasks[1]]);
});
});
});

View file

@ -1,28 +0,0 @@
'use strict';
describe('Filters Controller', function() {
var scope, user;
beforeEach(inject(function($rootScope, $controller, Shared) {
user = specHelper.newUser();
Shared.wrap(user);
scope = $rootScope.$new();
$controller('FiltersCtrl', {$scope: scope, User: {user: user}});
}));
it('creates a tag', function(){
scope._newTag = {name:'tagName'}
scope.createTag();
expect(user.tags).to.have.length(1);
expect(user.tags[0].name).to.eql('tagName');
expect(user.tags[0]).to.have.property('id');
});
it('toggles tag filtering', inject(function(Shared){
var tag = {id: Shared.uuid(), name: 'myTag'};
scope.toggleFilter(tag);
expect(user.filters[tag.id]).to.eql(true);
scope.toggleFilter(tag);
expect(user.filters[tag.id]).to.eql(false);
}))
});

View file

@ -1,30 +0,0 @@
'use strict';
describe('Custom Filters', function() {
var filter
, orderBySpy = sinon.spy();
beforeEach(function() {
module(function($provide) {
$provide.value('orderByFilter', orderBySpy);
});
inject(function($rootScope, $filter) {
filter = $filter;
});
});
describe('conditionalOrderBy', function() {
describe('when the predicate is true', function() {
it('delegates the arguments to the orderBy filter', function() {
filter('conditionalOrderBy')('array', true, 'sortPredicate', 'reverseOrder');
expect(orderBySpy).to.have.been.calledWith('array','sortPredicate','reverseOrder');
});
});
describe('when the predicate is false', function() {
it('returns the initial array', function() {
expect(filter('conditionalOrderBy')([1,2,3], false)).to.eql([1,2,3]);
});
});
});
});

View file

@ -35,3 +35,6 @@
margin-right: 0.618em
@extend $hrpg-button-with-input
hrpg-button-color-mixin($color-options-submenu)
.filters-search
margin-bottom: 0.618em
max-width: 180px

View file

@ -20,7 +20,7 @@ $color-toolbar = lighten($color-herobox, 70%)
$color-options-menu = lighten($color-herobox, 85%)
$color-options-submenu = lighten($color-herobox, 75%)
// Button colors
$color-button-style-one = $best
$color-button-highlight = $best
// Task background
$color-tasks = lighten($color-herobox, 65%)
// Task filter colors
@ -37,4 +37,4 @@ $color-contributor-seven = #00aaff
$color-contributor-mod = #130ead
$color-contributor-staff = #88108f
$color-contributor-npc = #000
$color-contributor-npc-font = #00FF00
$color-contributor-npc-font = #00FF00

View file

@ -13,14 +13,21 @@ hrpg-text-shadow-mixin($hrpg-text-shadow-base-color)
1px 1px 1px darken($hrpg-text-shadow-base-color,70%);
// Buttons
// The !important declarations override Bootstrap
hrpg-button-color-mixin($hrpg-button-color)
// buttons with the .highlight class pass highlight=true to this mixin
hrpg-button-color-mixin($hrpg-button-color, highlight=false)
// this case covers button elements with the highlight class
// like the subscribe button, for which the following selectors do not apply
if highlight==true
border-color: darken($color-button-highlight, 16.18%) !important
background-color: $color-button-highlight !important
&
color: darken($hrpg-button-color, 70%) !important
hrpg-anchor-button-color-mixin($color-button-highlight)
> a, > button
background-color: $hrpg-button-color !important
&:active
background-color: darken($hrpg-button-color, 61.18%) !important
@media screen and (min-width:768px)
&:hover
background-color: darken($hrpg-button-color, 2.36%) !important
if highlight==true
hrpg-anchor-button-color-mixin($color-button-highlight)
else
hrpg-anchor-button-color-mixin($hrpg-button-color)
> a, > button, > input, textarea
color: darken($hrpg-button-color, 70%) !important
border-color: darken($hrpg-button-color, 16.18%) !important
@ -38,6 +45,9 @@ hrpg-button-color-mixin($hrpg-button-color)
&:active
background-color: darken($hrpg-button-color, 16.18%) !important;
> a:nth-of-type(2)
if highlight==true
border-left: 1px solid darken($color-button-highlight, 3.82%) !important
else
border-left: 1px solid darken($hrpg-button-color, 3.82%) !important
> div
@media screen and (min-width:768px)
@ -69,6 +79,13 @@ hrpg-button-color-mixin($hrpg-button-color)
color: #fff !important;
span
color: #fff !important;
hrpg-anchor-button-color-mixin($hrpg-button-color)
background-color: $hrpg-button-color !important
&:active
background-color: darken($hrpg-button-color, 61.18%) !important
@media screen and (min-width:768px)
&:hover
background-color: darken($hrpg-button-color, 2.36%) !important
$hrpg-button-master
list-style: none
> a, > button, > input, label::after
@ -89,9 +106,8 @@ $hrpg-button
> a, > button, > input, label::after
border: 1px solid #ccc !important
border-radius: 0.382em !important
$hrpg-button-call-to-action
@extend $hrpg-button
hrpg-button-color-mixin($color-button-style-one)
.highlight
hrpg-button-color-mixin($color-toolbar, true)
$hrpg-button-toggle
@extend $hrpg-button-master
border: 1px solid #ccc !important
@ -100,6 +116,8 @@ $hrpg-button-toggle
border-radius: 0.382em 0em 0em 0.382em !important
> a:last-of-type
border-radius: 0em 0.382em 0.382em 0em !important
&.highlight
hrpg-button-color-mixin($color-toolbar, true)
// Input + Button
$hrpg-button-with-input
@extend $hrpg-button-master

View file

@ -85,6 +85,9 @@
@extend $hrpg-button-toggle
@extend $hrpg-modal-dropdown-right
hrpg-button-color-mixin($color-toolbar)
&.highlight
> a span.glyphicon
margin-right: 0.382em !important
.toolbar-button
@extend $hrpg-button
hrpg-button-color-mixin($color-toolbar)
@ -163,7 +166,7 @@
@extend $hrpg-button
hrpg-button-color-mixin(lighten($color-toolbar,32.8%))
.toolbar-subscribe-button, .toolbar-controls .toolbar-subscribe-button
@extend $hrpg-button-call-to-action
@extend $hrpg-button
@media screen and (max-width:768px)
.toolbar-toggle
display: none

View file

@ -12,7 +12,7 @@ for $stage in $stages
.color-{$stage[0]}:not(.completed)
background-color: $stage[1]
border: 1px solid shade($stage[1],10%)
.priority-multiplier, .task-attributes, .repeat-days
.priority-multiplier, .task-attributes, .repeat-days, .repeat-frequency
li
hrpg-button-color-mixin($stage[1])
button
@ -63,7 +63,7 @@ for $stage in $stages
color: darken($completed,30%)
background-color: $completed
border: 1px solid shade($completed,10%)
.priority-multiplier, .task-attributes, .repeat-days
.priority-multiplier, .task-attributes, .repeat-days, .repeat-frequency
li
hrpg-button-color-mixin($completed)
button
@ -215,7 +215,6 @@ for $stage in $stages
border: 1px solid #aaa
border-radius: 0.382em
padding-left: 0.618em
background-color: #fff !important
-webkit-appearance: none
-moz-appearance: none
appearance: none
@ -410,6 +409,10 @@ form
padding: 0 0 1em
margin-bottom: 1em
button.advanced-options-toggle
display: block;
width: 100%;
background: none;
.option-title
font-size: 1em
margin: 0.5em 0 0.5em
@ -507,7 +510,7 @@ form
form
padding-bottom: 1em
.priority-multiplier, .task-attributes, .repeat-days
.priority-multiplier, .task-attributes, .repeat-days, .repeat-frequency
text-align: center
li
@extend $hrpg-button
@ -517,6 +520,7 @@ form
&:last-of-type
margin-right: 0
.repeat-days
padding-bottom: 1em
li
button
min-width: 2.5em
@ -524,6 +528,11 @@ form
text-align: center
@extend $hrpg-button
// Dailies
.dailies
.repeat-weekly
padding-bottom: 1em
// Habits task button styles (+ -)
.habits
.task-actions
@ -580,7 +589,7 @@ form
margin-top: 0.5em
span
margin-right: 0.5em
> form
> .checklist-form
li
@extend $hrpg-button-with-input
@extend $clearfix

Binary file not shown.

After

Width:  |  Height:  |  Size: 9 KiB

View file

@ -1,810 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<link href="http://fonts.googleapis.com/css?family=Lato:400,700" rel='stylesheet' type="text/css">
<title>HabitRPG | Gamify Your Life</title>
<meta name="description" content="">
<meta name="keywords" content="">
<meta name="author" content="">
<meta name="geo.placename" content="">
<!--[if IE]><meta http-equiv="imagetoolbar" content="no" /><![endif]-->
<meta name="viewport" content="width=device-width, maximum-scale=1" />
<meta property="og:title" content="" />
<meta property="og:description" content="" />
<meta property="og:url" content="" />
<meta property="og:image" content="" />
<meta property="og:site_name" content="" />
<link rel="canonical" href="" type="text/html" />
<link rel="sitemap" type="application/xml" title="Sitemap" href="/sitemap.xml" />
<link rel="shortcut icon" href="/images/favicon.png" />
<link rel="apple-touch-icon" href="/images/apple-touch-icon.png" />
<!--[if lt IE 9]>
<script src="//html5shim.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="css/bootstrap.min.css">
<!--Custom CSS-->
<link rel="stylesheet" type="text/css" href="style.css" />
<!-- Latest compiled and minified JavaScript -->
<script src="js/bootstrap.min.js"></script>
</head>
<body>
<header id="header">
<nav class="navbar navbar-default navbar-static-top">
<div class="container-fluid">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#"><img src="images/icon175x175.png" />
<img src="images/habitrpg_pixel.png" /></a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav nav-pills navbar-right">
<li><a href="/howitworks">How it works</a></li>
<li><a href="/enterprise">Corporate plans</a></li>
<li><a href="/about">About us</a></li>
<li><a href="http://blog.habitrpg.com/">Blog</a></li>
<li><a href="">Press Kit</a></li>
<li><a href="/contact">Contact us</a></li>
<li><button id="header-play-button" class="btn btn-primary navbar-btn navbar-right">Play HabitRPG</button></li>
</ul>
</div>
</div>
</nav>
</header>
<div id="intro">
<h1>Motivate yourself and your team!</h1>
<img class="text-center" src="images/intro.jpg" /><!--insert intro images-->
<div class="introcall bg-success">
<h4>Join 200,000 players making it fun to achieve goals!
<small><button class="btn btn-primary gamifybutton">Play for free</button></small>
</h4>
</div>
<div class="presslogos text-center">Featured in<br/>
<img src="images/presslogos/lifehacker.png" />
<img src="images/presslogos/nyt-logo.png" />
<img src="images/presslogos/makeuseof.png" />
<img src="images/presslogos/Forbes_logo.png" />
<img src="images/presslogos/Cnetlogo.png" />
<img src="images/presslogos/Fast-Company-logo.png" />
<img src="images/presslogos/kickstarter-logo.png" />
</div>
</div>
<div id="intro-text" class="container-fluid">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<p class="lead text-center">HabitRPG is a free habit building and productivity app that treats your real life like a game. With in-game rewards and punishments to motivate you and a strong social network to inspire you, HabitRPG can help you achieve your goals to become healthy, hard-working, and happy. </p>
</div></div></div>
<section id="testimonial-carousel" class="bg-info">
<div class="container-fluid">
<div class="row">
<div class="col-md-3 col-md-offset-1">
<h2>What people say...</h2><br/>
<img class="img-say img-responsive" src="images/uses/publicSpaces.png"/>
</div>
<!--Testimonials-->
<div class="col-md-8">
<div class="carousel slide" data-interval="4000" data-ride="carousel" id="quote-carousel">
<!-- Bottom Carousel Indicators -->
<ol class="carousel-indicators">
<li data-target="#quote-carousel" data-slide-to="0" class="active"><img class="img-responsive " src="images/testimonials/Drag0nsilver.png" alt=""></li>
<li data-target="#quote-carousel" data-slide-to="1"><img class="img-responsive " src="images/testimonials/frabjabulous.png" alt=""></li>
<li data-target="#quote-carousel" data-slide-to="2"><img class="img-responsive " src="images/testimonials/AndeeLiao.png" alt=""></li>
<li data-target="#quote-carousel" data-slide-to="3"><img class="img-responsive " src="images/testimonials/AlexandraSo.png" alt=""></li>
</ol>
<!-- Carousel Slides / Quotes -->
<div class="carousel-inner text-center">
<!-- Quote 1 -->
<div class="item active">
<blockquote>
<div class="row">
<div class="col-sm-8 col-sm-offset-2"><p>I can't tell you how many time and task tracking systems I've tried over the decades... HRPG is the only thing I've used that actually helps me get things done rather than just list them.</p>
<small>Drag0nsilver</small>
</div>
</div>
</blockquote>
</div>
<!-- Quote 2 -->
<div class="item">
<blockquote>
<div class="row">
<div class="col-sm-8 col-sm-offset-2">
<p>HabitRPG is the reason I got a killer, high-paying job... and even more miraculous, I'm now a daily flosser!</p>
<small>frabjabulous</small>
</div>
</div>
</blockquote>
</div>
<!-- Quote 3 -->
<div class="item">
<blockquote>
<div class="row">
<div class="col-sm-8 col-sm-offset-2">
<p>Awesome product, just started a few days ago and already more conscious and productive with my time!</p>
<small>AndeeLiao</small>
</div>
</div>
</blockquote>
</div>
<div class="item">
<blockquote>
<div class="row">
<div class="col-sm-8 col-sm-offset-2">
<p>Couldn't NOT talk about HabitRPG during my speech in Madrid. Must-have tool for freelancers who still need a boss.</p>
<small>_AlexandraSo_</small>
</div>
</div>
</blockquote>
</div>
</div>
<!-- Carousel Buttons Next/Prev -->
<a data-slide="prev" href="#quote-carousel" class="left carousel-control"><i class="fa fa-chevron-left"></i></a>
<a data-slide="next" href="#quote-carousel" class="right carousel-control"><i class="fa fa-chevron-right"></i></a>
</div>
</div>
</div>
</div>
</section>
<section id="uses">
<h2>Players use HabitRPG to manage...</h2>
<div class="container">
<div id="myCarousel" class="carousel slide" data-ride="carousel">
<ul class="nav nav-pills nav-justified">
<li data-target="#myCarousel" data-slide-to="0" class="active"><a href="#">Work</a></li>
<li data-target="#myCarousel" data-slide-to="1"><a href="#">Health</a></li>
<li data-target="#myCarousel" data-slide-to="2"><a href="#">Teams</a></li>
<li data-target="#myCarousel" data-slide-to="3"><a href="#">School</a></li>
<li data-target="#myCarousel" data-slide-to="4"><a href="#">Goals</a></li>
<li data-target="#myCarousel" data-slide-to="5"><a href="#">Chores</a></li>
</ul>
<!-- Wrapper for slides -->
<div class="carousel-inner" style="z-index:0;">
<div class="item active work-use">
<h3>Work<br/><small><a href="/business.html">Use HabitRPG at your business</a></small></h3>
<div class="carousel-content">
<div class="sampletasks">
<h4>Sample Habits</h4>
<div style="width:19em; background-color: rgb(252, 229, 205); color: rgb(51, 51, 51); text-align:center; padding: 0px; font-size: 1.41em; line-height: 1.62765; list-style: none outside none; padding: 0px; height: 2.3em; min-height: 1.62765em; margin-bottom:0.75em; margin:0px; box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.5) inset;">
<div style="display: inline-block; width: 1.62765em; height: 1.62765em; padding: 0px; margin:0px; font-size: 1.41em; line-height: 1.62765; text-align: center; color: rgb(34, 34, 34); float:left; cursor: pointer; vertical-align: top; left:0px; position:relative; background-color: rgb(219, 120, 66); border-right: 1px solid rgba(0, 0, 0, 0.25);">+</div>&#160;<div style="display: inline-block; font-family: Lato,sans-serif; padding: 0.6em 0px 0em 1em; font-size: .8em; letter-spacing: normal; float:left; word-wrap: break-word;">Confirm 1 page of Inventory</div></div><br />
<div style="width:19em; background-color: rgb(201, 218, 248); color: rgb(51, 51, 51); text-align:center; padding: 0px; font-size: 1.41em; line-height: 1.62765; list-style: none outside none; padding: 0px; height: 2.3em; min-height: 1.62765em; margin-bottom:0.75em; margin:0px; box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.5) inset;">
<div style="display: inline-block; width: 1.62765em; height: 1.62765em; padding: 0px; margin:0px; font-size: 1.41em; line-height: 1.62765; text-align: center; color: rgb(34, 34, 34); float:left; cursor: pointer; vertical-align: top; left:0px; position:relative; background-color: rgb(90, 98, 223); border-right: 1px solid rgba(0, 0, 0, 0.25);">+</div>&#160;<div style="display: inline-block; font-family: Lato,sans-serif; padding: 0.6em 0px 0em 1em; font-size: .8em; letter-spacing: normal; float:left; word-wrap: break-word;">20 mins Filing</div></div><br />
<div style="width:19em; background-color: #d9ead3; color: rgb(51, 51, 51); text-align:center; padding: 0px; font-size: 1.41em; line-height: 1.62765; list-style: none outside none; padding: 0px; height: 2.3em; min-height: 1.62765em; margin-bottom:0.75em; margin:0px; box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.5) inset;">
<div style="display: inline-block; width: 1.62765em; height: 1.62765em; padding: 0px; margin:0px; font-size: 1.41em; line-height: 1.62765; text-align: center; color: rgb(34, 34, 34); float:left; cursor: pointer; vertical-align: top; left:0px; position:relative; background-color: rgb(113, 176, 91); border-right: 1px solid rgba(0, 0, 0, 0.25);">+</div>&#160;<div style="display: inline-block; font-family: Lato,sans-serif; padding: 0.6em 0px 0em 1em; font-size: .8em; letter-spacing: normal; float:left; word-wrap: break-word;">Sort and Process Inbox</div></div><br />
<div style="width:19em; background-color: rgb(255, 242, 204); color: rgb(51, 51, 51); text-align:center; padding: 0px; font-size: 1.41em; line-height: 1.62765; list-style: none outside none; padding: 0px; height: 2.3em; min-height: 1.62765em; margin-bottom:0.75em; margin:0px; box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.5) inset;">
<div style="display: inline-block; width: 1.62765em; height: 1.62765em; padding: 0px; margin:0px; font-size: 1.41em; line-height: 1.62765; text-align: center; color: rgb(34, 34, 34); float:left; cursor: pointer; vertical-align: top; left:0px; position:relative; background-color: rgb(255, 207, 66); border-right: 1px solid rgba(0, 0, 0, 0.25);">+</div>&#160;<div style="display: inline-block; font-family: Lato,sans-serif; padding: 0.6em 0px 0em 1em; font-size: .8em; letter-spacing: normal; float:left; word-wrap: break-word;">Prepare 1 Document for Client</div></div><br />
<div style="width:19em; background-color: rgb(244, 204, 204); color: rgb(51, 51, 51); text-align:center; padding: 0px; font-size: 1.41em; line-height: 1.62765; list-style: none outside none; padding: 0px; height: 2.3em; min-height: 1.62765em; margin-bottom:0.75em; margin:0px; box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.5) inset;">
<div style="display: inline-block; width: 1.62765em; height: 1.62765em; padding: 0px; margin:0px; font-size: 1.41em; line-height: 1.62765; text-align: center; color: rgb(34, 34, 34); float:left; cursor: pointer; vertical-align: top; left:0px; position:relative; background-color: rgb(220, 93, 93); border-right: 1px solid rgba(0, 0, 0, 0.25);">+</div><div style="display: inline-block; width: 1.62765em; height: 1.62765em; padding: 0px; margin:0px; font-size: 1.41em; line-height: 1.62765; text-align: center; color: rgb(34, 34, 34); float:left; cursor: pointer; vertical-align: top; background-color: rgb(220, 93, 93); border-right: 0px none;">-</div><div style="display: inline-block; font-family: Lato,sans-serif; padding: 0.6em 0px 0em 1em; font-size: .8em; letter-spacing: normal; float:left; word-wrap: break-word;">Call Clients/Put Off Phone Calls</div></div>
</div>
<img class="sample-img" src="images/uses/coding.png" />
<div class="usetweet-groups">
<div class="usetweet-group">
<img data-toggle="tooltip" data-placement="top" title="frabjabulous" src="images/testimonials/frabjabulous.png">
<div class="usetweet tweet popover right">
<div class="arrow"></div>
<div class="popover-content">HabitRPG is the reason I got a killer, high-paying job... and even more miraculous, I'm now a daily flosser</div>
</div>
</div>
<div class="usetweet-group">
<img data-toggle="tooltip" data-placement="top" title="_AlexandraSo_" src="images/testimonials/AlexandraSo.png">
<div class="usetweet tweet popover right">
<div class="arrow"></div>
<div class="popover-content">Couldn't NOT talk about HabitRPG during my speech in Madrid. Must-have tool for freelancers who still need a boss.</div>
</div>
</div>
</div>
</div>
</div><!--End item-->
<div class="item health-use">
<h3>Health</h3>
<div class="carousel-content">
<div class="sampletasks">
<h4>Sample Habits</h4>
<div style="width:19em; background-color: #d9ead3; color: rgb(51, 51, 51); text-align:center; padding: 0px; font-size: 1.41em; line-height: 1.62765; list-style: none outside none; padding: 0px; height: 2.3em; min-height: 1.62765em; margin-bottom:0.75em; margin:0px; box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.5) inset;">
<div style="display: inline-block; width: 1.62765em; height: 1.62765em; padding: 0px; margin:0px; font-size: 1.41em; line-height: 1.62765; text-align: center; color: rgb(34, 34, 34); float:left; cursor: pointer; vertical-align: top; left:0px; position:relative; background-color: rgb(113, 176, 91); border-right: 1px solid rgba(0, 0, 0, 0.25);">+</div><div style="display: inline-block; width: 1.62765em; height: 1.62765em; padding: 0px; margin:0px; font-size: 1.41em; line-height: 1.62765; text-align: center; color: rgb(34, 34, 34); float:left; cursor: pointer; vertical-align: top; background-color: rgb(113, 176, 91); border-right: 0px none;">-</div><div style="display: inline-block; font-family: Lato,sans-serif; padding: 0.6em 0px 0em 1em; font-size: .8em; letter-spacing: normal; float:left; word-wrap: break-word;">Drink Water/Soda</div></div><br />
<div style="width:19em; background-color: rgb(244, 204, 204); color: rgb(51, 51, 51); text-align:center; padding: 0px; font-size: 1.41em; line-height: 1.62765; list-style: none outside none; padding: 0px; height: 2.3em; min-height: 1.62765em; margin-bottom:0.75em; margin:0px; box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.5) inset;">
<div style="display: inline-block; width: 1.62765em; height: 1.62765em; padding: 0px; margin:0px; font-size: 1.41em; line-height: 1.62765; text-align: center; color: rgb(34, 34, 34); float:left; cursor: pointer; vertical-align: top; left:0px; position:relative; background-color: rgb(220, 93, 93); border-right: 1px solid rgba(0, 0, 0, 0.25);">+</div><div style="display: inline-block; width: 1.62765em; height: 1.62765em; padding: 0px; margin:0px; font-size: 1.41em; line-height: 1.62765; text-align: center; color: rgb(34, 34, 34); float:left; cursor: pointer; vertical-align: top; background-color: rgb(220, 93, 93); border-right: 0px none;">-</div><div style="display: inline-block; font-family: Lato,sans-serif; padding: 0.6em 0px 0em 1em; font-size: .8em; letter-spacing: normal; float:left; word-wrap: break-word;">Chew Gum/Smoke</div></div><br />
<div style="width:19em; background-color: #d9ead3; color: rgb(51, 51, 51); text-align:center; padding: 0px; font-size: 1.41em; line-height: 1.62765; list-style: none outside none; padding: 0px; height: 2.3em; min-height: 1.62765em; margin-bottom:0.75em; margin:0px; box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.5) inset;">
<div style="display: inline-block; width: 1.62765em; height: 1.62765em; padding: 0px; margin:0px; font-size: 1.41em; line-height: 1.62765; text-align: center; color: rgb(34, 34, 34); float:left; cursor: pointer; vertical-align: top; left:0px; position:relative; background-color: rgb(113, 176, 91); border-right: 1px solid rgba(0, 0, 0, 0.25);">+</div><div style="display: inline-block; width: 1.62765em; height: 1.62765em; padding: 0px; margin:0px; font-size: 1.41em; line-height: 1.62765; text-align: center; color: rgb(34, 34, 34); float:left; cursor: pointer; vertical-align: top; background-color: rgb(113, 176, 91); border-right: 0px none;">-</div><div style="display: inline-block; font-family: Lato,sans-serif; padding: 0.6em 0px 0em 1em; font-size: .8em; letter-spacing: normal; float:left; word-wrap: break-word;">Take Stairs/Elevator</div></div><br />
<div style="width:19em; background-color: rgb(255, 242, 204); color: rgb(51, 51, 51); text-align:center; padding: 0px; font-size: 1.41em; line-height: 1.62765; list-style: none outside none; padding: 0px; height: 2.3em; min-height: 1.62765em; margin-bottom:0.75em; margin:0px; box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.5) inset;">
<div style="display: inline-block; width: 1.62765em; height: 1.62765em; padding: 0px; margin:0px; font-size: 1.41em; line-height: 1.62765; text-align: center; color: rgb(34, 34, 34); float:left; cursor: pointer; vertical-align: top; left:0px; position:relative; background-color: rgb(255, 207, 66); border-right: 1px solid rgba(0, 0, 0, 0.25);">+</div><div style="display: inline-block; width: 1.62765em; height: 1.62765em; padding: 0px; margin:0px; font-size: 1.41em; line-height: 1.62765; text-align: center; color: rgb(34, 34, 34); float:left; cursor: pointer; vertical-align: top; background-color: rgb(255, 207, 66); border-right: 0px none;">-</div><div style="display: inline-block; font-family: Lato,sans-serif; padding: 0.6em 0px 0em 1em; font-size: .8em; letter-spacing: normal; float:left; word-wrap: break-word;">Eat Healthy/Junk Food</div></div><br />
<div style="width:19em; background-color: rgb(255, 242, 204); color: rgb(51, 51, 51); text-align:center; padding: 0px; font-size: 1.41em; line-height: 1.62765; list-style: none outside none; padding: 0px; height: 2.3em; min-height: 1.62765em; margin-bottom:0.75em; margin:0px; box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.5) inset;">
<div style="display: inline-block; width: 1.62765em; height: 1.62765em; padding: 0px; margin:0px; font-size: 1.41em; line-height: 1.62765; text-align: center; color: rgb(34, 34, 34); float:left; cursor: pointer; vertical-align: top; left:0px; position:relative; background-color: rgb(255, 207, 66); border-right: 1px solid rgba(0, 0, 0, 0.25);">+</div>&#160;<div style="display: inline-block; font-family: Lato,sans-serif; padding: 0.6em 0px 0em 1em; font-size: .8em; letter-spacing: normal; float:left; word-wrap: break-word;">Break a Sweat for 1 hr</div></div>
</div>
<img class="sample-img" src="images/uses/clipart-rosemonkeyct-meditation.png" />
<div class="usetweet-group">
<div class="usetweet tweet popover right">
<div class="arrow"></div>
<div class="popover-content"><a href="https://twitter.com/mwkelley/status/484390723585064960">The only reason I'm remembering to floss this week is because a sea serpent is attacking the tavern in @HabitRPG and that's weird but cool.</a></div>
</div>
<div class="usetweet tweet popover right">
<div class="arrow"></div>
<div class="popover-content"><a href="https://twitter.com/Myg/status/514095570936688641">Don't laugh, but I'm playing http://Habitrpg.com and it's making me walk around the house saying things like, "What vegetable can I eat?"</a></div>
</div>
</div>
</div>
</div>
<!-- End Item -->
<div class="item team-use">
<h3>Teams</h3>
<div class="carousel-content">
<div class="sampletasks">
<h4>Sample To-Dos</h4>
<div style="width:19em; background-color: rgb(252, 229, 205); color: rgb(51, 51, 51); text-align:center; padding: 0px; font-size: 1.41em; line-height: 1.62765; list-style: none outside none; padding: 0px; height: 2.3em; min-height: 1.62765em; margin-bottom:0.75em; margin:0px; box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.5) inset;">
<div style="display: inline-block; width: 1.62765em; height: 1.62765em; padding: 0px; margin:0px; font-size: 1.41em; line-height: 1.62765; text-align: center; color: rgb(34, 34, 34); float:left; cursor: pointer; vertical-align: top; left:0px; position:relative; background-color: rgb(219, 120, 66); border-right: 1px solid rgba(0, 0, 0, 0.25);"><span style="padding: 0.5em 0px 0em 0em; font-size: .8em; color: #666;"></span></div>&#160;<div style="display: inline-block; font-family: Lato,sans-serif; padding: 0.6em 0px 0em 1em; font-size: .8em; letter-spacing: normal; float:left; word-wrap: break-word;">Outline Meeting Itinerary for Tuesday</div></div><br />
<div style="width:19em; background-color: rgb(255, 242, 204); color: rgb(51, 51, 51); text-align:center; padding: 0px; font-size: 1.41em; line-height: 1.62765; list-style: none outside none; padding: 0px; height: 2.3em; min-height: 1.62765em; margin-bottom:0.75em; margin:0px; box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.5) inset;">
<div style="display: inline-block; width: 1.62765em; height: 1.62765em; padding: 0px; margin:0px; font-size: 1.41em; line-height: 1.62765; text-align: center; color: rgb(34, 34, 34); float:left; cursor: pointer; vertical-align: top; left:0px; position:relative; background-color: rgb(255, 207, 66); border-right: 1px solid rgba(0, 0, 0, 0.25);"><span style="padding: 0.5em 0px 0em 0em; font-size: .8em; color: #666;"></span></div>&#160;<div style="display: inline-block; font-family: Lato,sans-serif; padding: 0.6em 0px 0em 1em; font-size: .8em; letter-spacing: normal; float:left; word-wrap: break-word;">Brainstorm Growth Hacking</div></div><br />
<div style="width:19em; background-color: rgb(244, 204, 204); color: rgb(51, 51, 51); text-align:center; padding: 0px; font-size: 1.41em; line-height: 1.62765; list-style: none outside none; padding: 0px; height: 2.3em; min-height: 1.62765em; margin-bottom:0.75em; margin:0px; box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.5) inset;">
<div style="display: inline-block; width: 1.62765em; height: 1.62765em; padding: 0px; margin:0px; font-size: 1.41em; line-height: 1.62765; text-align: center; color: rgb(34, 34, 34); float:left; cursor: pointer; vertical-align: top; left:0px; position:relative; background-color: rgb(220, 93, 93); border-right: 1px solid rgba(0, 0, 0, 0.25);"><span style="padding: 0.5em 0px 0em 0em; font-size: .8em; color: #666;"></span></div>&#160;<div style="display: inline-block; font-family: Lato,sans-serif; padding: 0.6em 0px 0em 1em; font-size: .8em; letter-spacing: normal; float:left; word-wrap: break-word;">Discuss this weeks KPIs</div></div><br />
</div>
<img class="sample-img" src="images/uses/publicSpaces.png" />
<div class="usetweet-group">
<div class="usetweet tweet popover right">
<div class="arrow"></div>
<div class="popover-content"><a href="https://twitter.com/tessa_racked/status/488024741278543872">HabitRPG! Because I won't do yoga and practice Spanish for their own benefits, but I will to get a giant mantis shrimp mount for my avatar.</a></div>
</div>
<div class="usetweet tweet popover right">
<div class="arrow"></div>
<div class="popover-content"><a href="https://twitter.com/kristenrapp/status/522771210602807296">Without @habitrpg I don't think I would have finished my novel draft.</a></div>
</div>
</div>
</div>
</div>
<!-- End Item -->
<div class="item school-use">
<h3>School</h3>
<div class="carousel-content">
<div class="sampletasks">
<h4>Sample Habits</h4>
<div style="width:19em; background-color: rgb(255, 242, 204); color: rgb(51, 51, 51); text-align:center; padding: 0px; font-size: 1.41em; line-height: 1.62765; list-style: none outside none; padding: 0px; height: 2.3em; min-height: 1.62765em; margin-bottom:0.75em; margin:0px; box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.5) inset;">
<div style="display: inline-block; width: 1.62765em; height: 1.62765em; padding: 0px; margin:0px; font-size: 1.41em; line-height: 1.62765; text-align: center; color: rgb(34, 34, 34); float:left; cursor: pointer; vertical-align: top; left:0px; position:relative; background-color: rgb(255, 207, 66); border-right: 1px solid rgba(0, 0, 0, 0.25);">+</div>&#160;<div style="display: inline-block; font-family: Lato,sans-serif; padding: 0.6em 0px 0em 1em; font-size: .8em; letter-spacing: normal; float:left; word-wrap: break-word;">Finish 1 Assignment</div></div><br />
<div style="width:19em; background-color: #d9ead3; color: rgb(51, 51, 51); text-align:center; padding: 0px; font-size: 1.41em; line-height: 1.62765; list-style: none outside none; padding: 0px; height: 2.3em; min-height: 1.62765em; margin-bottom:0.75em; margin:0px; box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.5) inset;">
<div style="display: inline-block; width: 1.62765em; height: 1.62765em; padding: 0px; margin:0px; font-size: 1.41em; line-height: 1.62765; text-align: center; color: rgb(34, 34, 34); float:left; cursor: pointer; vertical-align: top; left:0px; position:relative; background-color: rgb(113, 176, 91); border-right: 1px solid rgba(0, 0, 0, 0.25);">+</div>&#160;<div style="display: inline-block; font-family: Lato,sans-serif; padding: 0.6em 0px 0em 1em; font-size: .8em; letter-spacing: normal; float:left; word-wrap: break-word;">Study 1 hour </div></div><br />
<div style="width:19em; background-color: rgb(255, 242, 204); color: rgb(51, 51, 51); text-align:center; padding: 0px; font-size: 1.41em; line-height: 1.62765; list-style: none outside none; padding: 0px; height: 2.3em; min-height: 1.62765em; margin-bottom:0.75em; margin:0px; box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.5) inset;">
<div style="display: inline-block; width: 1.62765em; height: 1.62765em; padding: 0px; margin:0px; font-size: 1.41em; line-height: 1.62765; text-align: center; color: rgb(34, 34, 34); float:left; cursor: pointer; vertical-align: top; left:0px; position:relative; background-color: rgb(255, 207, 66); border-right: 1px solid rgba(0, 0, 0, 0.25);">+</div>&#160;<div style="display: inline-block; font-family: Lato,sans-serif; padding: 0.6em 0px 0em 1em; font-size: .8em; letter-spacing: normal; float:left; word-wrap: break-word;">Meet with Study Group</div></div><br />
<div style="width:19em; background-color: rgb(244, 204, 204); color: rgb(51, 51, 51); text-align:center; padding: 0px; font-size: 1.41em; line-height: 1.62765; list-style: none outside none; padding: 0px; height: 2.3em; min-height: 1.62765em; margin-bottom:0.75em; margin:0px; box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.5) inset;">
<div style="display: inline-block; width: 1.62765em; height: 1.62765em; padding: 0px; margin:0px; font-size: 1.41em; line-height: 1.62765; text-align: center; color: rgb(34, 34, 34); float:left; cursor: pointer; vertical-align: top; left:0px; position:relative; background-color: rgb(220, 93, 93); border-right: 1px solid rgba(0, 0, 0, 0.25);">+</div><div style="display: inline-block; width: 1.62765em; height: 1.62765em; padding: 0px; margin:0px; font-size: 1.41em; line-height: 1.62765; text-align: center; color: rgb(34, 34, 34); float:left; cursor: pointer; vertical-align: top; background-color: rgb(220, 93, 93); border-right: 0px none;">-</div><div style="display: inline-block; font-family: Lato,sans-serif; padding: 0.6em 0px 0em 1em; font-size: .8em; letter-spacing: normal; float:left; word-wrap: break-word;">Notes for 1 Chapter</div></div><br />
<div style="width:19em; background-color: rgb(201, 218, 248); color: rgb(51, 51, 51); text-align:center; padding: 0px; font-size: 1.41em; line-height: 1.62765; list-style: none outside none; padding: 0px; height: 2.3em; min-height: 1.62765em; margin-bottom:0.75em; margin:0px; box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.5) inset;">
<div style="display: inline-block; width: 1.62765em; height: 1.62765em; padding: 0px; margin:0px; font-size: 1.41em; line-height: 1.62765; text-align: center; color: rgb(34, 34, 34); float:left; cursor: pointer; vertical-align: top; left:0px; position:relative; background-color: rgb(90, 98, 223); border-right: 1px solid rgba(0, 0, 0, 0.25);">+</div><div style="display: inline-block; width: 1.62765em; height: 1.62765em; padding: 0px; margin:0px; font-size: 1.41em; line-height: 1.62765; text-align: center; color: rgb(34, 34, 34); float:left; cursor: pointer; vertical-align: top; background-color: rgb(90, 98, 223); border-right: 0px none;">-</div><div style="display: inline-block; font-family: Lato,sans-serif; padding: 0.6em 0px 0em 1em; font-size: .8em; letter-spacing: normal; float:left; word-wrap: break-word;">Read 1 Chapter</div></div>
</div>
<img class="sample-img" src="images/uses/reading.png" />
<div class="usetweet-group">
<div class="usetweet tweet popover right">
<div class="arrow"></div>
<div class="popover-content"><a href="https://twitter.com/alteriego/status/481560395048427520">My nerdiest venture yet: Using @habitrpg to gamify my to-do list. Because my thesis isn't gonna write itself</a></div>
</div>
<div class="usetweet tweet popover right">
<div class="arrow"></div>
<div class="popover-content"><a href="https://twitter.com/NightBlogger2/status/512040760250605568">Full-time graduate student and part-time TA. I need #habitrpg to keep my days organized and efficient on my quest to earn a Masters!</a></div>
</div>
</div>
</div>
</div>
<!-- End Item -->
<div class="item improvement-use">
<h3>Goals</h3>
<div class="carousel-content">
<div class="sampletasks">
<h4>Sample Habits</h4>
<div style="width:19em; background-color: rgb(255, 242, 204); color: rgb(51, 51, 51); text-align:center; padding: 0px; font-size: 1.41em; line-height: 1.62765; list-style: none outside none; padding: 0px; height: 2.3em; min-height: 1.62765em; margin-bottom:0.75em; margin:0px; box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.5) inset;">
<div style="display: inline-block; width: 1.62765em; height: 1.62765em; padding: 0px; margin:0px; font-size: 1.41em; line-height: 1.62765; text-align: center; color: rgb(34, 34, 34); float:left; cursor: pointer; vertical-align: top; left:0px; position:relative; background-color: rgb(255, 207, 66); border-right: 1px solid rgba(0, 0, 0, 0.25);">+</div>&#160;<div style="display: inline-block; font-family: Lato,sans-serif; padding: 0.6em 0px 0em 1em; font-size: .8em; letter-spacing: normal; float:left; word-wrap: break-word;">Learn Something New </div></div><br />
<div style="width:19em; background-color: #d9ead3; color: rgb(51, 51, 51); text-align:center; padding: 0px; font-size: 1.41em; line-height: 1.62765; list-style: none outside none; padding: 0px; height: 2.3em; min-height: 1.62765em; margin-bottom:0.75em; margin:0px; box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.5) inset;">
<div style="display: inline-block; width: 1.62765em; height: 1.62765em; padding: 0px; margin:0px; font-size: 1.41em; line-height: 1.62765; text-align: center; color: rgb(34, 34, 34); float:left; cursor: pointer; vertical-align: top; left:0px; position:relative; background-color: rgb(113, 176, 91); border-right: 1px solid rgba(0, 0, 0, 0.25);">+</div><div style="display: inline-block; width: 1.62765em; height: 1.62765em; padding: 0px; margin:0px; font-size: 1.41em; line-height: 1.62765; text-align: center; color: rgb(34, 34, 34); float:left; cursor: pointer; vertical-align: top; background-color: rgb(113, 176, 91); border-right: 0px none;">-</div><div style="display: inline-block; font-family: Lato,sans-serif; padding: 0.6em 0px 0em 1em; font-size: .8em; letter-spacing: normal; float:left; word-wrap: break-word;">Accept a Compliment</div></div><br />
<div style="width:19em; background-color: rgb(255, 242, 204); color: rgb(51, 51, 51); text-align:center; padding: 0px; font-size: 1.41em; line-height: 1.62765; list-style: none outside none; padding: 0px; height: 2.3em; min-height: 1.62765em; margin-bottom:0.75em; margin:0px; box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.5) inset;">
<div style="display: inline-block; width: 1.62765em; height: 1.62765em; padding: 0px; margin:0px; font-size: 1.41em; line-height: 1.62765; text-align: center; color: rgb(34, 34, 34); float:left; cursor: pointer; vertical-align: top; left:0px; position:relative; background-color: rgb(255, 207, 66); border-right: 1px solid rgba(0, 0, 0, 0.25);">+</div>&#160;<div style="display: inline-block; font-family: Lato,sans-serif; padding: 0.6em 0px 0em 1em; font-size: .8em; letter-spacing: normal; float:left; word-wrap: break-word;">Creative Session</div></div><br />
<div style="width:19em; background-color: rgb(255, 242, 204); color: rgb(51, 51, 51); text-align:center; padding: 0px; font-size: 1.41em; line-height: 1.62765; list-style: none outside none; padding: 0px; height: 2.3em; min-height: 1.62765em; margin-bottom:0.75em; margin:0px; box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.5) inset;">
<div style="display: inline-block; width: 1.62765em; height: 1.62765em; padding: 0px; margin:0px; font-size: 1.41em; line-height: 1.62765; text-align: center; color: rgb(34, 34, 34); float:left; cursor: pointer; vertical-align: top; left:0px; position:relative; background-color: rgb(255, 207, 66); border-right: 1px solid rgba(0, 0, 0, 0.25);">+</div>&#160;<div style="display: inline-block; font-family: Lato,sans-serif; padding: 0.6em 0px 0em 1em; font-size: .8em; letter-spacing: normal; float:left; word-wrap: break-word;">Do a Good Deed</div></div><br />
<div style="width:19em; background-color: rgb(201, 218, 248); color: rgb(51, 51, 51); text-align:center; padding: 0px; font-size: 1.41em; line-height: 1.62765; list-style: none outside none; padding: 0px; height: 2.3em; min-height: 1.62765em; margin-bottom:0.75em; margin:0px; box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.5) inset;">
<div style="display: inline-block; width: 1.62765em; height: 1.62765em; padding: 0px; margin:0px; font-size: 1.41em; line-height: 1.62765; text-align: center; color: rgb(34, 34, 34); float:left; cursor: pointer; vertical-align: top; left:0px; position:relative; background-color: rgb(90, 98, 223); border-right: 1px solid rgba(0, 0, 0, 0.25);">+</div>&#160;<div style="display: inline-block; font-family: Lato,sans-serif; padding: 0.6em 0px 0em 1em; font-size: .8em; letter-spacing: normal; float:left; word-wrap: break-word;">Read an Informative Article</div></div>
</div>
<img class="sample-img" src="images/uses/Gaining_an_achievement_by_cosmic_caterpillar-d7uyv5z.png" />
<div class="usetweet-group">
<div class="usetweet tweet popover right">
<div class="arrow"></div>
<div class="popover-content"><a href="https://twitter.com/tessa_racked/status/488024741278543872">HabitRPG! Because I won't do yoga and practice Spanish for their own benefits, but I will to get a giant mantis shrimp mount for my avatar.</a></div>
</div>
<div class="usetweet tweet popover right">
<div class="arrow"></div>
<div class="popover-content"><a href="https://twitter.com/kristenrapp/status/522771210602807296">Without @habitrpg I don't think I would have finished my novel draft.</a></div>
</div>
</div>
</div>
</div>
<!-- End Item -->
<div class="item housework-use">
<h3>Chores</h3>
<div class="carousel-content">
<div class="sampletasks">
<h4>Sample Habits</h4>
<div style="width:19em; background-color: rgb(255, 242, 204); color: rgb(51, 51, 51); text-align:center; padding: 0px; font-size: 1.41em; line-height: 1.62765; list-style: none outside none; padding: 0px; height: 2.3em; min-height: 1.62765em; margin-bottom:0.75em; margin:0px; box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.5) inset;">
<div style="display: inline-block; width: 1.62765em; height: 1.62765em; padding: 0px; margin:0px; font-size: 1.41em; line-height: 1.62765; text-align: center; color: rgb(34, 34, 34); float:left; cursor: pointer; vertical-align: top; left:0px; position:relative; background-color: rgb(255, 207, 66); border-right: 1px solid rgba(0, 0, 0, 0.25);">+</div>&#160;<div style="display: inline-block; font-family: Lato,sans-serif; padding: 0.6em 0px 0em 1em; font-size: .8em; letter-spacing: normal; float:left; word-wrap: break-word;">Put Dirty Clothes in Hamper</div></div><br />
<div style="width:19em; background-color: #d9ead3; color: rgb(51, 51, 51); text-align:center; padding: 0px; font-size: 1.41em; line-height: 1.62765; list-style: none outside none; padding: 0px; height: 2.3em; min-height: 1.62765em; margin-bottom:0.75em; margin:0px; box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.5) inset;">
<div style="display: inline-block; width: 1.62765em; height: 1.62765em; padding: 0px; margin:0px; font-size: 1.41em; line-height: 1.62765; text-align: center; color: rgb(34, 34, 34); float:left; cursor: pointer; vertical-align: top; left:0px; position:relative; background-color: rgb(113, 176, 91); border-right: 1px solid rgba(0, 0, 0, 0.25);">+</div><div style="display: inline-block; width: 1.62765em; height: 1.62765em; padding: 0px; margin:0px; font-size: 1.41em; line-height: 1.62765; text-align: center; color: rgb(34, 34, 34); float:left; cursor: pointer; vertical-align: top; background-color: rgb(113, 176, 91); border-right: 0px none;">-</div><div style="display: inline-block; font-family: Lato,sans-serif; padding: 0.6em 0px 0em 1em; font-size: .8em; letter-spacing: normal; float:left; word-wrap: break-word;">20 mins of Housework</div></div><br />
<div style="width:19em; background-color: #d9ead3; color: rgb(51, 51, 51); text-align:center; padding: 0px; font-size: 1.41em; line-height: 1.62765; list-style: none outside none; padding: 0px; height: 2.3em; min-height: 1.62765em; margin-bottom:0.75em; margin:0px; box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.5) inset;">
<div style="display: inline-block; width: 1.62765em; height: 1.62765em; padding: 0px; margin:0px; font-size: 1.41em; line-height: 1.62765; text-align: center; color: rgb(34, 34, 34); float:left; cursor: pointer; vertical-align: top; left:0px; position:relative; background-color: rgb(113, 176, 91); border-right: 1px solid rgba(0, 0, 0, 0.25);">+</div><div style="display: inline-block; width: 1.62765em; height: 1.62765em; padding: 0px; margin:0px; font-size: 1.41em; line-height: 1.62765; text-align: center; color: rgb(34, 34, 34); float:left; cursor: pointer; vertical-align: top; background-color: rgb(113, 176, 91); border-right: 0px none;">-</div><div style="display: inline-block; font-family: Lato,sans-serif; padding: 0.6em 0px 0em 1em; font-size: .8em; letter-spacing: normal; float:left; word-wrap: break-word;">Wash a Load of Dishes</div></div><br />
<div style="width:19em; background-color: rgb(255, 242, 204); color: rgb(51, 51, 51); text-align:center; padding: 0px; font-size: 1.41em; line-height: 1.62765; list-style: none outside none; padding: 0px; height: 2.3em; min-height: 1.62765em; margin-bottom:0.75em; margin:0px; box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.5) inset;">
<div style="display: inline-block; width: 1.62765em; height: 1.62765em; padding: 0px; margin:0px; font-size: 1.41em; line-height: 1.62765; text-align: center; color: rgb(34, 34, 34); float:left; cursor: pointer; vertical-align: top; left:0px; position:relative; background-color: rgb(255, 207, 66); border-right: 1px solid rgba(0, 0, 0, 0.25);">+</div>&#160;<div style="display: inline-block; font-family: Lato,sans-serif; padding: 0.6em 0px 0em 1em; font-size: .8em; letter-spacing: normal; float:left; word-wrap: break-word;">Tidy One Room</div></div><br />
<div style="width:19em; background-color: rgb(201, 218, 248); color: rgb(51, 51, 51); text-align:center; padding: 0px; font-size: 1.41em; line-height: 1.62765; list-style: none outside none; padding: 0px; height: 2.3em; min-height: 1.62765em; margin-bottom:0.75em; margin:0px; box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.5) inset;">
<div style="display: inline-block; width: 1.62765em; height: 1.62765em; padding: 0px; margin:0px; font-size: 1.41em; line-height: 1.62765; text-align: center; color: rgb(34, 34, 34); float:left; cursor: pointer; vertical-align: top; left:0px; position:relative; background-color: rgb(90, 98, 223); border-right: 1px solid rgba(0, 0, 0, 0.25);">+</div>&#160;<div style="display: inline-block; font-family: Lato,sans-serif; padding: 0.6em 0px 0em 1em; font-size: .8em; letter-spacing: normal; float:left; word-wrap: break-word;">Wash and Dry a Load of Clothes</div></div>
</div>
<img class="sample-img" src="images/uses/dusting_by_leephon.png" />
<div class="usetweet-group">
<div class="usetweet tweet popover right">
<div class="arrow"></div>
<div class="popover-content"><a href="https://twitter.com/wholemilk/status/483341884929359872">Just did all the dishes AND scrubbed the sink, all for imaginary internet points! Thanks @habitrpg!</a></div>
</div>
<div class="usetweet tweet popover right">
<div class="arrow"></div>
<div class="popover-content"><a href="https://twitter.com/Caroline_Eising/status/553484464794267648">Remembered @habitrpg and started using it again. Today I cleaned the light fittings, which I have meant to do for at least a year #itworks</a></div>
</div>
</div>
</div>
</div>
<!-- End Item -->
</div>
</div>
<!-- End Carousel -->
</div>
</section>
<section id="quest-intro">
<h2 data-anchor-target="#rewards" data-500-bottom-top="opacity:0;position:fixed;right:0;top:0%;" data-50-bottom-top="opacity:1; top:35%;" data-center-center="top:-50%;">Join us on a mini-quest!<br/><span class="glyphicon glyphicon-chevron-down"></span></h2>
<!--Avatar fades in from behind, is affixed to travel at the center of the page all the way down until it hits the footer call-to-action-->
<img id="myAvatar" data--200-bottom-bottom="opacity:0;" data-center-center="display:block;position:fixed;right:10%;top:40%;opacity:1;" data-260-end="top:40%;" data-end="top:3%" data-edge-strategy="set" src="images/avatar/avatar.png" />
</section>
<section id="rewards" class="bg-warning">
<h2 class="headline">Complete a task to earn gold!</h2>
<div class="avatarscroll">
<h2 data-center-bottom="opacity:0;" data-120-top-center="opacity:1;"><span class="glyphicon glyphicon-check"></span></h2>
<img data-center-bottom="opacity:0;" data-180-top-center="opacity:1;" src="images/misc/shop_gold.png" /><img data-center-bottom="opacity:0;" data-180-top-center="opacity:1;" src="images/misc/shop_gold.png" /><img data-center-bottom="opacity:0;" data-180-top-center="opacity:1;" src="images/misc/shop_gold.png" /><br/>
<img data-center-bottom="opacity:0;" data-220-top-center="opacity:1;" src="images/TVreward.png" />
</div>
<!--3rd level equipment fades in on avatar, gets affixed until more equipment presented in Features area-->
<p class="sectioninfo">Spend gold on virtual and real-life rewards.<br/><br/>Instant rewards keep you motivated!</p>
<div class="scrolltweet scrolltweet-right">
<img class="speech-bubble" src="images/testimonial_by_Streak.png" />
<img class="scrolltweet-image" data-toggle="popover" data-placement="top" data-container="body" data-content="I really like HabitRPG. I did a bunch of jumping jacks because I needed a bit more gold for a helmet. -tonitonirocca" src="images/testimonials/Drag0nsilver.png" />
</div>
<div class="container-fluid">
<div class="row">
<div class="col-md-5 col-md-offset-1">
<div class="scrolltweet tweet popover left">
<div class="arrow"></div>
<div class="popover-content"><a href-"https://twitter.com/L0stPuppy/status/507034694970781696">I just found myself drinking more water so I could buy some leather armor. #habitrpg<span class="tweep">@L0stPuppy</span></a></div>
</div>
</div>
</div>
</div>
</section>
<section id="levels">
<h2 class="headline">As you stay productive, you unlock new content!</h2>
<div class="avatarscroll quest-classes">
<img data-bottom-bottom="display:block;opacity:0;margin-top:15%;right:200%;" data-center-center="display:block;opacity:1;right:80%;" src="images/Healer.png" />
<img data-bottom-bottom="display:block;opacity:0;left:200%;" data-center-center="display:block;opacity:1;margin-top:15%;left:80%;" src="images/Rogue.png" />
<img data-bottom-bottom="display:block;opacity:0;margin-top:40%;left:200%;" data-center-center="display:block;opacity:1;margin-top:36%;left:80%;" src="images/Wizard.png" />
<img data-bottom-bottom="display:block;opacity:0;margin-top:45%;right:200%;" data-center-center="display:block;opacity:1;margin-top:40%;right:80%;" src="images/Warrior.png" />
</div>
<div data-center-center="opacity:0;" data-150-top-center="display:block;position:fixed;right:10%;top:37%;opacity:1;" data-640-end="top:37%;opacity:1;" data-620-end="opacity:0;" data-edge-strategy="set" class="scroll-armor">
<img class="armor" src="images/avatar/head_warrior_3.png" />
<img class="armor" src="images/avatar/shield_warrior_3.png" />
<img class="armor" src="images/avatar/slim_armor_warrior_3.png" />
<img class="armor" src="images/avatar/weapon_warrior_3.png" />
</div>
<div data-center-center="opacity:0;" data-150-top-center="display:block;position:fixed;right:10%;top:53%;z-index:3;opacity:1;" data-260-end="top:53%;" data-end="top:16%" data-edge-strategy="set" class="quest-pet">
<img src="images/Pet-Fox-Red.png" />
</div>
<!--Dragon pet and class costumes come in from sides-->
<p class="sectioninfo">Achieve your goals and level up.<br/><br/>Unlock new motivational tools, such as pet collecting, random rewards, spell-casting, and more!</p>
<div class="container-fluid">
<div class="row">
<div class="col-md-5 col-md-offset-7">
<div class="scrolltweet tweet popover right">
<div class="arrow"></div>
<div class="popover-content"><a href="https://twitter.com/NatJeanMiller/status/505598740242001920">I'm level 30 and riding a dragon #winning</a></div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-5 col-md-offset-1">
<div class="scrolltweet tweet popover left">
<div class="arrow"></div>
<div class="popover-content"><a href-"https://twitter.com/ClaireThalken/status/466631598847574017">Woot! I reached level ten on HabitRPG and switched my class from warrior to rogue. Now I get to hold TWO weapons.</a></div>
</div>
</div>
</div>
</div>
</section>
<section id="health" class="bg-danger">
<h2 class="headline">Miss a daily goal?</h2>
<!--Progress bar appears next to avatar, decreases on scroll. Probably will require SVG animation-->
<div class="health-progress">
<div tooltip="Health" class="meter-label">
<span class="glyphicon glyphicon-heart"></span>
</div>
<div class="meter health">
<div class="bar"><div data-center-center="width:100%;" data-200-top-top="width:50%;">&nbsp;</div></div>
</div>
</div>
<h2>Lose health!</h2>
<p class="sectioninfo">Break bad habits and procrastination cycles with immediate consequences.</p>
<div class="container-fluid">
<div class="row">
<div class="col-md-5 col-md-offset-7">
<div class="scrolltweet tweet popover right">
<div class="arrow"></div>
<div class="popover-content"><a href="https://twitter.com/kevinpurdy/status/494498960116293633">Pleasantly surprised how well I'm sticking to @habitrpg as a task list/habit enforcer. A lifetime of watching health meters pays off.<span class="tweep">@kevinpurdy</span></a></div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-5 col-md-offset-1">
<div class="scrolltweet tweet popover left">
<div class="arrow"></div>
<div class="popover-content"><a href="https://twitter.com/soft_lit/status/560231146467127297">I need to stop neglecting habitrpg otherwise my little dude will die soon<span class="tweep">@soft_lit</span></a></div>
</div>
</div>
</div>
</div>
</section>
<section id="quest">
<h2 class="headline">Battle monsters with your friends!</h2>
<!--Boss image background, with other avatars present. Their progress bars decrease on scroll. The one on the bottom right corner could die, haha-->
<div class="quest-friend quest-left">
<div class="quest-friend-health">
<div tooltip="Health" class="meter-label">
<span class="glyphicon glyphicon-heart"></span></div>
<div class="meter health">
<div class="bar"><div data-center-center="width:90%;" data-200-top-top="width:30%;">&nbsp;</div></div>
</div>
</div>
<div class="quest-friend-img"><img src="images/party/AnnaCosplay.png" /></div>
</div>
<div class="quest-friend quest-right">
<div class="quest-friend-health">
<div tooltip="Health" class="meter-label">
<span class="glyphicon glyphicon-heart"></span></div>
<div class="meter health">
<div class="bar"><div data-center-center="width:40%;" data-200-top-top="width:0%;">&nbsp;</div></div>
</div>
</div>
<div class="quest-friend-img" data-bottom-bottom='background: url("images/party/HomeStuckLusus.png") no-repeat left top;' data-220-top-top='background: url("images/party/GrimReaper.png")no-repeat center top;'></div>
</div>
<h2>If you slack off, they all get hurt!</h2>
<p class="sectioninfo">Playing with your friends keeps you accountable for your tasks.<br/>Issue each other Challenges to complete a goal together!</p>
<div class="container-fluid">
<div class="row">
<div class="col-md-5 col-md-offset-7">
<div class="scrolltweet tweet popover right">
<div class="arrow"></div>
<div class="popover-content"><a href="https://twitter.com/DejiNyucu/status/429211504726900737">Oh, we did it! we completed our first quest in #HabitRPG as a party and we got the polar bear mount!<span class="tweep">@DejiNyucu</span></a></div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-5 col-md-offset-1">
<div class="scrolltweet tweet popover left">
<div class="arrow"></div>
<div class="popover-content"><a href="https://twitter.com/korybing/status/539135640072253440">oh shoot I forgot to check off a couple dailies on my habitrpg I'M SORRY, HABITRPG PARTY.<span class="tweep">@korybing</span></a></div>
</div>
</div>
</div>
</div>
</section>
<div id="features" class="bg-info">
<h2>We also feature...</h2>
<div class="container-fluid">
<div class="row">
<!--Pets and mount fade-in. Need to think about how to sticky it to the avatar-->
<div class="col-md-1 col-md-offset-6 quest-mount">
<img data-100-center-center="opacity:0;" data-40-center-center="display:block;position:fixed;top:46%;opacity:1;" data-260-end="top:46%;" data-end="top:9%" data-edge-strategy="set" class="mount" src="images/Mount_Body_Wolf-Base.png" />
<img data-100-center-center="opacity:0;" data-40-center-center="display:block;position:fixed;top:46%;opacity:1;" data-260-end="top:46%;" data-end="top:9%" data-edge-strategy="set" class="mount mount-head" src="images/Mount_Head_Wolf-Base.png" />
</div>
<div class="col-md-4">
<div class="featuretext">
<h4>Pets and Mounts</h4>
<p>Eggs and items drop when you complete your tasks. Be as productive as possible to collect pets and mounts!</p>
</div>
</div>
</div>
</div>
<!--
<div class="container-fluid">
<div class="row">
<div class="col-md-3 col-md-offset-1">
<div class="scrolltweet tweet popover bottom">
<div class="arrow"></div>
<div class="popover-title"><strong>You're Resting in the Inn</strong></div>
<div class="popover-content"><p>The Zzz's over your avatar's head means you are <a href="http://habitrpg.wikia.com/wiki/Tavern#Resting_in_the_Inn">Resting in the Inn</a>.</p><p>Your Dailies won't reset until you check out.</p>
<button class="btn btn-sm btn-block btn-default">I'm still resting but remind me tomorrow</button>
<button class="btn btn-block btn-default">Don't remind me again</button>
<button class="btn btn-block btn-primary">Check out of inn</button>
</div>
</div>
</div>
</div>-->
<div class="row">
<!--Achievemnt badge fade-in-->
<div class="col-md-1 col-md-offset-6">
<img data-50-center-center="opacity:0;" data--40-center-center="display:block;position:fixed;top:44%;left:55%;opacity:1;" data-260-end="top:44%;" data-end="top:6%" data-edge-strategy="set" src="images/achievement-triadbingo.png" />
<img data-50-center-center="opacity:0;" data--40-center-center="display:block;position:fixed;top:49%;left:55%;opacity:1;" data-260-end="top:49%;" data-end="top:11%" data-edge-strategy="set" src="images/achievement-perfect.png" />
</div>
<div class="col-md-4">
<div class="featuretext">
<h4>Achievement Badges</h4>
<p>Do something totally awesome? Get a badge and show it off!</p>
</div>
</div>
</div>
<div class="container-fluid">
<div class="row">
<!--Level 5 equipment fade-in, with candy/potion/quest scroll. Level 5 equipment stickies on avatar all the way down-->
<div class="col-md-1 col-md-offset-6 quest-warrior">
<img data-100-center-center="opacity:0;" data-40-center-center="display:block;position:fixed;top:39%;opacity:1;" data-260-end="top:39%;" data-end="top:2%" data-edge-strategy="set" class="warrior-5" src="images/avatar/head_warrior_5.png" />
<img data-100-center-center="opacity:0;" data-40-center-center="display:block;position:fixed;top:39%;opacity:1;" data-260-end="top:39%;" data-end="top:2%" data-edge-strategy="set" class="warrior-5" src="images/avatar/shield_warrior_5.png" />
<img data-100-center-center="opacity:0;" data-40-center-center="display:block;position:fixed;top:39%;opacity:1;" data-260-end="top:39%;" data-end="top:2%" data-edge-strategy="set" class="warrior-5" src="images/avatar/slim_armor_warrior_5.png" />
<img data-100-center-center="opacity:0;" data-40-center-center="display:block;position:fixed;top:39%;opacity:1;" data-260-end="top:39%;" data-end="top:2%" data-edge-strategy="set" class="warrior-5" src="images/avatar/weapon_warrior_5.png" />
</div>
<div class="col-md-4">
<div class="featuretext">
<h4>Equipment and extras</h4>
<p>Buy limited edition equipment, potions, and other virtual goodies in our Market with your task rewards!</p>
</div>
</div>
</div>
</div>
<div class="container-fluid">
<div class="row">
<!--other avatars fly gin from sides to be next to main avatar-->
<div class="col-md-1 col-md-offset-6">
<img data-100-center-center="left:-100%;" data-50-center-center="position:fixed;top:45%;left:0%;" data-end="top:6%" data-edge-strategy="set" src="images/Party-Header.png" />
</div>
<div class="col-md-4">
<div class="featuretext">
<h4>Social play</h4>
<p>Join common-interest groups with like-minded people.<br/><br/>Create Challenges to compete against other users.</p>
</div>
</div>
</div>
</div>
</div>
<!-- <section id="testimonials">
<h2>What people say...</h2>
<div class="container-fluid">
<div class="row">
<div class="col-md-5 col-md-offset-7">
<div class="testimonialgroup">
<div class="testimonial tweet popover right">
<div class="arrow"></div>
<div class="popover-content"><a href="https://twitter.com/MayLHarrison/status/559440289556103169">Can't remember how I kept control of my life before @habitrpg. Best tool I've ever found for becoming the best version of myself I can be.</a></div>
</div>
<img class="tweeppic" />
<span class="tweep">@MayLHarrison</span>
</div>
</div></div>
<div class="row">
<div class="col-md-5 col-md-offset-1">
<div class="testimonialgroup">
<div class="testimonial tweet popover left">
<div class="arrow"></div>
<div class="popover-content"><a href="https://twitter.com/wholemilk/status/484533856864071680">Thank you, @habitrpg , I have now run five mornings in a row, my house is cleaner, and I'm drinking more water!</a></div>
</div>
<img class="tweeppic" />
<span class="tweep">@wholemilk</span>
</div></div></div>
<div class="row">
<div class="col-md-5 col-md-offset-7">
<div class="testimonialgroup">
<div class="testimonial tweet popover right">
<div class="arrow"></div>
<div class="popover-content"><a href="https://twitter.com/mattjoehunt/status/559613163654905856">The best game I have ever played is @habitrpg - I have never been more productive.</a></div>
</div>
<img class="tweeppic" />
<span class="tweep">@mattjoehunt</span>
</div>
</div></div></div>
</section> -->
<div id="footercall">
<div class="container-fluid">
<div class="row">
<div class="col-md-4 col-md-offset-7">
<h3>Join 200,000 players making it fun to achieve goals!</h3>
</div>
</div>
<div class="row">
<div class="col-md-4 col-md-offset-4">
<button class="btn btn-primary btn-lg btn-block">Play for free!</button>
</div>
</div>
</div>
</div>
<footer class="footer">
<div class="container-fluid shoutout">
<h4>HabitRPG &lt;3s</h4>
<div class="row">
<div class="col-md-2 col-md-offset-1"><a href="http://ionicframework.com/"><img src="images/presslogos/ionic-logo-horizontal-transparent.png"></a></div>
<div class="col-md-2"><a href="https://www.jetbrains.com/webstorm/"><img src="images/presslogos/logo_webstorm.png"></a></div>
<div class="col-md-2"><a href="http://github.com/"><img src="images/presslogos/GitHub_Logo.png"></a></div>
<div class="col-md-2"><a href="https://trello.com/"><img src="images/presslogos/trello-logo-blue.png"></a></div>
<div class="col-md-2"><a href="https://slack.com/"><img src="images/presslogos/landing_slack_hash_wordmark_logo.png"></a></div>
</div>
</div>
<div class="row footer-content">
<div class="col-md-2 col-md-offset-2">
<h4>Mobile</h4>
<ul class="list-unstyled">
<li><a href="https://itunes.apple.com/us/app/habitrpg/id689569235?mt=8" target="_blank">iOS</a></li>
<li><a href="https://play.google.com/store/apps/details?id=com.ocdevel.habitrpg" target="_blank">Android</a></li>
</ul>
</div>
<div class="col-md-2">
<h4>Company</h4>
<ul class="list-unstyled">
<li><a href="/static/features">Features</a></li>
<li><a target="_blank" href="http://blog.habitrpg.com/">Blog</a></li>
<li><a target="_blank" href="http://habitrpg.wikia.com/wiki/FAQ">FAQ</a></li>
<li><a href="/static/privacy">Privacy</a></li>
<li><a href="/static/terms">Terms</a></li>
<li><a href="/static/contact">Contact Us</a></li>
</ul>
</div>
<div class="col-md-2">
<h4>Community</h4>
<ul class="list-unstyled">
<li><a target="_blank" href="https://habitrpg.com/static/api">API</a></li>
<li><a href="http://habitrpg.wikia.com/wiki/App_and_Extension_Integrations" target="_blank">Add-ons &amp; Extensions</a></li>
<li><a target="_blank" href="http://habitrpg.wikia.com/wiki/Special:Forum">Forum</a></li>
<li><a target="_blank" href="http://www.kickstarter.com/projects/lefnire/habitrpg-mobile">Kickstarter</a></li>
<li><a target="_blank" href="https://www.facebook.com/Habitrpg">Facebook</a></li>
<li><a target="_blank" href="http://www.reddit.com/r/habitrpg/">Reddit</a></li>
</ul>
</div>
<div class="col-md-2">
<h4>Social</h4>
<div addthis:url="https://habitrpg.com" addthis:title="HabitRPG - Gamify Your Life" class="addthis_toolbox addthis_default_style">
<table>
<tr>
<td><a fb:like:layout="button_count" class="addthis_button_facebook_like"></a></td>
</tr>
<tr>
<td><a tw:via="habitrpg" class="addthis_button_tweet"></a></td>
</tr>
<tr>
<!-- <td><iframe src="http://www.habitrpg.com/bower_components/github-buttons/github-btn.html?user=lefnire&amp;repo=habitrpg&amp;type=watch&amp;count=true" allowtransparency="true" frameborder="0" scrolling="0" width="85px" height="20px"></iframe></td> -->
</tr>
<tr>
<td><a g:plusone:size="medium" class="addthis_button_google_plusone"></a></td>
</tr>
</table>
</div>
</div>
</div>
</div>
</footer>
<!--Fixed CTA-->
<button data-anchor-target=".gamifybutton" data-top="opacity:0;" data--100-top="opacity:1;" data-500-end="opacity:1;" data-400-end="opacity:0;" class="btn btn-info fixedcta">Gamify your life today!</button>
<!-- Footer scripts -->
<!--Use carousel initialize-->
<script type="text/javascript">
$(document).ready( function() {
$('#myCarousel').carousel({
interval: false
});
var clickEvent = false;
$('#myCarousel').on('click', '.nav a', function() {
clickEvent = true;
$('.nav li').removeClass('active');
$(this).parent().addClass('active');
}).on('slid.bs.carousel', function(e) {
if(!clickEvent) {
var count = $('.nav').children().length -1;
var current = $('.nav li.active');
current.removeClass('active').next().addClass('active');
var id = parseInt(current.data('slide-to'));
if(count == id) {
$('.nav li').first().addClass('active');
}
}
clickEvent = false;
});
});
</script>
<!--Skroller init-->
<script type="text/javascript" src="js/skrollr.min.js"></script>
<script type="text/javascript">
var s = skrollr.init();
</script>
<!--Tooltips-->
<script type="text/javascript">
$(function () {
$('[data-toggle="tooltip"]').tooltip()
$('[data-toggle="popover"]').popover()
})
</script>
</body>
</html>

File diff suppressed because one or more lines are too long

View file

@ -1 +0,0 @@
<!-- See /website/views/static/front -->

View file

@ -19,7 +19,9 @@ habitrpg.controller("ChallengesCtrl", ['$rootScope','$scope', 'Shared', 'User',
$scope.challenges = challenges;
$scope.groupsFilter = _.uniq(_.pluck(challenges, 'group'), function(g){return g._id});
$scope.search = {
group: _.transform($scope.groups, function(m,g){m[g._id]=true;})
group: _.transform($scope.groups, function(m,g){m[g._id]=true;}),
_isMember: "either",
_isOwner: "either"
};
});
}
@ -254,18 +256,10 @@ habitrpg.controller("ChallengesCtrl", ['$rootScope','$scope', 'Shared', 'User',
// Filtering
//------------------------------------------------------------
// $scope.$watch('search', function(search){
// if (!search) $scope.filteredChallenges = $scope.challenges;
// $scope.filteredChallenges = $filter('filter')($scope.challenges, function(chal) {
// return (search.group[chal.group._id] &&
// (typeof search._isMember == 'undefined' || search._isMember == chal._isMember));
// })
// })
// TODO probably better to use $watch above, to avoid this being calculated on every digest cycle
$scope.filterChallenges = function(chal){
return (!$scope.search) ? true :
($scope.search.group[chal.group._id] &&
(typeof $scope.search._isMember == 'undefined' || $scope.search._isMember == chal._isMember));
if (!$scope.search) return true;
return _shouldShowChallenge(chal);
}
$scope.$watch('newChallenge.group', function(gid){
@ -286,4 +280,16 @@ habitrpg.controller("ChallengesCtrl", ['$rootScope','$scope', 'Shared', 'User',
$scope.shouldShow = function(task, list, prefs){
return true;
};
function _shouldShowChallenge(chal) {
// Have to check that the leader object exists first in the
// case where a challenge's leader deletes their account
var userIsOwner = (chal.leader && chal.leader._id) == User.user.id;
var groupSelected = $scope.search.group[chal.group._id];
var checkOwner = $scope.search._isOwner === 'either' || (userIsOwner === $scope.search._isOwner);
var checkMember = $scope.search._isMember === 'either' || (chal._isMember === $scope.search._isMember);
return groupSelected && checkOwner && checkMember;
}
}]);

View file

@ -5,6 +5,7 @@ habitrpg.controller("FiltersCtrl", ['$scope', '$rootScope', 'User', 'Shared',
var user = User.user;
$scope._editing = false;
$scope._newTag = {name:''};
$scope.filterQuery = '';
var tagsSnap; // used to compare which tags need updating
@ -30,6 +31,11 @@ habitrpg.controller("FiltersCtrl", ['$scope', '$rootScope', 'User', 'Shared',
// User.save();
};
$scope.updateTaskFilter = function(){
user.filterQuery = $scope.filterQuery;
};
$scope.updateTaskFilter();
$scope.createTag = function() {
User.user.ops.addTag({body:{name:$scope._newTag.name, id:Shared.uuid()}});
$scope._newTag.name = '';

View file

@ -4,6 +4,7 @@ habitrpg.controller("TasksCtrl", ['$scope', '$rootScope', '$location', 'User','N
function($scope, $rootScope, $location, User, Notification, $http, ApiUrl, $timeout, Shared, Guide) {
$scope.obj = User.user; // used for task-lists
$scope.user = User.user;
$scope.armoireCount = function(gear) {
return Shared.countArmoire(gear);
};
@ -131,6 +132,19 @@ habitrpg.controller("TasksCtrl", ['$scope', '$rootScope', '$location', 'User','N
*/
$scope._today = moment().add({days: 1});
/*
------------------------
Dailies
------------------------
*/
$scope.openDatePicker = function($event, task) {
$event.preventDefault();
$event.stopPropagation();
task._isDatePickerOpen = !task._isDatePickerOpen;
}
/*
------------------------
Checklists
@ -216,7 +230,7 @@ habitrpg.controller("TasksCtrl", ['$scope', '$rootScope', '$location', 'User','N
$scope.shouldShow = function(task, list, prefs){
if (task._editing) // never hide a task while being edited
return true;
var shouldDo = task.type == 'daily' ? habitrpgShared.shouldDo(new Date, task.repeat, prefs) : true;
var shouldDo = task.type == 'daily' ? habitrpgShared.shouldDo(new Date, task, prefs) : true;
switch (list.view) {
case "yellowred": // Habits
return task.value < 1;

View file

@ -1,31 +0,0 @@
angular.module('habitrpg')
.filter('gold', function () {
return function (gp) {
return Math.floor(gp);
}
})
.filter('silver', function () {
return function (gp) {
return Math.floor((gp - Math.floor(gp))*100);
}
})
.filter('htmlDecode',function(){
return function(html){
return $('<div/>').html(html).text();
}
})
.filter('goldRoundThousandsToK', function(){
return function (gp) {
return (gp > 999999999) ? (gp / Math.pow(10, 9)).toFixed(1) + "b" :
(gp > 999999) ? (gp / Math.pow(10, 6)).toFixed(1) + "m" :
(gp > 999) ? (gp / Math.pow(10, 3)).toFixed(1) + "k" : gp;
}
})
.filter('conditionalOrderBy', ['$filter', function($filter) {
return function (array, predicate, sortPredicate, reverseOrder) {
if (predicate) {
return $filter('orderBy')(array, sortPredicate, reverseOrder);
}
return array;
};
}]);

View file

@ -0,0 +1,11 @@
angular.module('habitrpg')
.filter('gold', function () {
return function (gp) {
return Math.floor(gp);
}
})
.filter('silver', function () {
return function (gp) {
return Math.floor((gp - Math.floor(gp))*100);
}
});

View file

@ -0,0 +1,30 @@
angular.module('habitrpg')
.filter('roundLargeNumbers', function(){
return function (num) {
return _calculateRoundedNumber(num);
}
});
function _calculateRoundedNumber(num) {
if (num > 999999999) {
return _convertToBillion(num);
} else if (num > 999999) {
return _convertToMillion(num);
} else if (num > 999) {
return _convertToThousand(num);
} else {
return num;
}
}
function _convertToThousand(num) {
return (num / Math.pow(10, 3)).toFixed(1) + "k";
}
function _convertToMillion(num) {
return (num / Math.pow(10, 6)).toFixed(1) + "m";
}
function _convertToBillion(num) {
return (num / Math.pow(10, 9)).toFixed(1) + "b";
}

View file

@ -0,0 +1,30 @@
angular.module('habitrpg')
.filter('conditionalOrderBy', ['$filter', function($filter) {
return function (array, predicate, sortPredicate, reverseOrder) {
if (predicate) {
return $filter('orderBy')(array, sortPredicate, reverseOrder);
}
return array;
};
}])
.filter('filterByTextAndNotes', ['$filter', function($filter) {
return function (input, term) {
if (!input) return;
if (!angular.isString(term) || term.legth === 0) {
return input;
}
term = new RegExp(term, 'i');
var result = [];
for (var i = 0; i < input.length; i++) {
if (term.test(input[i].text) || term.test(input[i].notes)) {
result.push(input[i]);
}
}
return result;
};
}]);

View file

@ -38,6 +38,7 @@
"js/app.js",
"common/script/public/config.js",
"js/services/sharedServices.js",
"js/services/notificationServices.js",
"common/script/public/userServices.js",
@ -48,7 +49,9 @@
"js/services/challengeServices.js",
"js/services/paymentServices.js",
"js/filters/filters.js",
"js/filters/money.js",
"js/filters/roundLargeNumbers.js",
"js/filters/taskOrdering.js",
"js/directives/focus-me.directive.js",
"js/directives/from-now.directive.js",

View file

@ -8,6 +8,7 @@ var mongoose = require("mongoose");
var Schema = mongoose.Schema;
var shared = require('../../../common');
var _ = require('lodash');
var moment = require('moment');
// Task Schema
// -----------
@ -50,10 +51,13 @@ var checklist = [{
var DailySchema = new Schema(
_.defaults({
type: {type:String, 'default': 'daily'},
type: {type: String, 'default': 'daily'},
frequency: {type: String, 'default': 'weekly', enum: ['daily', 'weekly']},
everyX: {type: Number, 'default': 1}, // e.g. once every X weeks
startDate: {type: Date, 'default': moment().startOf('day').toDate()},
history: Array,
completed: {type: Boolean, 'default': false},
repeat: {
repeat: { // used only for 'weekly' frequency,
m: {type: Boolean, 'default': true},
t: {type: Boolean, 'default': true},
w: {type: Boolean, 'default': true},

View file

@ -38,7 +38,7 @@ html(ng-app="habitrpg", ng-controller="RootCtrl", ng-class='{"applying-action":a
include ./shared/header/menu
include ./shared/modals/index
include ./shared/header/header
include ./shared/tasks/lists
include ./shared/tasks/index
include ./main/index
include ./options/index

View file

@ -1,6 +1,10 @@
.container-fluid
.row
.filters(ng-controller='FiltersCtrl')
.input-group.input-group-sm.filters-search.pull-right
input.form-control(type='text', placeholder=env.t('search'), ng-model='filterQuery', ng-change='updateTaskFilter()', ng-model-options='{ debounce: 250 }')
.input-group-addon
.glyphicon.glyphicon-search
ul.filters-controls
li=env.t('tags')
//- Edit button

View file

@ -52,13 +52,13 @@ mixin boss(tavern, mobile)
.meter.health
.bar(style='width: {{Shared.percent(progress.hp, boss.hp)}}%;')
span.meter-text.value
| {{Math.ceil(progress.hp) | goldRoundThousandsToK}} / {{boss.hp | goldRoundThousandsToK}}
| {{Math.ceil(progress.hp) | roundLargeNumbers}} / {{boss.hp | roundLargeNumbers}}
.meter-label(tooltip='Rage', ng-if='boss.rage')
span.glyphicon.glyphicon-fire
.meter.mana(ng-if='boss.rage',popover="{{::boss.rage.description()}}",popover-title="{{::boss.rage.title()}}",popover-trigger='mouseenter',popover-placement='right')
.bar(style='width: {{Shared.percent(progress.rage, boss.rage.value)}}%;')
span.meter-text.value
| {{Math.ceil(progress.rage) | goldRoundThousandsToK}} / {{boss.rage.value | goldRoundThousandsToK}}
| {{Math.ceil(progress.rage) | roundLargeNumbers}} / {{boss.rage.value | roundLargeNumbers}}
div(ng-if='::Content.quests[group.quest.key].collect')
div(class="quest_{{::group.quest.key}}")
h4=env.t('collected') + ':'

View file

@ -81,16 +81,29 @@ script(type='text/ng-template', id='partials/options.social.challenges.html')
h4=env.t('membership')
.radio
label
input(type='radio', name='search-participation-radio', ng-click='search._isMember = true')
input(type='radio', name='search-participation-radio', ng-model='search._isMember', ng-value='true', ng-change='filterChallenges')
=env.t('participating')
.radio
label
input(type='radio', name='search-participation-radio', ng-click='search._isMember = false')
input(type='radio', name='search-participation-radio', ng-model='search._isMember', ng-value='false', ng-change='filterChallenges')
=env.t('notParticipating')
.radio
label
input(type='radio', name='search-participation-radio', ng-click='search._isMember = undefined', checked='checked')
input(type='radio', name='search-participation-radio', ng-model='search._isMember', value='either', ng-change='filterChallenges')
=env.t('either')
h4=env.t('challengedOwnedFilterHeader')
.radio
label
input(type='radio', name='search-owner-radio', ng-model='search._isOwner', ng-value='true', ng-change='filterChallenges')
=env.t('challengedOwnedFilter')
.radio
label
input(type='radio', name='search-owner-radio', ng-model='search._isOwner', ng-value='false', ng-change='filterChallenges')
=env.t('challengedNotOwnedFilter')
.radio
label
input(type='radio', name='search-owner-radio', ng-model='search._isOwner', value='either', ng-change='filterChallenges', checked='checked')
=env.t('challengedEitherOwnedFilter')
.col-md-10
a.btn.btn-info#back-to-challenges(ng-show="cid", ui-sref='options.social.challenges', ui-sref-opts='{reload: true}')
| Back to all challenges

View file

@ -146,8 +146,9 @@ nav.toolbar(ng-controller='AuthCtrl', ng-class='{active: isToolbarHidden}')
a(target="_blank" ng-href='http://data.habitrpg.com?uuid={{user._id}}')=env.t('dataTool')
li
a(ui-sref='options.settings.export')=env.t('exportData')
li.toolbar-button-dropdown
li.toolbar-button-dropdown.highlight
a(target="_blank" href='http://habitrpg.wikia.com/wiki/')
span.glyphicon.glyphicon-question-sign
span=env.t('help')
a(ng-click='expandMenu("help")', ng-class='{active: _expandedMenu == "help"}')
span &#9776;
@ -169,7 +170,7 @@ nav.toolbar(ng-controller='AuthCtrl', ng-class='{active: isToolbarHidden}')
a(ng-click='showTour()', popover-placement='right', popover-trigger='mouseenter', popover=env.t('restartTour'))= env.t('showTour')
ul.toolbar-subscribe(ng-if='!user.purchased.plan.customerId')
li.toolbar-subscribe-button
button(ui-sref='options.settings.subscription',popover-trigger='mouseenter',popover-placement='bottom',popover-title=env.t('subscriptions'),popover=env.t('subDescription'),popover-append-to-body='true')=env.t('subscribe')
button.highlight(ui-sref='options.settings.subscription',popover-trigger='mouseenter',popover-placement='bottom',popover-title=env.t('subscriptions'),popover=env.t('subDescription'),popover-append-to-body='true')=env.t('subscribe')
ul.toolbar-options
li.toolbar-notifs
a(ng-click='expandMenu("notifs")')
@ -264,7 +265,7 @@ nav.toolbar(ng-controller='AuthCtrl', ng-class='{active: isToolbarHidden}')
span.gem-text {{user.balance * 4 | number:0}}
li.toolbar-currency.gold(popover=env.t('gold') + ' ({{Shared.gold(user.stats.gp)}})', popover-placement='bottom',popover-trigger='mouseenter')
span.shop_gold
span {{Shared.gold(user.stats.gp) | goldRoundThousandsToK}}
span {{Shared.gold(user.stats.gp) | roundLargeNumbers}}
li.toolbar-currency.silver(popover=env.t('silver'), popover-placement='bottom',popover-trigger='mouseenter')
span.shop_silver
span {{Shared.silver(user.stats.gp)}}

View file

@ -1,33 +1,65 @@
h5 6/1/2015 - NEW EQUIPMENT: THE ENCHANTED ARMOIRE, JUNE BACKGROUNDS, AND NEW MOUNT POSITIONING!
h5 6/11/2015 - REPEATING TASKS, START DATE, AND MOBILE APP UPDATES!
p
br
p.small.muted by Blade and fallenpanda
hr
tr
td
.promo_enchanted_armoire.pull-right
h5 New Equipment: The Enchanted Armoire!
p Now after you achieve Ultimate Gear, you'll unlock a new Reward: THE ENCHANTED ARMOIRE!
h5 New Repeat Option for Dailies
p Dailies now have a new Advanced Option: Repeat Every X Days. You've wanted this feature for a long time, and it's finally here!
br
p Click on the Enchanted Armoire, a 100 GP Reward in the Rewards Column, for a random chance at special Equipment! It may also give you random XP or food items. We'll be adding new equipment to it every month, but even when you've exhausted the current supply, you can keep clicking for a chance at food and XP.
p First, please note that this new option is OPT-IN only. We won't make any changes to your preexisting Dailies without you knowing it. We wouldn't do that!
br
p Now go spend all that accumulated Gold! May the Random Number Generator smile upon you...
p.small.muted by Lemoness and SabreCat
p.small.muted Art by Kiwibot, Starsystemic, UncommonCriminal, Zoebeagle, and Andrews38
p That being said, here are the new features:
tr
td
.background_island_waterfalls.pull-right
h5 June Backgrounds Revealed
p There are three new avatar backgrounds in the <a href='/#/options/profile/backgrounds' target='_blank'>Background Shop</a>! Now your avatar can paddle a Drifting Raft, float through a sea of Shimmery Bubbles, or picnic near Island Waterfalls!
p.small.muted by (in order): Teto is Great, beffymaroo, and UncommonCriminal
h5 Repeating Tasks
p Use the "Every X Days" function under Dailies Advanced Options to create tasks that repeat after a certain number of days have passed, whether every 2 days, every 15 days, every 30 days... You choose the number that works for you!
br
p These Dailies are only due on those given dates. Need to pay your rent every 30 days? Take medicine every other day? Water your plants every 4 days? No longer a problem.
tr
td
h5 New Mount Positioning!
p The mount positioning has been fixed for all the base mounts where it looked like the avatar was riding extreme sidesaddle. Now avatars sit properly, no longer clinging to the sides of their mounts for dear life.
p.small.muted by Kiwibot, Lemoness, and SabreCat
h5 Start Date
p Dailies now have a Start Date. They will not be due before this date. This means that if you want to add a new Daily while you're thinking about it, but not have it be due until later, you can achieve that by setting a future Start Date!
tr
td
h5 Mobile App Updates
p New <a href='https://play.google.com/store/apps/details?id=com.ocdevel.habitrpg' target='_blank'>Android</a> and <a href='https://itunes.apple.com/us/app/habitrpg/id689569235?mt=8' target='_blank'>iOS</a> updates are available to support this feature. Please, update your apps before using it, or the new repeating Dailies will not display normally on the mobile apps!
tr
td
h5 Other Notes
p For a short period of time, the <a href='http://data.habitrpg.com' target='_blank'>Data Display Tool</a> will not be able to calculate damage correctly for Repeat Every X Dailies. We'll get that updated very soon so that it will be accurate again!
br
p If you still have questions about Repeat Every X Dailies, don't hesitate to ask in <a href='/#/options/groups/guilds/5481ccf3-5d2d-48a9-a871-70a7380cee5a' target='_blank'>the Newbies Guild</a>!
hr
a(href='/static/old-news', target='_blank') Read older news
mixin oldNews
h5 6/1/2015 - NEW EQUIPMENT: THE ENCHANTED ARMOIRE, JUNE BACKGROUNDS, AND NEW MOUNT POSITIONING!
tr
td
.promo_enchanted_armoire.pull-right
h5 New Equipment: The Enchanted Armoire!
p Now after you achieve Ultimate Gear, you'll unlock a new Reward: THE ENCHANTED ARMOIRE!
br
p Click on the Enchanted Armoire, a 100 GP Reward in the Rewards Column, for a random chance at special Equipment! It may also give you random XP or food items. We'll be adding new equipment to it every month, but even when you've exhausted the current supply, you can keep clicking for a chance at food and XP.
br
p Now go spend all that accumulated Gold! May the Random Number Generator smile upon you...
p.small.muted by Lemoness and SabreCat
p.small.muted Art by Kiwibot, Starsystemic, UncommonCriminal, Zoebeagle, and Andrews38
tr
td
.background_island_waterfalls.pull-right
h5 June Backgrounds Revealed
p There are three new avatar backgrounds in the <a href='/#/options/profile/backgrounds' target='_blank'>Background Shop</a>! Now your avatar can paddle a Drifting Raft, float through a sea of Shimmery Bubbles, or picnic near Island Waterfalls!
p.small.muted by (in order): Teto is Great, beffymaroo, and UncommonCriminal
tr
td
h5 New Mount Positioning!
p The mount positioning has been fixed for all the base mounts where it looked like the avatar was riding extreme sidesaddle. Now avatars sit properly, no longer clinging to the sides of their mounts for dear life.
p.small.muted by Kiwibot, Lemoness, and SabreCat
h5 6/1/2015 - JUNE MYSTERY ITEM!
tr
td

View file

@ -0,0 +1,70 @@
div(ng-if='::task.type!="reward"')
button.advanced-options-toggle.option-title.mega(type='button',
ng-click='task._advanced = !task._advanced', tooltip=env.t('expandCollapse'))
=env.t('advancedOptions')
div(ng-show='task._advanced')
div(ng-if='::task.type == "daily"')
.form-group
legend.option-title
span.hint(popover-title=env.t('startDateHelpTitle'), popover=env.t("startDateHelp"), popover-trigger='mouseenter')
=env.t('startDate')
input.form-control(type='text', ng-model='task.startDate',
datepicker-popup='{{::user.preferences.dateFormat}}', is-open='datepickerOpened',
ng-click='datepickerOpened = true', ng-disabled='task.challenge.id')
hr
.form-group
legend.option-title=env.t('repeat')
select.form-control(ng-model='task.frequency', ng-disabled='task.challenge.id')
option(value='weekly')=env.t('repeatWeek')
option(value='daily')=env.t('repeatDays')
include ./dailies/repeat_options
hr
fieldset.option-group.advanced-option(ng-show="task._advanced")
legend.option-title
a.hint.priority-multiplier-help(href='http://habitrpg.wikia.com/wiki/Difficulty', target='_blank', popover-title=env.t('difficultyHelpTitle'), popover-trigger='mouseenter', popover=env.t('difficultyHelpContent'))=env.t('difficulty')
ul.priority-multiplier
li
button(type='button', ng-class='{active: task.priority==1 || !task.priority}',
ng-click='task.challenge.id || (task.priority=1)')
=env.t('easy')
li
button(type='button', ng-class='{active: task.priority==1.5}',
ng-click='task.challenge.id || (task.priority=1.5)')
=env.t('medium')
li
button(type='button', ng-class='{active: task.priority==2}',
ng-click='task.challenge.id || (task.priority=2)')
=env.t('hard')
span(ng-if='task.type=="daily"')
legend.option-title.pull-left=env.t('restoreStreak')
input.option-content(type='number', ng-model='task.streak')
div(ng-if='::(user.preferences.allocationMode == "taskbased" && user.preferences.automaticAllocation) || $state.is("options.social.challenges")')
legend.option-title.pull-left=env.t('attributes')
ul.task-attributes
li
button(type='button', ng-class='{active: task.attribute=="str"}',
ng-click='task.attribute="str"')
=env.t('physical')
li
button(type='button', ng-class='{active: task.attribute=="int"}',
ng-click='task.attribute="int"')
=env.t('mental')
li
button(type='button', ng-class='{active: task.attribute=="con"}',
ng-click='task.attribute="con"')
=env.t('social')
li
button(type='button', ng-class='{active: task.attribute=="per"}',
ng-click='task.attribute="per"',
popover=env.t('otherExamples'), popover-trigger='mouseenter', popover-placement='top')
=env.t('other')

View file

@ -0,0 +1,23 @@
.task-checklist-edit(ng-if='::!$state.includes("options.social.challenges") && (task.type=="daily" || task.type=="todo")')
ul
li
button(type='button', ng-if='!task.checklist[0]'
popover=env.t('checklistText'), popover-trigger='mouseenter', popover-placement='bottom',
ng-click='addChecklist(task)')
span.glyphicon.glyphicon-tasks
span=env.t('addChecklist')
.checklist-form(ng-if='task.checklist')
fieldset.option-group(ng-if='!$state.includes("options.social.challenges")')
legend.option-title(ng-if='task.checklist[0]')
span.hint(popover=env.t('checklistText'), popover-trigger='mouseenter', popover-placement='bottom')
=env.t('checklist')
ul(hrpg-sort-checklist)
li(ng-repeat='item in task.checklist')
//input(type='checkbox',ng-model='item.completed',ng-change='saveTask(task,true)')
//-,ng-blur='saveTask(task,true)')
span.checklist-icon.glyphicon.glyphicon-resize-vertical
input(type='text', ng-model='item.text',
ui-keyup="{'13':'addChecklistItem(task,$event,$index)','38 40':'navigateChecklist(task,$index,$event)'}")
a(ng-click='removeChecklistItem(task,$event,$index,true)')
span.glyphicon.glyphicon-trash(tooltip=env.t('delete'))

View file

@ -0,0 +1,3 @@
fieldset.option-group.calendar(ng-if='::task.type=="daily"', class="option-group")
.dailies
include ./repeat_options

View file

@ -0,0 +1,25 @@
legend.option-title=env.t('repeatEvery')
// If frequency is daily
ng-form.form-group(name='everyX' ng-if='task.frequency=="daily"')
.input-group
input.form-control(type='number', ng-model='task.everyX', ng-disabled='task.challenge.id', min='0', required)
span.input-group-addon {{task.everyX == 1 ? env.t('day') : env.t('days')}}
// If frequency is weekly
.form-group(ng-if='task.frequency=="weekly"')
ul.repeat-days
// note, does not use data-toggle="buttons-checkbox" - it would interfere with our own click binding
mixin dayOfWeek(day, num)
li
button(type='button', ng-class='{active: task.repeat.#{day}}',
ng-disabled='task.challenge.id', ng-click='task.repeat.#{day} = !task.repeat.#{day}')
| {{::moment.weekdaysMin(#{num})}}
+dayOfWeek('su', 0)
+dayOfWeek('m', 1)
+dayOfWeek('t', 2)
+dayOfWeek('w', 3)
+dayOfWeek('th', 4)
+dayOfWeek('f', 5)
+dayOfWeek('s', 6)

View file

@ -0,0 +1,8 @@
fieldset.option-group.plusminus(ng-if='task.type=="habit" && !task.challenge.id')
legend.option-title=env.t('direction/Actions')
span.task-checker
input.visuallyhidden.focusable(id='{{obj._id}}_{{task.id}}-option-plus', type='checkbox', ng-model='task.up')
label(for='{{obj._id}}_{{task.id}}-option-plus')
span.task-checker
input.visuallyhidden.focusable(id='{{obj._id}}_{{task.id}}-option-minus', type='checkbox', ng-model='task.down')
label(for='{{obj._id}}_{{task.id}}-option-minus')

View file

@ -0,0 +1,52 @@
div(ng-if='task._editing')
.task-options
// Broken Challenge
.well(ng-if='task.challenge.broken')
div(ng-if='task.challenge.broken=="TASK_DELETED"')
p=env.t('brokenTask')
p
a(ng-click='unlink(task, "keep")')=env.t('keepIt')
| &nbsp;&nbsp;
a(ng-click="removeTask(task, obj[list.type+'s'])")=env.t('removeIt')
div(ng-if='task.challenge.broken=="CHALLENGE_DELETED"')
p
|&nbsp;
=env.t('brokenChallenge')
p
a(ng-click='unlink(task, "keep-all")')=env.t('keepThem')
| &nbsp;|&nbsp;
a(ng-click='unlink(task, "remove-all")')=env.t('removeThem')
div(ng-if='task.challenge.broken=="CHALLENGE_CLOSED"')
p
!=env.t('challengeCompleted', {user: "{{task.challenge.winner}}"})
p
a(ng-click='unlink(task, "keep-all")')=env.t('keepThem')
| &nbsp;|&nbsp;
a(ng-click='unlink(task, "remove-all")')=env.t('removeThem')
//div(ng-if='task.challenge.broken=="UNSUBSCRIBED"')
p=env.t('unsubChallenge')
p
a(ng-click="unlink(task, 'keep-all')")=env.t('keepThem')
| &nbsp;|&nbsp;
a(ng-click="unlink(task, 'remove-all')")=env.t('removeThem')
include ./checklist
form(ng-submit='saveTask(task,false,true)')
include ./text_notes
include ./habits/plus_minus
include ./dailies/calendar
include ./rewards/pricing
include ./todos/due_date
include ./tags
include ./advanced_options
.save-close
button(type='submit')=env.t('saveAndClose')

View file

@ -0,0 +1,5 @@
fieldset.option-group.option-short(ng-if='task.type=="reward" && !task.challenge.id')
legend.option-title=env.t('price')
input.option-content(type='number', size='16', min='0', step='any', ng-model='task.value', required)
.money.input-suffix
span.shop_gold

View file

@ -0,0 +1,5 @@
fieldset.option-group(ng-if='!$state.includes("options.social.challenges")')
p.option-title.mega(ng-click='task._tags = !task._tags', tooltip=env.t('expandCollapse'))=env.t('tags')
label.checkbox(ng-repeat='tag in user.tags', ng-class="{visuallyhidden: task._tags}")
input(type='checkbox', ng-model='task.tags[tag.id]')
markdown(text='tag.name')

View file

@ -0,0 +1,7 @@
fieldset.option-group
label.option-title=env.t('text')
input.form-control(type='text', ng-model='task.text', required, ng-disabled='task.challenge.id')
fieldset.option-group
label.option-title=env.t('extraNotes')
textarea.form-control(rows='3', ng-model='task.notes', ng-model-options="{debounce: 1000}")

View file

@ -0,0 +1,6 @@
fieldset.option-group(ng-if='task.type=="todo" && !task.challenge.id')
legend.option-title=env.t('dueDate')
input.option-content.datepicker(type='text', ng-model='task.date',
datepicker-popup='{{::user.preferences.dateFormat}}', is-open='datepickerOpened',
ng-click='datepickerOpened = true')

View file

@ -0,0 +1,39 @@
// Note here, we need this part of Habit to be a directive since we're going to be passing it variables from various
// parts of the app. The alternative would be to create new scopes for different containing sections, but that
// started to get unwieldy
include ./task_view/mixins
script(id='templates/habitrpg-tasks.html', type="text/ng-template")
.tasks-lists.container-fluid
.row
.col-md-3.col-sm-6(ng-repeat='list in lists', ng-class='::{"rewards-module": list.type==="reward"}')
.task-column(class='{{::list.type}}s')
include ./task_view/graph
h2.task-column_title {{::list.header}}
include ./task_view/help
.todos-chart(ng-if='::list.type == "todo"', ng-show='charts.todos')
include ./task_view/add_new
alert.alert-warning.dailiesRestingInInn(ng-if='::list.type == "daily" && user.preferences.sleep')
i.glyphicon.glyphicon-warning-sign &nbsp;
=env.t('dailiesRestingInInn')
+taskColumnTabs('top')
// Actual List
ul(class='{{::list.type}}s main-list', ng-show='obj[list.type + "s"].length > 0', hrpg-sort-tasks, ng-if='!$state.includes("options.social.challenges")')
include ./task
//Loads the non-sortable lists for challenges
ul(class='{{::list.type}}s main-list', ng-show='obj[list.type + "s"].length > 0', ng-if='$state.includes("options.social.challenges")')
include ./task
include ./task_view/static_rewards
include ./task_view/spells
+taskColumnTabs('bottom')

View file

@ -1,188 +0,0 @@
// Note here, we need this part of Habit to be a directive since we're going to be passing it variables from various
// parts of the app. The alternative would be to create new scopes for different containing sections, but that
// started to get unwieldy
script(id='templates/habitrpg-tasks.html', type="text/ng-template")
.tasks-lists.container-fluid
.row
.col-md-3.col-sm-6(bindonce='lists', ng-repeat='list in lists', ng-class='::{"rewards-module": list.type==="reward"}')
.task-column(class='{{list.type}}s')
// Todos export/graph options
span.option-box.pull-right(ng-if='::main')
a.option-action(ng-if='list.type=="todo"', ng-show='obj.history.todos', ng-click='toggleChart("todos")', tooltip=env.t('progress'), style='margin-right:5px;')
span.glyphicon.glyphicon-signal
//a.option-action(ng-href='/v1/users/{{user.id}}/calendar.ics?apiToken={{user.apiToken}}', tooltip='iCal')
//-a.option-action(ng-if='list.type=="todo"', ng-click='notPorted()', tooltip='iCal', ng-show='false')
span.glyphicon.glyphicon-calendar
// <a href="https://www.google.com/calendar/render?cid={{encodeiCalLink(_user.id, _user.apiToken)}}" rel=tooltip title="Google Calendar"><i class=icon-calendar></i></a>
a.option-action(ng-click='list.help=!list.help', tooltip='Click for help')
span.glyphicon.glyphicon-question-sign(style={'zoom':1.5,'vertical-align':'-webkit-baseline-middle'})
// Header
h2.task-column_title
| {{list.header}}
div(ng-if='list.help', ng-switch='::list.type')
div(ng-switch-when='habit')
ul
li!=env.t('habitHelp1', {plusIcon:"<span class='glyphicon glyphicon-plus'></span>"})
li!=env.t('habitHelp2', {minusIcon:"<span class='glyphicon glyphicon-minus'></span>"})
li!=env.t('habitHelp3')
li!=env.t('newbieGuild', {linkStart:"<a href='https://habitrpg.com/#/options/groups/guilds/5481ccf3-5d2d-48a9-a871-70a7380cee5a' target='_blank'>", linkEnd: "</a>"})
div(ng-switch-when='daily')
ul
li!=env.t('dailyHelp1', {emphasisStart:"<strong>", emphasisEnd:"</strong>", pencilIcon:"<span class='glyphicon glyphicon-pencil'></span>"})
li=env.t('dailyHelp2')
li!=env.t('dailyHelp3', {emphasisStart:"<strong>", emphasisEnd:"</strong>"})
li!=env.t('dailyHelp4', {linkStart:"<a href='/#/options/settings/settings' target='_blank'>", linkEnd:"</a>"})
li!=env.t('dailyHelp5')
li!=env.t('newbieGuild', {linkStart:"<a href='https://habitrpg.com/#/options/groups/guilds/5481ccf3-5d2d-48a9-a871-70a7380cee5a' target='_blank'>", linkEnd: "</a>"})
div(ng-switch-when='todo')
ul
li=env.t('toDoHelp1')
li=env.t('toDoHelp2')
li=env.t('toDoHelp3')
li!=env.t('toDoHelp4')
li!=env.t('newbieGuild', {linkStart:"<a href='https://habitrpg.com/#/options/groups/guilds/5481ccf3-5d2d-48a9-a871-70a7380cee5a' target='_blank'>", linkEnd: "</a>"})
div(ng-switch-when='reward')
ul
li!=env.t('rewardHelp1', {linkStart:"<a href='/#/options/inventory/equipment' target='_blank'>", linkEnd: "</a>"})
li!=env.t('rewardHelp2', {linkStart:"<a href='/#/options/profile/stats' target='_blank'>", linkEnd: "</a>"})
li=env.t('rewardHelp3')
li!=env.t('rewardHelp4')
li!=env.t('newbieGuild', {linkStart:"<a href='https://habitrpg.com/#/options/groups/guilds/5481ccf3-5d2d-48a9-a871-70a7380cee5a' target='_blank'>", linkEnd: "</a>"})
// Todo Chart
.todos-chart(ng-if='::list.type == "todo"', ng-show='charts.todos')
// Add New
form.task-add(name='new{{list.type}}form', ng-hide='obj._locked', ng-submit='addTask(obj[list.type+"s"],list)' novalidate)
textarea(rows='6', task-focus='list.bulk && list.focus', ng-model='list.newTask', placeholder='{{list.placeHolderBulk}}', ng-if='list.bulk', ui-keydown='{"meta-enter ctrl-enter":"addTask(obj[list.type+\'s\'],list)"}', required)
input(type='text', task-focus='!list.bulk && list.focus', ng-model='list.newTask', placeholder='{{list.placeHolder}}', ng-if='!list.bulk', required)
button(type='submit', ng-disabled='new{{list.type}}form.$invalid')
div.empty-task-notification( ng-show='new{{list.type}}form.$invalid', tooltip=env.t("emptyTask") )
span.glyphicon.glyphicon-plus
span.glyphicon.glyphicon-plus(ng-show='!new{{list.type}}form.$invalid')
small.help-block.btn-link.pull-right(ng-click='toggleBulk(list)')
span(ng-if='!list.bulk')=env.t('addmultiple')
span(ng-if='list.bulk')=env.t('addsingle')
alert.alert-warning.dailiesRestingInInn(ng-if='::list.type == "daily" && user.preferences.sleep')
i.glyphicon.glyphicon-warning-sign &nbsp;
=env.t('dailiesRestingInInn')
mixin taskColumnTabs(position)
// Habits Tabs
div(ng-if='::main && list.type=="habit"', class='tabbable tabs-below')
ul.task-filter
li(ng-class='{active: list.view == "all"}')
a(ng-click='list.view = "all"')=env.t('all')
li(ng-class='{active: list.view == "yellowred"}')
a(ng-click='list.view = "yellowred"')=env.t('yellowred')
li(ng-class='{active: list.view == "greenblue"}')
a(ng-click='list.view = "greenblue"')=env.t('greenblue')
// Daily Tabs
div(ng-if='::main && list.type=="daily"', class='tabbable tabs-below')
// remaining/completed tabs
ul.task-filter
li(ng-class='{active: list.view == "all"}')
a(ng-click='list.view = "all"')=env.t('all')
li(ng-class='{active: list.view == "remaining"}')
a(ng-click='list.view = "remaining"')=env.t('due')
li(ng-class='{active: list.view == "complete"}')
a(ng-click='list.view = "complete"')=env.t('grey')
// Todo Tabs
div(ng-if='::main && list.type=="todo"', ng-class='::{"tabbable tabs-below": list.type=="todo"}')
if position=="bottom"
div(ng-show='list.view == "complete"')
.alert
=env.t('lotOfToDos')
button.task-action-btn.tile.spacious.bright(ng-click='user.ops.clearCompleted({})',popover=env.t('deleteToDosExplanation'),popover-trigger='mouseenter')=env.t('clearCompleted')
p!=env.t('beeminderDeleteWarning')
// remaining/completed tabs
ul.task-filter
li(ng-class='{active: list.view == "remaining"}')
a(ng-click='list.view = "remaining"')=env.t('remaining')
li(ng-class='{active: list.view == "dated"}')
a(ng-click='list.view = "dated"')=env.t('dated')
li(ng-class='{active: list.view == "complete"}')
a(ng-click='list.view = "complete"')=env.t('complete')
// Rewards Tabs
div(ng-if='::main && list.type=="reward"', class='tabbable tabs-below')
ul.task-filter
li(ng-class='{active: list.view == "all"}')
a(ng-click='list.view = "all"')=env.t('all')
li(ng-class='{active: list.view == "ingamerewards"}')
a(ng-click='list.view = "ingamerewards"')=env.t('ingamerewards')
+taskColumnTabs('top')
// Actual List
ul(class='{{list.type}}s main-list', ng-show='obj[list.type + "s"].length > 0', hrpg-sort-tasks, ng-if='!$state.includes("options.social.challenges")')
include ./task
//Loads the non-sortable lists for challenges
ul(class='{{list.type}}s main-list', ng-show='obj[list.type + "s"].length > 0', ng-if='$state.includes("options.social.challenges")')
include ./task
// Static Rewards
ul.items.rewards(ng-if='main && list.type=="reward"')
li.task.reward-item(ng-repeat='item in itemStore',popover-trigger='mouseenter', popover-placement='top', popover='{{item.key == "armoire" && !user.flags.armoireEmpty ? env.t("armoireNotesFull") + armoireCount(user.items.gear.owned) : item.notes()}}')
// right-hand side control buttons
.task-meta-controls
span.task-notes
span.glyphicon.glyphicon-comment
//left-hand size commands
.task-controls.task-primary
a.money.btn-buy.item-btn(ng-class='{highValue: item.value >= 1000}', ng-click='buy(item)')
span.shop_gold
span.reward-cost {{item.value}}
// main content
span(ng-class='::{"shop_{{item.key}} shop-sprite item-img": true}').reward-img
p.task-text {{item.text()}}
// Events
ul.items.rewards(ng-if='main && list.type=="reward" && (user.items.special.snowball>0 || user.stats.buffs.snowball || user.items.special.spookDust>0 || user.stats.buffs.spookDust || user.items.special.shinySeed>0 || user.stats.buffs.shinySeed)')
mixin specialSpell(k,canceler)
li.task.reward-item(ng-if='#{canceler ? "user.stats.buffs."+canceler : "user.items.special."+k+">0"}',popover-trigger='mouseenter', popover-placement='top', popover='{{Content.spells.special.#{k}.notes()}}')
.task-meta-controls
span.task-notes
span.glyphicon.glyphicon-comment
//left-hand size commands
.task-controls.task-primary
a.money.btn-buy.item-btn(ng-click='castStart(Content.spells.special.#{k})', ng-class='{active: Content.spells.special.#{k}.key == spell.key}')
if canceler
span.shop_gold
span.reward-cost {{Content.spells.special.#{k}.value}}
else
span.shop_spell(class='shop_#{k}')
span.reward-cost {{user.items.special.#{k}}}
// main content
p.task-text {{Content.spells.special.#{k}.text()}}
+specialSpell('snowball')
+specialSpell('spookDust')
+specialSpell('shinySeed')
+specialSpell('salt','snowball')
+specialSpell('opaquePotion','spookDust')
+specialSpell('petalFreePotion','shinySeed')
// Spells
ul.items(ng-if='main && list.type=="reward" && user.stats.class && !user.preferences.disableClasses')
li.task.reward-item(ng-repeat='(k,skill) in Content.spells[user.stats.class]', ng-if='user.stats.lvl >= skill.lvl',popover-trigger='mouseenter', popover-placement='top', popover='{{skill.notes()}}')
.task-meta-controls
span.task-notes
span.glyphicon.glyphicon-comment
//left-hand size commands
.task-controls.task-primary
a.money.btn-buy.item-btn(ng-click='castStart(skill)', ng-class='{active: skill.key == spell.key}')
span.reward-cost
strong {{skill.mana}}
=env.t('mp')
// main content
span(ng-class='{"shop_{{skill.key}} shop-sprite item-img": true}')
p.task-text {{skill.text()}}
br
+taskColumnTabs('bottom')

View file

@ -0,0 +1,56 @@
.task-meta-controls
// Due Date
span(ng-if='task.type=="todo" && task.date')
span(ng-class='{"label label-danger":(moment(task.date).isBefore(_today, "days") && !task.completed)}') {{task.date | date:(user.preferences.dateFormat.indexOf('yyyy') == 0 ? user.preferences.dateFormat.substr(5) : user.preferences.dateFormat.substr(0,5))}}
// Streak
| &nbsp;
span(ng-show='task.streak') {{task.streak}}&nbsp;
span(tooltip=env.t('streakCounter'))
span.glyphicon.glyphicon-forward
| &nbsp;
// Icons only available if you own the tasks (aka, hidden from challenge stats)
span(ng-if='!obj._locked')
a(ng-click='pushTask(task,$index,"top")', tooltip=env.t('pushTaskToTop'))
span.glyphicon.glyphicon-open
// a(ng-click='pushTask(task,$index,"bottom")', tooltip=env.t('pushTaskToBottom'))
// span.glyphicon.glyphicon-import
// // glyphicon-import or glyphicon-save or glyphicon-sort-by-attributes
a.badge(ng-if='task.checklist[0]', ng-class='{"badge-success":checklistCompletion(task.checklist) == task.checklist.length}', ng-click='collapseChecklist(task)', tooltip=env.t('expandCollapse'))
|{{checklistCompletion(task.checklist)}}/{{task.checklist.length}}
span.glyphicon.glyphicon-tags(tooltip='{{Shared.appliedTags(user.tags, task.tags)}}', ng-hide='Shared.noTags(task.tags)')
// edit
a(ng-hide='task._editing', ng-click='editTask(task)', tooltip=env.t('edit'))
| &nbsp;
span.glyphicon.glyphicon-pencil(ng-hide='task._editing')
| &nbsp;
a(ng-hide='!task._editing', ng-click='editTask(task)', tooltip=env.t('cancel'))
span.glyphicon.glyphicon-remove(ng-hide='!task._editing')
| &nbsp;
// save
a(ng-hide='!task._editing', ng-click='editTask(task);saveTask(task)', tooltip=env.t('save'))
span.glyphicon.glyphicon-ok(ng-hide='!task._editing')
| &nbsp;
//challenges
span(ng-if='task.challenge.id')
span(ng-if='task.challenge.broken')
span.glyphicon.glyphicon-bullhorn(style='background-color:red;', ng-click='task._editing = true', tooltip=env.t('brokenChaLink') tooltip-placement='right')
| &nbsp;
span(ng-if='!task.challenge.broken')
span.glyphicon.glyphicon-bullhorn(tooltip=env.t('challenge'))
| &nbsp;
// delete
a(ng-if='!task.challenge.id', ng-click='removeTask(task, obj[list.type+"s"])', tooltip=env.t('delete'))
span.glyphicon.glyphicon-trash
| &nbsp;
// chart
a(ng-show='task.history', ng-click='toggleChart(obj._id+task.id, task)', tooltip=env.t('progress'))
span.glyphicon.glyphicon-signal
| &nbsp;
// notes
span.task-notes(ng-show='task.notes && !task._editing', ng-click='task.popoverOpen = !task.popoverOpen', popover-trigger='click', data-popover-html="{{task.notes | markdown}}", popover-placement="top", popover-append-to-body='{{::modal ? "false":"true"}}')
span.glyphicon.glyphicon-comment
| &nbsp;

View file

@ -1,241 +1,17 @@
li(bindonce='list', id='task-{{::task.id}}', ng-repeat='task in obj[list.type+"s"] | conditionalOrderBy: list.view=="dated":"date"', class='task {{Shared.taskClasses(task, user.filters, user.preferences.dayStart, user.lastCron, list.showCompleted, main)}}', ng-click='spell && (list.type != "reward") && castEnd(task, "task", $event)', ng-class='{"cast-target":spell && (list.type != "reward"), "locked-task":obj._locked === true}', popover-trigger='mouseenter', data-popover-html="{{task.popoverOpen ? '' : task.notes | markdown}}", popover-placement="top", popover-append-to-body='{{::modal ? "false":"true"}}', ng-show='shouldShow(task, list, user.preferences)')
// right-hand side control buttons
.task-meta-controls
li(id='task-{{::task.id}}',
ng-repeat='task in obj[list.type+"s"] | filterByTextAndNotes: obj.filterQuery | conditionalOrderBy: list.view=="dated":"date"',
class='task {{Shared.taskClasses(task, user.filters, user.preferences.dayStart, user.lastCron, list.showCompleted, main)}}',
ng-class='{"cast-target":spell && (list.type != "reward"), "locked-task":obj._locked === true}',
ng-click='spell && (list.type != "reward") && castEnd(task, "task", $event)',
ng-show='shouldShow(task, list, user.preferences)',
popover-trigger='mouseenter', popover-placement="top", popover-append-to-body='{{::modal ? "false":"true"}}',
data-popover-html="{{task.popoverOpen ? '' : task.notes | markdown}}")
// Due Date
span(ng-if='task.type=="todo" && task.date')
span(ng-class='{"label label-danger":(moment(task.date).isBefore(_today, "days") && !task.completed)}') {{task.date | date:(user.preferences.dateFormat.indexOf('yyyy') == 0 ? user.preferences.dateFormat.substr(5) : user.preferences.dateFormat.substr(0,5))}}
ng-form(name='taskForm')
include ./meta_controls
// Streak
| &nbsp;
span(ng-show='task.streak') {{task.streak}}&nbsp;
span(tooltip=env.t('streakCounter'))
span.glyphicon.glyphicon-forward
| &nbsp;
include ./task_view/index
// Icons only available if you own the tasks (aka, hidden from challenge stats)
span(ng-if='!obj._locked')
a(ng-click='pushTask(task,$index,"top")', tooltip=env.t('pushTaskToTop'))
span.glyphicon.glyphicon-open
// a(ng-click='pushTask(task,$index,"bottom")', tooltip=env.t('pushTaskToBottom'))
// span.glyphicon.glyphicon-import
// // glyphicon-import or glyphicon-save or glyphicon-sort-by-attributes
a.badge(ng-if='task.checklist[0]', ng-class='{"badge-success":checklistCompletion(task.checklist) == task.checklist.length}', ng-click='collapseChecklist(task)', tooltip=env.t('expandCollapse'))
|{{checklistCompletion(task.checklist)}}/{{task.checklist.length}}
span.glyphicon.glyphicon-tags(tooltip='{{Shared.appliedTags(user.tags, task.tags)}}', ng-hide='Shared.noTags(task.tags)')
// edit
a(ng-hide='task._editing', ng-click='editTask(task)', tooltip=env.t('edit'))
| &nbsp;
span.glyphicon.glyphicon-pencil(ng-hide='task._editing')
| &nbsp;
a(ng-hide='!task._editing', ng-click='editTask(task)', tooltip=env.t('cancel'))
span.glyphicon.glyphicon-remove(ng-hide='!task._editing')
| &nbsp;
// save
a(ng-hide='!task._editing', ng-click='editTask(task);saveTask(task)', tooltip=env.t('save'))
span.glyphicon.glyphicon-ok(ng-hide='!task._editing')
| &nbsp;
//challenges
span(ng-if='task.challenge.id')
span(ng-if='task.challenge.broken')
span.glyphicon.glyphicon-bullhorn(style='background-color:red;', ng-click='task._editing = true', tooltip=env.t('brokenChaLink') tooltip-placement='right')
| &nbsp;
span(ng-if='!task.challenge.broken')
span.glyphicon.glyphicon-bullhorn(tooltip=env.t('challenge'))
| &nbsp;
// delete
a(ng-if='!task.challenge.id', ng-click='removeTask(task, obj[list.type+"s"])', tooltip=env.t('delete'))
span.glyphicon.glyphicon-trash
| &nbsp;
// chart
a(ng-show='task.history', ng-click='toggleChart(obj._id+task.id, task)', tooltip=env.t('progress'))
span.glyphicon.glyphicon-signal
| &nbsp;
// notes
span.task-notes(ng-show='task.notes && !task._editing', ng-click='task.popoverOpen = !task.popoverOpen', popover-trigger='click', data-popover-html="{{task.notes | markdown}}", popover-placement="top", popover-append-to-body='{{::modal ? "false":"true"}}')
span.glyphicon.glyphicon-comment
| &nbsp;
// left-hand side checkbox
.task-controls.task-primary(ng-if='!task._editing')
// Habits
.task-actions(ng-if='::task.type=="habit"')
// score() is overridden in challengesCtrl to do nothing
a(ng-if='task.up', ng-click='applyingAction || score(task,"up")')
span.glyphicon.glyphicon-plus
a(ng-if='task.down', ng-click='applyingAction || score(task,"down")')
span.glyphicon.glyphicon-minus
// Rewards
span(ng-show='task.type=="reward"')
a.money.btn-buy(ng-class='{highValue: task.value >= 1000}', ng-click='score(task, "down")')
span.shop_gold
span.reward-cost {{task.value}}
// Daily & Todos
span.task-checker.action-yesno(ng-if='::task.type=="daily" || task.type=="todo"')
input.visuallyhidden.focusable(ng-if='$state.includes("tasks")', id='box-{{obj._id}}_{{task.id}}', type='checkbox', ng-model='task.completed', ng-change='task.type=="todo" && pushTask(task,$index,"bottom"); changeCheck(task)')
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
div.task-text(ng-dblclick='task._editing ? saveTask(task) : editTask(task)')
markdown(text='task.text',target='_blank')
//-| {{task.text}}
div(ng-if='task.checklist && !$state.includes("options.social.challenges") && !task.collapseChecklist && !task._editing')
fieldset.option-group.task-checklist
label.checkbox(ng-repeat='item in task.checklist')
input(type='checkbox',ng-model='item.completed',ng-change='saveTask(task,true)')
markdown(text='item.text',target='_blank')
// edit/options dialog
div(ng-if='task._editing')
.task-options
// Broken Challenge
.well(ng-if='task.challenge.broken')
div(ng-if='task.challenge.broken=="TASK_DELETED"')
p=env.t('brokenTask')
p
a(ng-click='unlink(task, "keep")')=env.t('keepIt')
| &nbsp;&nbsp;
a(ng-click="removeTask(task, obj[list.type+'s'])")=env.t('removeIt')
div(ng-if='task.challenge.broken=="CHALLENGE_DELETED"')
p
|&nbsp;
=env.t('brokenChallenge')
p
a(ng-click='unlink(task, "keep-all")')=env.t('keepThem')
| &nbsp;|&nbsp;
a(ng-click='unlink(task, "remove-all")')=env.t('removeThem')
div(ng-if='task.challenge.broken=="CHALLENGE_CLOSED"')
p
!=env.t('challengeCompleted', {user: "{{task.challenge.winner}}"})
p
a(ng-click='unlink(task, "keep-all")')=env.t('keepThem')
| &nbsp;|&nbsp;
a(ng-click='unlink(task, "remove-all")')=env.t('removeThem')
//div(ng-if='task.challenge.broken=="UNSUBSCRIBED"')
p=env.t('unsubChallenge')
p
a(ng-click="unlink(task, 'keep-all')")=env.t('keepThem')
| &nbsp;|&nbsp;
a(ng-click="unlink(task, 'remove-all')")=env.t('removeThem')
form(ng-submit='saveTask(task,false,true)')
// Title text input
label.option-title=env.t('title')
input.option-content(type='text', ng-model='task.text', required, ng-disabled='task.challenge.id')
// Checklists
.task-checklist-edit(ng-if='!$state.includes("options.social.challenges")')
ul
li
button(type='button', ng-if='!task.checklist[0] && (task.type=="daily" || task.type=="todo")',ng-click='addChecklist(task)')
span.glyphicon.glyphicon-tasks
span=env.t('addChecklist')
form.checklist-form(ng-if='task.checklist')
fieldset.option-group(ng-if='!$state.includes("options.social.challenges")')
legend.option-title
span.hint(popover=env.t('checklistText'),popover-trigger='mouseenter',popover-placement='bottom')=env.t('checklist')
ul(hrpg-sort-checklist)
li(ng-repeat='item in task.checklist')
//input(type='checkbox',ng-model='item.completed',ng-change='saveTask(task,true)')
//-,ng-blur='saveTask(task,true)')
span.checklist-icon.glyphicon.glyphicon-resize-vertical()
input(type='text',ng-model='item.text', ui-keyup="{'13':'addChecklistItem(task,$event,$index)','38 40':'navigateChecklist(task,$index,$event)'}")
a(ng-click='removeChecklistItem(task,$event,$index,true)')
span.glyphicon.glyphicon-trash(tooltip=env.t('delete'))
form(ng-submit='saveTask(task,false,true)')
// Notes text input
fieldset.option-group
label.option-title=env.t('extraNotes')
textarea.option-content(rows='3', ng-model='task.notes', ng-model-options="{debounce: 1000}")
// if Habit, plus/minus command options
fieldset.option-group.plusminus(ng-if='task.type=="habit" && !task.challenge.id')
legend.option-title=env.t('direction/Actions')
span.task-checker
input.visuallyhidden.focusable(id='{{obj._id}}_{{task.id}}-option-plus', type='checkbox', ng-model='task.up')
label(for='{{obj._id}}_{{task.id}}-option-plus')
span.task-checker
input.visuallyhidden.focusable(id='{{obj._id}}_{{task.id}}-option-minus', type='checkbox', ng-model='task.down')
label(for='{{obj._id}}_{{task.id}}-option-minus')
// if Daily, calendar
fieldset(ng-if='::task.type=="daily"', class="option-group")
legend.option-title=env.t('repeat')
ul.repeat-days(bindonce)
// note, does not use data-toggle="buttons-checkbox" - it would interfere with our own click binding
li
button(ng-class='{active: task.repeat.su}', type='button', ng-click='task.challenge.id || (task.repeat.su = !task.repeat.su)') {{::moment.weekdaysMin(0)}}
li
button(ng-class='{active: task.repeat.m}', type='button', ng-click='task.challenge.id || (task.repeat.m = !task.repeat.m)') {{::moment.weekdaysMin(1)}}
li
button(ng-class='{active: task.repeat.t}', type='button', ng-click='task.challenge.id || (task.repeat.t = !task.repeat.t)') {{::moment.weekdaysMin(2)}}
li
button(ng-class='{active: task.repeat.w}', type='button', ng-click='task.challenge.id || (task.repeat.w = !task.repeat.w)') {{::moment.weekdaysMin(3)}}
li
button(ng-class='{active: task.repeat.th}', type='button', ng-click='task.challenge.id || (task.repeat.th = !task.repeat.th)') {{::moment.weekdaysMin(4)}}
li
button(ng-class='{active: task.repeat.f}', type='button', ng-click='task.challenge.id || (task.repeat.f= !task.repeat.f)') {{::moment.weekdaysMin(5)}}
li
button(ng-class='{active: task.repeat.s}', type='button', ng-click='task.challenge.id || (task.repeat.s = !task.repeat.s)') {{::moment.weekdaysMin(6)}}
// if Reward, pricing
fieldset.option-group.option-short(ng-if='task.type=="reward" && !task.challenge.id')
legend.option-title=env.t('price')
input.option-content(type='number', size='16', min='0', step="any", ng-model='task.value')
.money.input-suffix
span.shop_gold
// if Todos, the due date
fieldset.option-group(ng-if='task.type=="todo" && !task.challenge.id')
legend.option-title=env.t('dueDate')
input.option-content.datepicker(type='text', datepicker-popup='{{user.preferences.dateFormat}}', ng-model='task.date', is-open='datepickerOpened', ng-click='datepickerOpened = true')
// Tags
fieldset.option-group(ng-if='!$state.includes("options.social.challenges")')
p.option-title.mega(ng-click='task._tags = !task._tags', tooltip=env.t('expandCollapse'))=env.t('tags')
label.checkbox(ng-repeat='tag in user.tags', ng-class="{visuallyhidden: task._tags}")
input(type='checkbox', ng-model='task.tags[tag.id]')
markdown(text='tag.name')
// Advanced Options
span(ng-if='::task.type!="reward"')
p.option-title.mega(ng-click='task._advanced = !task._advanced', tooltip=env.t('expandCollapse'))=env.t('advancedOptions')
fieldset.option-group.advanced-option(ng-class="{visuallyhidden: task._advanced}")
legend.option-title
a.hint.priority-multiplier-help(href='http://habitrpg.wikia.com/wiki/Difficulty', target='_blank', popover-title=env.t('difficultyHelpTitle'), popover-trigger='mouseenter', popover=env.t('difficultyHelpContent'))=env.t('difficulty')
ul.priority-multiplier
li
button(type='button', ng-class='{active: task.priority==1 || !task.priority}', ng-click='task.challenge.id || (task.priority=1)')=env.t('easy')
li
button(type='button', ng-class='{active: task.priority==1.5}', ng-click='task.challenge.id || (task.priority=1.5)')=env.t('medium')
li
button(type='button', ng-class='{active: task.priority==2}', ng-click='task.challenge.id || (task.priority=2)')=env.t('hard')
//span(ng-if='task.type=="daily" && !task.challenge.id')
span(ng-if='task.type=="daily"')
legend.option-title.pull-left=env.t('restoreStreak')
input.option-content(type='number', ng-model='task.streak')
div(ng-if='(user.preferences.allocationMode == "taskbased" && user.preferences.automaticAllocation) || $state.is("options.social.challenges")')
legend.option-title.pull-left=env.t('attributes')
ul.task-attributes
li
button(type='button', ng-class='{active: task.attribute=="str"}', ng-click='task.attribute="str"')=env.t('physical')
li
button(type='button', ng-class='{active: task.attribute=="int"}', ng-click='task.attribute="int"')=env.t('mental')
li
button(type='button', ng-class='{active: task.attribute=="con"}', ng-click='task.attribute="con"')=env.t('social')
li
button(type='button', ng-class='{active: task.attribute=="per"}', ng-click='task.attribute="per"', popover=env.t('otherExamples'), popover-trigger='mouseenter', popover-placement='top')=env.t('other')
.save-close
button(type='submit')=env.t('saveAndClose')
include ./edit/index
div(class='{{obj._id}}{{task.id}}-chart', ng-show='charts[obj._id+task.id]')

View file

@ -0,0 +1,10 @@
form.task-add(name='new{{list.type}}form', ng-hide='obj._locked', ng-submit='addTask(obj[list.type+"s"],list)', novalidate)
textarea(rows='6', task-focus='list.bulk && list.focus', ng-model='list.newTask', placeholder='{{list.placeHolderBulk}}', ng-if='list.bulk', ui-keydown='{"meta-enter ctrl-enter":"addTask(obj[list.type+\'s\'],list)"}', required)
input(type='text', task-focus='!list.bulk && list.focus', ng-model='list.newTask', placeholder='{{list.placeHolder}}', ng-if='!list.bulk', required)
button(type='submit', ng-disabled='new{{list.type}}form.$invalid')
div.empty-task-notification( ng-show='new{{list.type}}form.$invalid', tooltip=env.t("emptyTask") )
span.glyphicon.glyphicon-plus
span.glyphicon.glyphicon-plus(ng-show='!new{{list.type}}form.$invalid')
small.help-block.btn-link.pull-right(ng-click='toggleBulk(list)')
span(ng-if='!list.bulk')=env.t('addmultiple')
span(ng-if='list.bulk')=env.t('addsingle')

View file

@ -0,0 +1,9 @@
span.option-box.pull-right(ng-if='::main')
a.option-action(ng-if='list.type=="todo"', ng-show='obj.history.todos', ng-click='toggleChart("todos")', tooltip=env.t('progress'), style='margin-right:5px;')
span.glyphicon.glyphicon-signal
//a.option-action(ng-href='/v1/users/{{user.id}}/calendar.ics?apiToken={{user.apiToken}}', tooltip='iCal')
//-a.option-action(ng-if='list.type=="todo"', ng-click='notPorted()', tooltip='iCal', ng-show='false')
span.glyphicon.glyphicon-calendar
// <a href="https://www.google.com/calendar/render?cid={{encodeiCalLink(_user.id, _user.apiToken)}}" rel=tooltip title="Google Calendar"><i class=icon-calendar></i></a>
a.option-action(ng-click='list.help=!list.help', tooltip=env.t('clickForHelp'))
span.glyphicon.glyphicon-question-sign(style={'zoom':1.5,'vertical-align':'-webkit-baseline-middle'})

View file

@ -0,0 +1,25 @@
div(ng-if='list.help', ng-switch='::list.type')
ul(ng-switch-when='habit')
li!=env.t('habitHelp1', {plusIcon:"<span class='glyphicon glyphicon-plus'></span>"})
li!=env.t('habitHelp2', {minusIcon:"<span class='glyphicon glyphicon-minus'></span>"})
li!=env.t('habitHelp3')
li!=env.t('newbieGuild', {linkStart:"<a href='https://habitrpg.com/#/options/groups/guilds/5481ccf3-5d2d-48a9-a871-70a7380cee5a' target='_blank'>", linkEnd: "</a>"})
ul(ng-switch-when='daily')
li!=env.t('dailyHelp1', {emphasisStart:"<strong>", emphasisEnd:"</strong>", pencilIcon:"<span class='glyphicon glyphicon-pencil'></span>"})
li=env.t('dailyHelp2')
li!=env.t('dailyHelp3', {emphasisStart:"<strong>", emphasisEnd:"</strong>"})
li!=env.t('dailyHelp4', {linkStart:"<a href='/#/options/settings/settings' target='_blank'>", linkEnd:"</a>"})
li!=env.t('dailyHelp5')
li!=env.t('newbieGuild', {linkStart:"<a href='https://habitrpg.com/#/options/groups/guilds/5481ccf3-5d2d-48a9-a871-70a7380cee5a' target='_blank'>", linkEnd: "</a>"})
ul(ng-switch-when='todo')
li=env.t('toDoHelp1')
li=env.t('toDoHelp2')
li=env.t('toDoHelp3')
li!=env.t('toDoHelp4')
li!=env.t('newbieGuild', {linkStart:"<a href='https://habitrpg.com/#/options/groups/guilds/5481ccf3-5d2d-48a9-a871-70a7380cee5a' target='_blank'>", linkEnd: "</a>"})
ul(ng-switch-when='reward')
li!=env.t('rewardHelp1', {linkStart:"<a href='/#/options/inventory/equipment' target='_blank'>", linkEnd: "</a>"})
li!=env.t('rewardHelp2', {linkStart:"<a href='/#/options/profile/stats' target='_blank'>", linkEnd: "</a>"})
li=env.t('rewardHelp3')
li!=env.t('rewardHelp4')
li!=env.t('newbieGuild', {linkStart:"<a href='https://habitrpg.com/#/options/groups/guilds/5481ccf3-5d2d-48a9-a871-70a7380cee5a' target='_blank'>", linkEnd: "</a>"})

View file

@ -0,0 +1,35 @@
// left-hand side checkbox
.task-controls.task-primary(ng-if='!task._editing')
// Habits
.task-actions(ng-if='::task.type=="habit"')
// score() is overridden in challengesCtrl to do nothing
a(ng-if='task.up', ng-click='applyingAction || score(task,"up")')
span.glyphicon.glyphicon-plus
a(ng-if='task.down', ng-click='applyingAction || score(task,"down")')
span.glyphicon.glyphicon-minus
// Rewards
span(ng-if='::task.type=="reward"')
a.money.btn-buy(ng-class='{highValue: task.value >= 1000}', ng-click='score(task, "down")')
span.shop_gold
span.reward-cost {{task.value}}
// Daily & Todos
span.task-checker.action-yesno(ng-if='::task.type=="daily" || task.type=="todo"')
input.visuallyhidden.focusable(id='box-{{::obj._id}}_{{::task.id}}', type='checkbox',
ng-model='task.completed', ng-if='$state.includes("tasks")',
ng-change='task.type=="todo" && pushTask(task,$index,"bottom"); changeCheck(task)')
input.visuallyhidden.focusable(id='box-{{::obj._id}}_{{::task.id}}', type='checkbox',
ng-if='!$state.includes("tasks")')
label(for='box-{{::obj._id}}_{{::task.id}}')
// main content
.task-text(ng-dblclick='task._editing ? saveTask(task) : editTask(task)')
markdown(text='task.text',target='_blank')
div(ng-if='task.checklist && !$state.includes("options.social.challenges") && !task.collapseChecklist && !task._editing')
fieldset.option-group.task-checklist
label.checkbox(ng-repeat='item in task.checklist')
input(type='checkbox', ng-model='item.completed', ng-change='saveTask(task,true)')
markdown(text='item.text', target='_blank')

Some files were not shown because too many files have changed in this diff Show more