Beginnings of toggling days-of-week for repeatable dailies

Conflicts:

	lib/app/index.js
	package.json
	src/app/index.coffee
This commit is contained in:
Tyler Renelle 2012-09-04 22:09:52 -04:00
parent 33c285c398
commit 9c58a7809f
11 changed files with 128 additions and 37 deletions

View file

@ -1,4 +1,7 @@
// Generated by CoffeeScript 1.3.3
var moment;
moment = require('moment');
module.exports.daysBetween = function(a, b) {
var DAY;
@ -9,10 +12,20 @@ module.exports.daysBetween = function(a, b) {
};
module.exports.viewHelpers = function(view) {
view.fn('taskClasses', function(type, completed, value) {
var classes;
view.fn('taskClasses', function(type, completed, value, repeat) {
var classes, dayMapping;
classes = type;
if (completed) {
dayMapping = {
0: 'su',
1: 'm',
2: 't',
3: 'w',
4: 'th',
5: 'f',
6: 's',
7: 'su'
};
if (completed || (repeat && repeat[dayMapping[moment().day()]] === false)) {
classes += " completed";
}
switch (false) {

View file

@ -178,6 +178,22 @@ ready(function(model) {
value: 20
});
case 'daily':
return list.push({
type: type,
text: text,
notes: '',
value: 0,
repeat: {
su: true,
m: true,
t: true,
w: true,
th: true,
f: true,
s: true
},
completed: false
});
case 'todo':
return list.push({
type: type,
@ -222,6 +238,15 @@ ready(function(model) {
return model.set('_user.completedIds', []);
});
};
exports.toggleDay = function(e, el) {
var task;
task = model.at(e.target);
if (/active/.test($(el).attr('class'))) {
return task.set('repeat.' + $(el).attr('data-day'), false);
} else {
return task.set('repeat.' + $(el).attr('data-day'), true);
}
};
exports.toggleTaskEdit = function(e, el) {
var hideId, toggleId;
hideId = $(el).attr('data-hide-id');
@ -324,8 +349,10 @@ ready(function(model) {
daysPassed = helpers.daysBetween(lastCron, today);
if (daysPassed > 0) {
model.set('_user.lastCron', today);
return _(daysPassed).times(function() {
return scoring.tally(model.at('_user'));
return _(daysPassed).times(function(n) {
var tallyFor;
tallyFor = moment(lastCron).add('d', n);
return scoring.tally(model.at('_user'), tallyFor);
});
}
};
@ -335,10 +362,7 @@ ready(function(model) {
setInterval(function() {
return poormanscron();
}, 3600000);
exports.endOfDayTally = function(e, el) {
return exports.endOfDayTally = function(e, el) {
return scoring.tally(model);
};
return exports.updateSchema = function(e, el) {
return schema.updateSchema(model);
};
});

View file

@ -22,6 +22,7 @@ module.exports.userSchema = userSchema = {
};
module.exports.updateSchema = function(model) {
return;
return model.fetch('users', function(err, users) {
return _.each(users.get(), function(userObj) {
var daysOld, sameTasks, user, userPath;

View file

@ -150,28 +150,40 @@ module.exports.score = score = function(spec) {
return delta;
};
module.exports.tally = function(user) {
module.exports.tally = function(user, momentDate) {
var expTally, lvl, todoTally;
todoTally = 0;
_.each(user.get('tasks'), function(taskObj, taskId, list) {
var absVal, completed, task, type, value, _ref;
var absVal, completed, dayMapping, repeat, task, type, value, _ref;
if (taskObj.id == null) {
return;
}
_ref = [taskObj.type, taskObj.value, taskObj.completed], type = _ref[0], value = _ref[1], completed = _ref[2];
_ref = [taskObj.type, taskObj.value, taskObj.completed, taskObj.repeat], type = _ref[0], value = _ref[1], completed = _ref[2], repeat = _ref[3];
task = user.at("tasks." + taskId);
if (type === 'todo' || type === 'daily') {
if (!completed) {
score({
user: user,
task: task,
direction: 'down',
cron: true
});
dayMapping = {
0: 'su',
1: 'm',
2: 't',
3: 'w',
4: 'th',
5: 'f',
6: 's',
7: 'su'
};
if (repeat && repeat[dayMapping[momentDate.day()]] === true) {
score({
user: user,
task: task,
direction: 'down',
cron: true
});
}
}
if (type === 'daily') {
task.push("history", {
date: new Date(),
date: new Date(momentDate),
value: value
});
} else {
@ -186,7 +198,7 @@ module.exports.tally = function(user) {
}
});
user.push('history.todos', {
date: new Date(),
date: new Date(momentDate),
value: todoTally
});
expTally = user.get('stats.exp');

View file

@ -11,7 +11,8 @@
"connect-mongo": ">=0.1.9",
"derby-ui-boot": "*",
"guid": "*",
"node.extend": "*"
"node.extend": "*",
"moment": "*"
},
"private": true,
"devDependencies": {

6
public/js/moment.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View file

@ -1,5 +1,7 @@
moment = require('moment')
module.exports.daysBetween = (a, b) ->
#TODO replace this function with moment().diff()?
DAY = 1000 * 60 * 60 * 24
# calculate as midnight
a = new Date( (new Date(a)).toDateString() )
@ -7,10 +9,14 @@ module.exports.daysBetween = (a, b) ->
return Math.abs(Math.floor((a.getTime() - b.getTime()) / DAY))
module.exports.viewHelpers = (view) ->
view.fn 'taskClasses', (type, completed, value) ->
view.fn 'taskClasses', (type, completed, value, repeat) ->
#TODO figure out how to just pass in the task model, so i can access all these properties from one object
classes = type
classes += " completed" if completed
# show as completed if completed (naturally) or not required for today
dayMapping = {0:'su',1:'m',2:'t',3:'w',4:'th',5:'f',6:'s',7:'su'}
if completed or (repeat and repeat[dayMapping[moment().day()]]==false)
classes += " completed"
switch
when value<-8 then classes += ' color-worst'

View file

@ -147,7 +147,10 @@ ready (model) ->
when 'reward'
list.push {type: type, text: text, notes: '', value: 20 }
when 'daily', 'todo'
when 'daily'
list.push {type: type, text: text, notes: '', value: 0, repeat:{su:true,m:true,t:true,w:true,th:true,f:true,s:true}, completed: false }
when 'todo'
list.push {type: type, text: text, notes: '', value: 0, completed: false }
# list.on 'set', '*.completed', (i, completed, previous, isLocal) ->
@ -184,6 +187,13 @@ ready (model) ->
_.each model.get('_completedList'), (task) ->
model.del('_user.tasks.'+task.id)
model.set('_user.completedIds', [])
exports.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)
exports.toggleTaskEdit = (e, el) ->
hideId = $(el).attr('data-hide-id')
@ -267,8 +277,9 @@ ready (model) ->
daysPassed = helpers.daysBetween(lastCron, today)
if daysPassed > 0
model.set('_user.lastCron', today) # reset cron
_(daysPassed).times () ->
scoring.tally(model.at('_user'))
_(daysPassed).times (n) ->
tallyFor = moment(lastCron).add('d',n)
scoring.tally(model.at('_user'), tallyFor)
# FIXME seems can't call poormanscron() instantly, have to call after some time (2s here)
# Doesn't do anything otherwise. Don't know why... model not initialized enough yet?
setTimeout () -> # Run once on refresh
@ -284,6 +295,6 @@ ready (model) ->
scoring.tally(model)
# Temporary solution to running updates against the schema when the code changes
exports.updateSchema = (e, el) ->
schema.updateSchema(model)
# exports.updateSchema = (e, el) ->
# schema.updateSchema(model)

View file

@ -11,6 +11,7 @@ module.exports.userSchema = userSchema = {
}
module.exports.updateSchema = (model) ->
return
# Reset history, remove inactive users
model.fetch 'users', (err, users) ->
_.each users.get(), (userObj) ->
@ -40,4 +41,4 @@ module.exports.updateSchema = (model) ->
_.each userObj.tasks, (taskObj) ->
task = user.at "tasks.#{taskObj.id}"
if task.get("history")
task.set "history", []
task.set "history", []

View file

@ -139,24 +139,27 @@ module.exports.score = score = (spec = {user:null, task:null, direction:null, cr
# At end of day, add value to all incomplete Daily & Todo tasks (further incentive)
# For incomplete Dailys, deduct experience
module.exports.tally = (user) ->
module.exports.tally = (user, momentDate) ->
todoTally = 0
_.each user.get('tasks'), (taskObj, taskId, list) ->
#FIXME is it hiccuping here? taskId == "$_65255f4e-3728-4d50-bade-3b05633639af_2", & taskObj.id = undefined
return unless taskObj.id? #this shouldn't be happening, some tasks seem to be corrupted
[type, value, completed] = [taskObj.type, taskObj.value, taskObj.completed]
[type, value, completed, repeat] = [taskObj.type, taskObj.value, taskObj.completed, taskObj.repeat]
task = user.at("tasks.#{taskId}")
if type in ['todo', 'daily']
# Deduct experience for missed Daily tasks,
# but not for Todos (just increase todo's value)
score({user:user, task:task, direction:'down', cron:true}) unless completed
unless completed
dayMapping = {0:'su',1:'m',2:'t',3:'w',4:'th',5:'f',6:'s',7:'su'}
if repeat && repeat[dayMapping[momentDate.day()]]==true
score({user:user, task:task, direction:'down', cron:true})
if type == 'daily'
task.push "history", { date: new Date(), value: value }
task.push "history", { date: new Date(momentDate), value: value }
else
absVal = if (completed) then Math.abs(value) else value
todoTally += absVal
task.pass({cron:true}).set('completed', false) if type == 'daily'
user.push 'history.todos', { date: new Date(), value: todoTally }
user.push 'history.todos', { date: new Date(momentDate), value: todoTally }
# tally experience
expTally = user.get 'stats.exp'

View file

@ -78,7 +78,6 @@
<i class="icon-warning-sign"></i> <b>Debugging Options</b><br/><br/>
<a x-bind=click:poormanscron class="btn">Cron</a>
<a x-bind=click:endOfDayTally class="btn">Tally</a>
<a x-bind=click:updateSchema class="btn">Update Schema</a>
</div>
{/}
@ -203,7 +202,7 @@
</form>
<task:>
<li data-id={{:task.id}} class="task {taskClasses(:task.type, :task.completed, :task.value)}">
<li data-id={{:task.id}} class="task {taskClasses(:task.type, :task.completed, :task.value, :task.repeat)}">
<pre>
<div class="task-meta-controls">
@ -259,6 +258,19 @@
<label class="checkbox inline"><input type=checkbox checked={:task.down}>Down</label>
</div>
{/}
{#if equal(:task.type, 'daily')}
<label>Repeat</label>
<div class="control-group btn-group repeat-days">
<!-- note, does not use data-toggle="buttons-checkbox" - it would interfere with our own click binding -->
<button type="button" class="btn btn-info {#if :task.repeat.su}active{/}" data-day='su' x-bind=click:toggleDay>Su</button>
<button type="button" class="btn btn-info {#if :task.repeat.m}active{/}" data-day='m' x-bind=click:toggleDay>M</button>
<button type="button" class="btn btn-info {#if :task.repeat.t}active{/}" data-day='t' x-bind=click:toggleDay>T</button>
<button type="button" class="btn btn-info {#if :task.repeat.w}active{/}" data-day='w' x-bind=click:toggleDay>W</button>
<button type="button" class="btn btn-info {#if :task.repeat.th}active{/}" data-day='th' x-bind=click:toggleDay>Th</button>
<button type="button" class="btn btn-info {#if :task.repeat.f}active{/}" data-day='f' x-bind=click:toggleDay>F</button>
<button type="button" class="btn btn-info {#if :task.repeat.s}active{/}" data-day='s' x-bind=click:toggleDay>S</button>
</div>
{/}
{#if equal(:task.type, 'reward')}
<div class=control-group>
<label>Price
@ -293,6 +305,7 @@
<Scripts:>
<script src=/js/jquery.min.js></script>
{#unless _mobileDevice}<script src=/js/jquery-ui.min.js></script>{/}
<script src=/js/moment.min.js></script><!-- https://raw.github.com/timrwood/moment/1.7.0/min/moment.min.js -->
<script src=/js/underscore-min.js></script><!-- http://underscorejs.org/underscore-min.js -->
<script src=/js/bootstrap.min.js></script><!-- http://twitter.github.com/bootstrap/assets/js/bootstrap.min.js -->
<script src=/js/jquery.cookie.js></script><!-- https://raw.github.com/carhartl/jquery-cookie/master/jquery.cookie.js -->