Files
habitica/assets/js/misc.js
T
Tyler Renelle 3c45220e1f rewrite2 WIP
2013-08-24 23:54:08 -04:00

324 lines
10 KiB
JavaScript

// Generated by CoffeeScript 1.6.3
(function() {
var algos, batchTxn, helpers, indexedPath, items, taskInChallenge, _;
_ = require('lodash');
algos = require('habitrpg-shared/script/algos');
items = require('habitrpg-shared/script/items').items;
helpers = require('habitrpg-shared/script/helpers');
module.exports.batchTxn = batchTxn = function(model, cb, options) {
var batch, paths, ret, setOps, uObj, user;
if (options == null) {
options = {};
}
_.defaults(options, {
user: model.at("_user"),
cron: false,
done: function() {}
});
user = options.user;
uObj = helpers.hydrate(user.get());
batch = {
set: function(k, v) {
helpers.dotSet(k, v, uObj);
return paths[k] = true;
},
get: function(k) {
return helpers.dotGet(k, uObj);
}
};
paths = {};
model._dontPersist = true;
ret = cb(uObj, paths, batch);
_.each(paths, function(v, k) {
user.pass({
cron: options.cron
}).set(k, batch.get(k));
return true;
});
model._dontPersist = false;
if (!_.isEmpty(paths)) {
setOps = _.reduce(paths, (function(m, v, k) {
m[k] = batch.get(k);
return m;
}), {});
user.set("update__", setOps, options.done);
} else {
options.done();
}
return ret;
};
/*
We can't always use refLists, but we often still need to get a positional path by id: eg, users.1234.tasks.5678.value
For arrays (which use indexes, not id-paths), here's a helper function so we can run indexedPath('users',:user.id,'tasks',:task.id,'value)
*/
indexedPath = function() {
var _this = this;
return _.reduce(arguments, function(m, v) {
if (!m) {
return v;
}
if (_.isString(v)) {
return "" + m + "." + v;
}
return ("" + m + ".") + _.findIndex(_this.model.get(m), v);
}, '');
};
taskInChallenge = function(task) {
if (!(task != null ? task.challenge : void 0)) {
return void 0;
}
return this.model.at(indexedPath.call(this, "groups." + task.group.id + ".challenges", {
id: task.challenge
}, "" + task.type + "s", {
id: task.id
}));
};
/*
algos.score wrapper for habitrpg-helpers to work in Derby. We need to do model.set() instead of simply setting the
object properties, and it's very difficult to diff the two objects and find dot-separated paths to set. So we to first
clone our user object (if we don't do that, it screws with model.on() listeners, ping Tyler for an explaination),
perform the updates while tracking paths, then all the values at those paths
*/
module.exports.score = function(model, taskId, direction, allowUndo) {
var delta, drop;
if (allowUndo == null) {
allowUndo = false;
}
drop = void 0;
delta = batchTxn(model, function(uObj, paths) {
var chal, chalTask, chalUser, cu, previousUndo, tObj, tObjBefore, timeoutId, _ref, _ref1, _ref2, _ref3, _ref4;
tObj = uObj.tasks[taskId];
if (allowUndo) {
tObjBefore = _.cloneDeep(tObj);
if ((_ref = tObjBefore.type) === 'daily' || _ref === 'todo') {
tObjBefore.completed = !tObjBefore.completed;
}
previousUndo = model.get('_undo');
if (previousUndo != null ? previousUndo.timeoutId : void 0) {
clearTimeout(previousUndo.timeoutId);
}
timeoutId = setTimeout((function() {
return model.del('_undo');
}), 20000);
model.set('_undo', {
stats: _.cloneDeep(uObj.stats),
task: tObjBefore,
timeoutId: timeoutId
});
}
delta = algos.score(uObj, tObj, direction, {
paths: paths
});
if ((_ref1 = uObj._tmp) != null ? _ref1.streakBonus : void 0) {
model.set('_streakBonus', uObj._tmp.streakBonus);
}
drop = (_ref2 = uObj._tmp) != null ? _ref2.drop : void 0;
if ((chalTask = taskInChallenge.call({
model: model
}, tObj)) && (chalTask != null ? chalTask.get() : void 0)) {
model._dontPersist = false;
chalTask.incr("value", delta);
chal = model.at(indexedPath.call({
model: model
}, "groups." + tObj.group.id + ".challenges", {
id: tObj.challenge
}));
chalUser = function() {
return indexedPath.call({
model: model
}, chal.path(), 'users', {
id: uObj.id
});
};
cu = model.at(chalUser());
if (!(cu != null ? cu.get() : void 0)) {
chal.push("users", {
id: uObj.id,
name: helpers.username(uObj.auth, (_ref3 = uObj.profile) != null ? _ref3.name : void 0)
});
cu = model.at(chalUser());
} else {
cu.set('name', helpers.username(uObj.auth, (_ref4 = uObj.profile) != null ? _ref4.name : void 0));
}
cu.set("" + tObj.type + "s." + tObj.id, {
value: tObj.value,
history: tObj.history
});
return model._dontPersist = true;
}
}, {
done: function() {
if (drop && (typeof $ !== "undefined" && $ !== null)) {
model.set('_drop', drop);
return $('#item-dropped-modal').modal('show');
}
}
});
return delta;
};
/*
Cleanup task-corruption (null tasks, rogue/invisible tasks, etc)
Obviously none of this should be happening, but we'll stop-gap until we can find & fix
Gotta love refLists! see https://github.com/lefnire/habitrpg/issues/803 & https://github.com/lefnire/habitrpg/issues/6343
*/
module.exports.fixCorruptUser = function(model) {
var resetDom, tasks, user;
user = model.at('_user');
tasks = user.get('tasks');
_.each(tasks, function(task, key) {
if (!(((task != null ? task.id : void 0) != null) && ((task != null ? task.type : void 0) != null))) {
user.del("tasks." + key);
delete tasks[key];
}
return true;
});
resetDom = false;
batchTxn(model, function(uObj, paths, batch) {
var uniqInvites, uniqPets, _ref;
uniqPets = _.uniq(uObj.items.pets);
if (!_.isEqual(uniqPets, uObj.items.pets)) {
batch.set('items.pets', uniqPets);
}
if ((_ref = uObj.invitations) != null ? _ref.guilds : void 0) {
uniqInvites = _.uniq(uObj.invitations.guilds);
if (!_.isEqual(uniqInvites, uObj.invitations.guilds)) {
batch.set('invitations.guilds', uniqInvites);
}
}
['habit', 'daily', 'todo', 'reward'].forEach(function(type) {
var idList, preened, taskIds, union;
idList = uObj["" + type + "Ids"];
taskIds = _.pluck(_.where(tasks, {
type: type
}), 'id');
union = _.union(idList, taskIds);
preened = _.filter(union, function(id) {
return id && _.contains(taskIds, id);
});
if (!_.isEqual(idList, preened)) {
batch.set("" + type + "Ids", preened);
console.error(uObj.id + ("'s " + type + "s were corrupt."));
}
return true;
});
return resetDom = !_.isEmpty(paths);
});
if (resetDom) {
return require('./browser').resetDom(model);
}
};
module.exports.viewHelpers = function(view) {
view.fn("percent", function(x, y) {
if (x === 0) {
x = 1;
}
return Math.round(x / y * 100);
});
view.fn('indexOf', function(str1, str2) {
if (!(str1 && str2)) {
return false;
}
return str1.indexOf(str2) !== -1;
});
view.fn("round", Math.round);
view.fn("floor", Math.floor);
view.fn("ceil", Math.ceil);
view.fn("lt", function(a, b) {
return a < b;
});
view.fn('gt', function(a, b) {
return a > b;
});
view.fn("mod", function(a, b) {
return parseInt(a) % parseInt(b) === 0;
});
view.fn("notEqual", function(a, b) {
return a !== b;
});
view.fn("and", function() {
return _.reduce(arguments, function(cumm, curr) {
return cumm && curr;
});
});
view.fn("or", function() {
return _.reduce(arguments, function(cumm, curr) {
return cumm || curr;
});
});
view.fn("truarr", function(num) {
return num - 1;
});
view.fn('count', function(arr) {
return (arr != null ? arr.length : void 0) || 0;
});
view.fn('int', {
get: function(num) {
return num;
},
set: function(num) {
return [parseInt(num)];
}
});
view.fn('indexedPath', indexedPath);
view.fn("encodeiCalLink", helpers.encodeiCalLink);
view.fn("gems", function(balance) {
return balance * 4;
});
view.fn("username", helpers.username);
view.fn("tnl", algos.tnl);
view.fn('equipped', helpers.equipped);
view.fn("gold", helpers.gold);
view.fn("silver", helpers.silver);
view.fn('userStr', helpers.userStr);
view.fn('totalStr', helpers.totalStr);
view.fn('userDef', helpers.userDef);
view.fn('totalDef', helpers.totalDef);
view.fn('itemText', helpers.itemText);
view.fn('itemStat', helpers.itemStat);
view.fn('ownsPet', helpers.ownsPet);
view.fn('taskClasses', helpers.taskClasses);
view.fn('friendlyTimestamp', helpers.friendlyTimestamp);
view.fn('newChatMessages', helpers.newChatMessages);
view.fn('relativeDate', helpers.relativeDate);
view.fn('noTags', helpers.noTags);
view.fn('appliedTags', helpers.appliedTags);
view.fn('taskInChallenge', function(task) {
var _ref;
return (_ref = taskInChallenge.call(this, task)) != null ? _ref.get() : void 0;
});
view.fn('taskAttrFromChallenge', function(task, attr) {
var _ref;
return (_ref = taskInChallenge.call(this, task)) != null ? _ref.get(attr) : void 0;
});
view.fn('brokenChallengeLink', function(task) {
var _ref;
return (task != null ? task.challenge : void 0) && !((_ref = taskInChallenge.call(this, task)) != null ? _ref.get() : void 0);
});
return view.fn('challengeMemberScore', function(member, tType, tid) {
var _ref, _ref1;
return Math.round((_ref = member["" + tType + "s"]) != null ? (_ref1 = _ref[tid]) != null ? _ref1.value : void 0 : void 0);
});
};
}).call(this);
/*
//@ sourceMappingURL=misc.map
*/