2013-02-08 22:44:06 +00:00
|
|
|
scoring = require './scoring'
|
|
|
|
|
helpers = require './helpers'
|
|
|
|
|
_ = require 'underscore'
|
|
|
|
|
moment = require 'moment'
|
2013-03-18 00:30:54 +00:00
|
|
|
character = require './character'
|
2013-02-08 22:44:06 +00:00
|
|
|
|
|
|
|
|
module.exports.app = (appExports, model) ->
|
|
|
|
|
user = model.at('_user')
|
|
|
|
|
|
|
|
|
|
appExports.addTask = (e, el, next) ->
|
|
|
|
|
type = $(el).attr('data-task-type')
|
|
|
|
|
list = model.at "_#{type}List"
|
|
|
|
|
newModel = model.at('_new' + type.charAt(0).toUpperCase() + type.slice(1))
|
|
|
|
|
text = newModel.get()
|
2013-02-20 21:29:06 +00:00
|
|
|
# Don't add a blank task; 20/02/13 Added a check for undefined value, more at issue #463 -lancemanfv
|
|
|
|
|
if /^(\s)*$/.test(text) || text == undefined
|
2013-02-11 18:12:15 +00:00
|
|
|
console.error "Task text entered was an empty string."
|
|
|
|
|
return
|
2013-02-08 22:44:06 +00:00
|
|
|
|
|
|
|
|
newModel.set ''
|
|
|
|
|
switch type
|
|
|
|
|
|
|
|
|
|
when 'habit'
|
2013-02-11 06:27:52 +00:00
|
|
|
list.unshift {type: type, text: text, notes: '', value: 0, up: true, down: true}
|
2013-02-08 22:44:06 +00:00
|
|
|
|
|
|
|
|
when 'reward'
|
2013-02-11 06:27:52 +00:00
|
|
|
list.unshift {type: type, text: text, notes: '', value: 20 }
|
2013-02-08 22:44:06 +00:00
|
|
|
|
|
|
|
|
when 'daily'
|
2013-02-11 06:27:52 +00:00
|
|
|
list.unshift {type: type, text: text, notes: '', value: 0, repeat:{su:true,m:true,t:true,w:true,th:true,f:true,s:true}, completed: false }
|
2013-02-08 22:44:06 +00:00
|
|
|
|
|
|
|
|
when 'todo'
|
2013-02-11 06:27:52 +00:00
|
|
|
list.unshift {type: type, text: text, notes: '', value: 0, completed: false }
|
2013-02-08 22:44:06 +00:00
|
|
|
|
|
|
|
|
# list.on 'set', '*.completed', (i, completed, previous, isLocal) ->
|
|
|
|
|
# # Move the item to the bottom if it was checked off
|
|
|
|
|
# list.move i, -1 if completed && isLocal
|
|
|
|
|
|
|
|
|
|
appExports.del = (e, el) ->
|
|
|
|
|
# Derby extends model.at to support creation from DOM nodes
|
2013-03-18 02:09:33 +00:00
|
|
|
task = e.at()
|
2013-02-09 15:45:00 +00:00
|
|
|
id = task.get('id')
|
2013-02-08 22:44:06 +00:00
|
|
|
|
|
|
|
|
history = task.get('history')
|
|
|
|
|
if history and history.length>2
|
|
|
|
|
# prevent delete-and-recreate hack on red tasks
|
|
|
|
|
if task.get('value') < 0
|
|
|
|
|
result = confirm("Are you sure? Deleting this task will hurt you (to prevent deleting, then re-creating red tasks).")
|
|
|
|
|
if result != true
|
|
|
|
|
return # Cancel. Don't delete, don't hurt user
|
|
|
|
|
else
|
|
|
|
|
task.set('type','habit') # hack to make sure it hits HP, instead of performing "undo checkbox"
|
2013-03-03 04:38:31 +00:00
|
|
|
scoring.score(model, id, direction:'down')
|
2013-02-08 22:44:06 +00:00
|
|
|
|
|
|
|
|
# prevent accidently deleting long-standing tasks
|
|
|
|
|
else
|
|
|
|
|
result = confirm("Are you sure you want to delete this task?")
|
|
|
|
|
return if result != true
|
|
|
|
|
|
|
|
|
|
#TODO bug where I have to delete from _users.tasks AND _{type}List,
|
|
|
|
|
# fix when query subscriptions implemented properly
|
|
|
|
|
$('[rel=tooltip]').tooltip('hide')
|
|
|
|
|
|
|
|
|
|
user.del('tasks.'+id)
|
2013-02-09 15:45:00 +00:00
|
|
|
task.remove()
|
2013-02-08 22:44:06 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
appExports.clearCompleted = (e, el) ->
|
2013-02-09 01:48:31 +00:00
|
|
|
todoIds = user.get('todoIds')
|
2013-02-08 22:44:06 +00:00
|
|
|
removed = false
|
|
|
|
|
_.each model.get('_todoList'), (task) ->
|
|
|
|
|
if task.completed
|
|
|
|
|
removed = true
|
|
|
|
|
user.del('tasks.'+task.id)
|
|
|
|
|
todoIds.splice(todoIds.indexOf(task.id), 1)
|
|
|
|
|
if removed
|
2013-02-09 01:48:31 +00:00
|
|
|
user.set('todoIds', todoIds)
|
2013-02-08 22:44:06 +00:00
|
|
|
|
|
|
|
|
appExports.toggleDay = (e, el) ->
|
|
|
|
|
task = model.at(e.target)
|
|
|
|
|
if /active/.test($(el).attr('class')) # previous state, not current
|
|
|
|
|
task.set('repeat.' + $(el).attr('data-day'), false)
|
|
|
|
|
else
|
|
|
|
|
task.set('repeat.' + $(el).attr('data-day'), true)
|
|
|
|
|
|
|
|
|
|
appExports.toggleTaskEdit = (e, el) ->
|
|
|
|
|
hideId = $(el).attr('data-hide-id')
|
|
|
|
|
toggleId = $(el).attr('data-toggle-id')
|
2013-03-06 03:19:20 +00:00
|
|
|
$(document.getElementById(hideId)).addClass('visuallyhidden')
|
|
|
|
|
$(document.getElementById(toggleId)).toggleClass('visuallyhidden')
|
2013-02-08 22:44:06 +00:00
|
|
|
|
|
|
|
|
appExports.toggleChart = (e, el) ->
|
|
|
|
|
hideSelector = $(el).attr('data-hide-id')
|
|
|
|
|
chartSelector = $(el).attr('data-toggle-id')
|
|
|
|
|
historyPath = $(el).attr('data-history-path')
|
|
|
|
|
$(document.getElementById(hideSelector)).hide()
|
|
|
|
|
$(document.getElementById(chartSelector)).toggle()
|
|
|
|
|
|
|
|
|
|
matrix = [['Date', 'Score']]
|
|
|
|
|
for obj in model.get(historyPath)
|
|
|
|
|
date = +new Date(obj.date)
|
|
|
|
|
readableDate = moment(date).format('MM/DD')
|
|
|
|
|
matrix.push [ readableDate, obj.value ]
|
|
|
|
|
data = google.visualization.arrayToDataTable matrix
|
|
|
|
|
|
|
|
|
|
options = {
|
2013-03-09 19:06:53 +00:00
|
|
|
title: 'History'
|
2013-03-21 22:31:23 +00:00
|
|
|
backgroundColor: { fill:'transparent' }
|
2013-02-08 22:44:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
chart = new google.visualization.LineChart(document.getElementById( chartSelector ))
|
|
|
|
|
chart.draw(data, options)
|
|
|
|
|
|
2013-02-09 15:45:00 +00:00
|
|
|
appExports.changeContext = (e, el) ->
|
|
|
|
|
# Get the data from the element
|
|
|
|
|
targetSelector = $(el).attr('data-target')
|
|
|
|
|
newContext = $(el).attr('data-context')
|
|
|
|
|
newActiveNav = $(el).parent('li')
|
|
|
|
|
|
|
|
|
|
# If the clicked nav is already active, do nothing
|
|
|
|
|
if newActiveNav.hasClass('active')
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
# Find the old active nav and context
|
|
|
|
|
oldActiveNav = $(el).closest('ul').find('> .active')
|
|
|
|
|
oldContext = oldActiveNav.find('a').attr('data-context')
|
|
|
|
|
|
|
|
|
|
# Set the new active nav
|
|
|
|
|
oldActiveNav.removeClass('active')
|
|
|
|
|
newActiveNav.addClass('active')
|
|
|
|
|
|
|
|
|
|
# Set the new context on the target
|
|
|
|
|
target = $(targetSelector)
|
|
|
|
|
target.removeClass(oldContext)
|
|
|
|
|
target.addClass(newContext)
|
|
|
|
|
|
2013-03-18 00:30:54 +00:00
|
|
|
|
2013-03-18 03:15:19 +00:00
|
|
|
setUndo = (stats, task) ->
|
|
|
|
|
previousUndo = model.get('_undo')
|
|
|
|
|
clearTimeout(previousUndo.timeoutId) if previousUndo?.timeoutId
|
|
|
|
|
timeoutId = setTimeout (-> model.del('_undo')), 10000
|
|
|
|
|
model.set '_undo', {stats:stats, task:task, timeoutId: timeoutId}
|
2013-03-18 00:30:54 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
###
|
|
|
|
|
Call scoring functions for habits & rewards (todos & dailies handled below)
|
|
|
|
|
###
|
|
|
|
|
appExports.score = (e, el) ->
|
|
|
|
|
task= model.at $(el).parents('li')[0]
|
|
|
|
|
taskObj = task.get()
|
2013-02-08 22:44:06 +00:00
|
|
|
direction = $(el).attr('data-direction')
|
2013-03-18 00:30:54 +00:00
|
|
|
|
|
|
|
|
# set previous state for undo
|
2013-03-18 03:15:19 +00:00
|
|
|
setUndo _.clone(user.get('stats')), _.clone(taskObj)
|
2013-03-18 00:30:54 +00:00
|
|
|
|
|
|
|
|
scoring.score(model, taskObj.id, direction)
|
|
|
|
|
|
|
|
|
|
###
|
|
|
|
|
This is how we handle appExports.score for todos & dailies. Due to Derby's special handling of `checked={:task.completd}`,
|
|
|
|
|
the above function doesn't work so we need a listener here
|
|
|
|
|
###
|
|
|
|
|
user.on 'set', 'tasks.*.completed', (i, completed, previous, isLocal, passed) ->
|
|
|
|
|
return if passed? && passed.cron # Don't do this stuff on cron
|
|
|
|
|
direction = if completed then 'up' else 'down'
|
|
|
|
|
|
|
|
|
|
# set previous state for undo
|
|
|
|
|
taskObj = _.clone user.get("tasks.#{i}")
|
|
|
|
|
taskObj.completed = previous
|
2013-03-18 03:15:19 +00:00
|
|
|
setUndo _.clone(user.get('stats')), taskObj
|
2013-03-18 00:30:54 +00:00
|
|
|
|
|
|
|
|
scoring.score(model, i, direction)
|
|
|
|
|
|
|
|
|
|
###
|
|
|
|
|
Undo
|
|
|
|
|
###
|
|
|
|
|
appExports.undo = () ->
|
|
|
|
|
undo = model.get '_undo'
|
2013-03-18 03:15:19 +00:00
|
|
|
clearTimeout(undo.timeoutId) if undo?.timeoutId
|
2013-03-18 00:30:54 +00:00
|
|
|
batch = character.BatchUpdate(model)
|
|
|
|
|
batch.startTransaction()
|
2013-03-18 03:15:19 +00:00
|
|
|
model.del '_undo'
|
2013-03-18 00:30:54 +00:00
|
|
|
_.each undo.stats, (val, key) -> batch.set "stats.#{key}", val
|
|
|
|
|
taskPath = "tasks.#{undo.task.id}"
|
2013-03-18 01:43:03 +00:00
|
|
|
_.each undo.task, (val, key) ->
|
2013-03-18 02:02:06 +00:00
|
|
|
return if key in ['id', 'type'] # strange bugs in this world: https://workflowy.com/shared/a53582ea-43d6-bcce-c719-e134f9bf71fd/
|
2013-03-18 01:43:03 +00:00
|
|
|
if key is 'completed'
|
|
|
|
|
user.pass({cron:true}).set("#{taskPath}.completed",val)
|
|
|
|
|
else
|
|
|
|
|
batch.set "#{taskPath}.#{key}", val
|
2013-03-18 00:30:54 +00:00
|
|
|
batch.commit()
|
2013-03-03 04:52:47 +00:00
|
|
|
|
2013-03-05 23:07:22 +00:00
|
|
|
appExports.tasksToggleAdvanced = (e, el) ->
|
2013-03-06 05:49:02 +00:00
|
|
|
$(el).next('.advanced-option').toggleClass('visuallyhidden')
|
2013-03-05 23:07:22 +00:00
|
|
|
|
2013-03-03 04:52:47 +00:00
|
|
|
appExports.tasksSaveAndClose = ->
|
|
|
|
|
# When they update their notes, re-establish tooltip & popover
|
|
|
|
|
$('[rel=tooltip]').tooltip()
|
|
|
|
|
$('[rel=popover]').popover()
|
2013-03-03 22:54:14 +00:00
|
|
|
|
2013-03-04 16:33:36 +00:00
|
|
|
appExports.tasksSetPriority = (e, el) ->
|
2013-03-03 22:54:14 +00:00
|
|
|
dataId = $(el).parent('[data-id]').attr('data-id')
|
|
|
|
|
#"_user.tasks.#{dataId}"
|
2013-03-04 16:33:36 +00:00
|
|
|
model.at(e.target).set 'priority', $(el).attr('data-priority')
|