diff --git a/website/views/index.jade b/website/views/index.jade
index cf70ebccdf..52d464c1b0 100644
--- a/website/views/index.jade
+++ b/website/views/index.jade
@@ -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
diff --git a/website/views/shared/tasks/edit/advanced_options.jade b/website/views/shared/tasks/edit/advanced_options.jade
new file mode 100644
index 0000000000..c757330adb
--- /dev/null
+++ b/website/views/shared/tasks/edit/advanced_options.jade
@@ -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=env.t('startDate')
+ .input-group
+ input.form-control(type='text', ng-model='task._tempDateForPicker' datepicker-popup
+ ng-change='updateTaskStartDate(task)' is-open='task._isDatePickerOpen')
+ span.input-group-btn
+ button.btn.btn-default(type='button' ng-click='openDatePicker($event, task)')
+ .glyphicon.glyphicon-calendar
+
+ hr
+
+ .form-group
+ legend.option-title=env.t('repeat')
+ select.form-control(ng-model='task.frequency')
+ 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" && !task.challenge.id')
+ 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')
diff --git a/website/views/shared/tasks/edit/checklist.jade b/website/views/shared/tasks/edit/checklist.jade
new file mode 100644
index 0000000000..2d5b9c347d
--- /dev/null
+++ b/website/views/shared/tasks/edit/checklist.jade
@@ -0,0 +1,22 @@
+.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'))
diff --git a/website/views/shared/tasks/edit/dailies/calendar.jade b/website/views/shared/tasks/edit/dailies/calendar.jade
new file mode 100644
index 0000000000..0ffb033acb
--- /dev/null
+++ b/website/views/shared/tasks/edit/dailies/calendar.jade
@@ -0,0 +1,3 @@
+fieldset.option-group.calendar(ng-if='::task.type=="daily"', class="option-group")
+ .dailies
+ include ./repeat_options
diff --git a/website/views/shared/tasks/edit/dailies/repeat_options.jade b/website/views/shared/tasks/edit/dailies/repeat_options.jade
new file mode 100644
index 0000000000..1e57ac7c6a
--- /dev/null
+++ b/website/views/shared/tasks/edit/dailies/repeat_options.jade
@@ -0,0 +1,27 @@
+legend.option-title=env.t('repeatEvery')
+
+// If frequency is daily
+.form-group(ng-if='task.frequency=="daily"')
+ .input-group
+ input.form-control(type='number', ng-model='task.everyX', min='1')
+ span.input-group-addon {{task.everyX == 1 ? env.t('day') : env.t('days')}}
+
+// If frequency is weekly
+.form-group(ng-show='task.frequency=="weekly"')
+
+ 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)}}
diff --git a/website/views/shared/tasks/edit/habits/plus_minus.jade b/website/views/shared/tasks/edit/habits/plus_minus.jade
new file mode 100644
index 0000000000..bbe17b7d4e
--- /dev/null
+++ b/website/views/shared/tasks/edit/habits/plus_minus.jade
@@ -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')
diff --git a/website/views/shared/tasks/edit/index.jade b/website/views/shared/tasks/edit/index.jade
new file mode 100644
index 0000000000..ce29ee8896
--- /dev/null
+++ b/website/views/shared/tasks/edit/index.jade
@@ -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')
+ |
+ a(ng-click="removeTask(task, obj[list.type+'s'])")=env.t('removeIt')
+ div(ng-if='task.challenge.broken=="CHALLENGE_DELETED"')
+ p
+ |
+ =env.t('brokenChallenge')
+ p
+ a(ng-click='unlink(task, "keep-all")')=env.t('keepThem')
+ | |
+ 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')
+ | |
+ 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')
+ | |
+ 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')
diff --git a/website/views/shared/tasks/edit/rewards/pricing.jade b/website/views/shared/tasks/edit/rewards/pricing.jade
new file mode 100644
index 0000000000..ff07223072
--- /dev/null
+++ b/website/views/shared/tasks/edit/rewards/pricing.jade
@@ -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')
+ .money.input-suffix
+ span.shop_gold
diff --git a/website/views/shared/tasks/edit/tags.jade b/website/views/shared/tasks/edit/tags.jade
new file mode 100644
index 0000000000..ab512731fd
--- /dev/null
+++ b/website/views/shared/tasks/edit/tags.jade
@@ -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')
diff --git a/website/views/shared/tasks/edit/text_notes.jade b/website/views/shared/tasks/edit/text_notes.jade
new file mode 100644
index 0000000000..72cddbd59c
--- /dev/null
+++ b/website/views/shared/tasks/edit/text_notes.jade
@@ -0,0 +1,6 @@
+fieldset.option-group
+ label.option-title=env.t('text')
+ input.option-content(type='text', ng-model='task.text', required, ng-disabled='task.challenge.id')
+
+ label.option-title=env.t('extraNotes')
+ textarea.option-content(rows='3', ng-model='task.notes', ng-model-options="{debounce: 1000}")
diff --git a/website/views/shared/tasks/edit/todos/due_date.jade b/website/views/shared/tasks/edit/todos/due_date.jade
new file mode 100644
index 0000000000..32b081a610
--- /dev/null
+++ b/website/views/shared/tasks/edit/todos/due_date.jade
@@ -0,0 +1,4 @@
+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')
+
diff --git a/website/views/shared/tasks/index.jade b/website/views/shared/tasks/index.jade
new file mode 100644
index 0000000000..31dd35bd42
--- /dev/null
+++ b/website/views/shared/tasks/index.jade
@@ -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
+ =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')
diff --git a/website/views/shared/tasks/lists.jade b/website/views/shared/tasks/lists.jade
deleted file mode 100644
index 73567ff2cc..0000000000
--- a/website/views/shared/tasks/lists.jade
+++ /dev/null
@@ -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.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:""})
- li!=env.t('habitHelp2', {minusIcon:""})
- li!=env.t('habitHelp3')
- li!=env.t('newbieGuild', {linkStart:"", linkEnd: ""})
- div(ng-switch-when='daily')
- ul
- li!=env.t('dailyHelp1', {emphasisStart:"", emphasisEnd:"", pencilIcon:""})
- li!=env.t('dailyHelp2')
- li!=env.t('dailyHelp3', {emphasisStart:"", emphasisEnd:""})
- li!=env.t('dailyHelp4', {linkStart:"", linkEnd:""})
- li!=env.t('dailyHelp5')
- li!=env.t('newbieGuild', {linkStart:"", linkEnd: ""})
- 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:"", linkEnd: ""})
- div(ng-switch-when='reward')
- ul
- li!=env.t('rewardHelp1', {linkStart:"", linkEnd: ""})
- li!=env.t('rewardHelp2', {linkStart:"", linkEnd: ""})
- li!=env.t('rewardHelp3')
- li!=env.t('rewardHelp4')
- li!=env.t('newbieGuild', {linkStart:"", linkEnd: ""})
-
- // 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)')
- 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
- =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.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')
diff --git a/website/views/shared/tasks/meta_controls.jade b/website/views/shared/tasks/meta_controls.jade
new file mode 100644
index 0000000000..acff83ef6f
--- /dev/null
+++ b/website/views/shared/tasks/meta_controls.jade
@@ -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
+ |
+ span(ng-show='task.streak') {{task.streak}}
+ span(tooltip=env.t('streakCounter'))
+ span.glyphicon.glyphicon-forward
+ |
+
+ // 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'))
+ |
+ span.glyphicon.glyphicon-pencil(ng-hide='task._editing')
+ |
+ a(ng-hide='!task._editing', ng-click='editTask(task)', tooltip=env.t('cancel'))
+ span.glyphicon.glyphicon-remove(ng-hide='!task._editing')
+ |
+ // save
+ a(ng-hide='!task._editing', ng-click='editTask(task);saveTask(task)', tooltip=env.t('save'))
+ span.glyphicon.glyphicon-ok(ng-hide='!task._editing')
+ |
+ //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')
+ |
+ span(ng-if='!task.challenge.broken')
+ span.glyphicon.glyphicon-bullhorn(tooltip=env.t('challenge'))
+ |
+ // delete
+ a(ng-if='!task.challenge.id', ng-click='removeTask(task, obj[list.type+"s"])', tooltip=env.t('delete'))
+ span.glyphicon.glyphicon-trash
+ |
+
+ // chart
+ a(ng-show='task.history', ng-click='toggleChart(obj._id+task.id, task)', tooltip=env.t('progress'))
+ span.glyphicon.glyphicon-signal
+ |
+ // 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
+ |
diff --git a/website/views/shared/tasks/task.jade b/website/views/shared/tasks/task.jade
index 5bcde72d00..1ee6d90a74 100644
--- a/website/views/shared/tasks/task.jade
+++ b/website/views/shared/tasks/task.jade
@@ -1,278 +1,16 @@
-mixin repeatOptions
- legend.option-title=env.t('repeatEvery')
+li(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-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}}")
- // If frequency is daily
- .form-group(ng-if='task.frequency=="daily"')
- .input-group
- input.form-control(type='number', ng-model='task.everyX', min='1')
- span.input-group-addon {{task.everyX == 1 ? env.t('day') : env.t('days')}}
+ include ./meta_controls
- // If frequency is weekly
- .form-group(ng-show='task.frequency=="weekly"')
+ include ./task_view/index
- 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)}}
-
-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
-
- // 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
- |
- span(ng-show='task.streak') {{task.streak}}
- span(tooltip=env.t('streakCounter'))
- span.glyphicon.glyphicon-forward
- |
-
- // 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'))
- |
- span.glyphicon.glyphicon-pencil(ng-hide='task._editing')
- |
- a(ng-hide='!task._editing', ng-click='editTask(task)', tooltip=env.t('cancel'))
- span.glyphicon.glyphicon-remove(ng-hide='!task._editing')
- |
- // save
- a(ng-hide='!task._editing', ng-click='editTask(task);saveTask(task)', tooltip=env.t('save'))
- span.glyphicon.glyphicon-ok(ng-hide='!task._editing')
- |
- //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')
- |
- span(ng-if='!task.challenge.broken')
- span.glyphicon.glyphicon-bullhorn(tooltip=env.t('challenge'))
- |
- // delete
- a(ng-if='!task.challenge.id', ng-click='removeTask(task, obj[list.type+"s"])', tooltip=env.t('delete'))
- span.glyphicon.glyphicon-trash
- |
-
- // chart
- a(ng-show='task.history', ng-click='toggleChart(obj._id+task.id, task)', tooltip=env.t('progress'))
- span.glyphicon.glyphicon-signal
- |
- // 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
- |
-
- // 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')
- |
- a(ng-click="removeTask(task, obj[list.type+'s'])")=env.t('removeIt')
- div(ng-if='task.challenge.broken=="CHALLENGE_DELETED"')
- p
- |
- =env.t('brokenChallenge')
- p
- a(ng-click='unlink(task, "keep-all")')=env.t('keepThem')
- | |
- 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')
- | |
- 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')
- | |
- a(ng-click="unlink(task, 'remove-all')")=env.t('removeThem')
-
- // 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)')
- // text & notes
- fieldset.option-group
- label.option-title=env.t('text')
- input.option-content(type='text', ng-model='task.text', required, ng-disabled='task.challenge.id')
-
- 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.option-group.calendar(ng-if='::task.type=="daily"', class="option-group")
- .dailies
- +repeatOptions
-
-
- // 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"')
- 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=env.t('startDate')
- .input-group
- input(type='text' class='form-control' datepicker-popup ng-model='task._tempDateForPicker' ng-change='updateTaskStartDate(task)' is-open='task._isDatePickerOpen')
- span.input-group-btn
- button.btn.btn-default(type='button' ng-click='openDatePicker($event, task)')
- .glyphicon.glyphicon-calendar
-
- hr
-
- .form-group
- legend.option-title=env.t('repeat')
- select.form-control(ng-model='task.frequency')
- option(value='weekly')=env.t('repeatWeek')
- option(value='daily')=env.t('repeatDays')
-
- +repeatOptions
-
- 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" && !task.challenge.id')
- 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]')
diff --git a/website/views/shared/tasks/task_view/add_new.jade b/website/views/shared/tasks/task_view/add_new.jade
new file mode 100644
index 0000000000..ef214d5ce1
--- /dev/null
+++ b/website/views/shared/tasks/task_view/add_new.jade
@@ -0,0 +1,10 @@
+form.task-add(name='new{{list.type}}form', ng-hide='obj._locked', ng-submit='addTask(obj[list.type+"s"],list)')
+ 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')
diff --git a/website/views/shared/tasks/task_view/graph.jade b/website/views/shared/tasks/task_view/graph.jade
new file mode 100644
index 0000000000..2ccc3cae1c
--- /dev/null
+++ b/website/views/shared/tasks/task_view/graph.jade
@@ -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.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'})
diff --git a/website/views/shared/tasks/task_view/help.jade b/website/views/shared/tasks/task_view/help.jade
new file mode 100644
index 0000000000..609aad5bc9
--- /dev/null
+++ b/website/views/shared/tasks/task_view/help.jade
@@ -0,0 +1,25 @@
+div(ng-if='list.help', ng-switch='::list.type')
+ ul(ng-switch-when='habit')
+ li!=env.t('habitHelp1', {plusIcon:""})
+ li!=env.t('habitHelp2', {minusIcon:""})
+ li!=env.t('habitHelp3')
+ li!=env.t('newbieGuild', {linkStart:"", linkEnd: ""})
+ ul(ng-switch-when='daily')
+ li!=env.t('dailyHelp1', {emphasisStart:"", emphasisEnd:"", pencilIcon:""})
+ li!=env.t('dailyHelp2')
+ li!=env.t('dailyHelp3', {emphasisStart:"", emphasisEnd:""})
+ li!=env.t('dailyHelp4', {linkStart:"", linkEnd:""})
+ li!=env.t('dailyHelp5')
+ li!=env.t('newbieGuild', {linkStart:"", linkEnd: ""})
+ 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:"", linkEnd: ""})
+ ul(ng-switch-when='reward')
+ li!=env.t('rewardHelp1', {linkStart:"", linkEnd: ""})
+ li!=env.t('rewardHelp2', {linkStart:"", linkEnd: ""})
+ li!=env.t('rewardHelp3')
+ li!=env.t('rewardHelp4')
+ li!=env.t('newbieGuild', {linkStart:"", linkEnd: ""})
diff --git a/website/views/shared/tasks/task_view/index.jade b/website/views/shared/tasks/task_view/index.jade
new file mode 100644
index 0000000000..f15490969d
--- /dev/null
+++ b/website/views/shared/tasks/task_view/index.jade
@@ -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')
diff --git a/website/views/shared/tasks/task_view/mixins.jade b/website/views/shared/tasks/task_view/mixins.jade
new file mode 100644
index 0000000000..775f194a76
--- /dev/null
+++ b/website/views/shared/tasks/task_view/mixins.jade
@@ -0,0 +1,60 @@
+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')
+
+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()}}
diff --git a/website/views/shared/tasks/task_view/spells.jade b/website/views/shared/tasks/task_view/spells.jade
new file mode 100644
index 0000000000..9360b0e656
--- /dev/null
+++ b/website/views/shared/tasks/task_view/spells.jade
@@ -0,0 +1,25 @@
+// 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)')
+
+ +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()}}
diff --git a/website/views/shared/tasks/task_view/static_rewards.jade b/website/views/shared/tasks/task_view/static_rewards.jade
new file mode 100644
index 0000000000..3f2b5f3b51
--- /dev/null
+++ b/website/views/shared/tasks/task_view/static_rewards.jade
@@ -0,0 +1,14 @@
+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.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()}}