mirror of
https://github.com/sudoxnym/habitica-self-host.git
synced 2026-05-19 12:18:41 +00:00
Subdocs & script templates. Migrate the API from User.tasks =>
User.habits/dailys/todos/rewards. Move /#/tasks & /#/options page loading from server-sent html to everything loaded in the page as script templates (including necessary fixes for adsense). NOTE: this commit won't work, it depends a bit on the *next* commit with Challenges functionality, but I wanted to separate it out a bit for clarity
This commit is contained in:
parent
e81193ef28
commit
e45d8307e7
18 changed files with 415 additions and 575 deletions
|
|
@ -1,7 +1,7 @@
|
|||
"use strict";
|
||||
|
||||
window.habitrpg = angular.module('habitrpg',
|
||||
['ngRoute', 'ngResource', 'ngSanitize', 'userServices', 'groupServices', 'memberServices', 'sharedServices', 'authServices', 'notificationServices', 'guideServices', 'ui.bootstrap', 'ui.keypress'])
|
||||
['ngRoute', 'ngResource', 'ngSanitize', 'userServices', 'groupServices', 'memberServices', 'challengeServices', 'sharedServices', 'authServices', 'notificationServices', 'guideServices', 'ui.bootstrap', 'ui.keypress'])
|
||||
|
||||
.constant("API_URL", "")
|
||||
.constant("STORAGE_USER_ID", 'habitrpg-user')
|
||||
|
|
@ -12,8 +12,8 @@ window.habitrpg = angular.module('habitrpg',
|
|||
function($routeProvider, $httpProvider, STORAGE_SETTINGS_ID) {
|
||||
$routeProvider
|
||||
//.when('/login', {templateUrl: 'views/login.html'})
|
||||
.when('/tasks', {templateUrl: 'partials/tasks'})
|
||||
.when('/options', {templateUrl: 'partials/options'})
|
||||
.when('/tasks', {templateUrl: 'templates/habitrpg-main.html'})
|
||||
.when('/options', {templateUrl: 'templates/habitrpg-options.html'})
|
||||
|
||||
.otherwise({redirectTo: '/tasks'});
|
||||
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ habitrpg.controller("FiltersCtrl", ['$scope', '$rootScope', 'User', 'API_URL', '
|
|||
delete user.filters[tag.id];
|
||||
user.tags.splice($index,1);
|
||||
// remove tag from all tasks
|
||||
_.each(user.tasks, function(task) {
|
||||
_.each(user.habits.concat(user.dailys).concat(user.todos).concat(user.rewards), function(task) {
|
||||
delete task.tags[tag.id];
|
||||
});
|
||||
User.log({op:'delTag',data:{'tag':tag.id}})
|
||||
|
|
|
|||
|
|
@ -12,6 +12,11 @@ habitrpg.controller("RootCtrl", ['$scope', '$rootScope', '$location', 'User', '$
|
|||
$rootScope.settings = User.settings;
|
||||
$rootScope.flash = {errors: [], warnings: []};
|
||||
|
||||
// indexOf helper
|
||||
$scope.indexOf = function(haystack, needle){
|
||||
return ~haystack.indexOf(needle);
|
||||
}
|
||||
|
||||
$scope.safeApply = function(fn) {
|
||||
var phase = this.$root.$$phase;
|
||||
if(phase == '$apply' || phase == '$digest') {
|
||||
|
|
|
|||
|
|
@ -1,53 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
habitrpg.controller("TaskDetailsCtrl", ['$scope', '$rootScope', '$location', 'User',
|
||||
function($scope, $rootScope, $location, User) {
|
||||
$scope.save = function(task) {
|
||||
var log, setVal;
|
||||
setVal = function(k, v) {
|
||||
var op;
|
||||
if (typeof v !== "undefined") {
|
||||
op = {
|
||||
op: "set",
|
||||
data: {}
|
||||
};
|
||||
op.data["tasks." + task.id + "." + k] = v;
|
||||
return log.push(op);
|
||||
}
|
||||
};
|
||||
log = [];
|
||||
setVal("text", task.text);
|
||||
setVal("notes", task.notes);
|
||||
setVal("priority", task.priority);
|
||||
setVal("tags", task.tags);
|
||||
if (task.type === "habit") {
|
||||
setVal("up", task.up);
|
||||
setVal("down", task.down);
|
||||
} else if (task.type === "daily") {
|
||||
setVal("repeat", task.repeat);
|
||||
// TODO we'll remove this once rewrite's running for a while. This was a patch for derby issues
|
||||
setVal("streak", task.streak);
|
||||
|
||||
} else if (task.type === "todo") {
|
||||
setVal("date", task.date);
|
||||
} else {
|
||||
if (task.type === "reward") {
|
||||
setVal("value", task.value);
|
||||
}
|
||||
}
|
||||
User.log(log);
|
||||
task._editing = false;
|
||||
};
|
||||
$scope.cancel = function() {
|
||||
/* reset $scope.task to $scope.originalTask
|
||||
*/
|
||||
|
||||
var key;
|
||||
for (key in $scope.task) {
|
||||
$scope.task[key] = $scope.originalTask[key];
|
||||
}
|
||||
$scope.originalTask = null;
|
||||
$scope.editedTask = null;
|
||||
$scope.editing = false;
|
||||
};
|
||||
}]);
|
||||
|
|
@ -2,35 +2,6 @@
|
|||
|
||||
habitrpg.controller("TasksCtrl", ['$scope', '$rootScope', '$location', 'User', 'Algos', 'Helpers', 'Notification',
|
||||
function($scope, $rootScope, $location, User, Algos, Helpers, Notification) {
|
||||
/*FIXME
|
||||
*/
|
||||
$scope.taskLists = [
|
||||
{
|
||||
header: 'Habits',
|
||||
type: 'habit',
|
||||
placeHolder: 'New Habit',
|
||||
main: true,
|
||||
editable: true
|
||||
}, {
|
||||
header: 'Dailies',
|
||||
type: 'daily',
|
||||
placeHolder: 'New Daily',
|
||||
main: true,
|
||||
editable: true
|
||||
}, {
|
||||
header: 'Todos',
|
||||
type: 'todo',
|
||||
placeHolder: 'New Todo',
|
||||
main: true,
|
||||
editable: true
|
||||
}, {
|
||||
header: 'Rewards',
|
||||
type: 'reward',
|
||||
placeHolder: 'New Reward',
|
||||
main: true,
|
||||
editable: true
|
||||
}
|
||||
];
|
||||
$scope.score = function(task, direction) {
|
||||
if (task.type === "reward" && User.user.stats.gp < task.value){
|
||||
return Notification.text('Not enough GP.');
|
||||
|
|
@ -42,18 +13,20 @@ habitrpg.controller("TasksCtrl", ['$scope', '$rootScope', '$location', 'User', '
|
|||
|
||||
$scope.addTask = function(list) {
|
||||
var task = window.habitrpgShared.helpers.taskDefaults({text: list.newTask, type: list.type}, User.user.filters);
|
||||
User.user[list.type + "s"].unshift(task);
|
||||
// $scope.showedTasks.unshift newTask # FIXME what's thiss?
|
||||
list.tasks.unshift(task);
|
||||
User.log({op: "addTask", data: task});
|
||||
delete list.newTask;
|
||||
};
|
||||
/*Add the new task to the actions log
|
||||
*/
|
||||
|
||||
/**
|
||||
* Add the new task to the actions log
|
||||
*/
|
||||
$scope.clearDoneTodos = function() {};
|
||||
|
||||
/**
|
||||
* This is calculated post-change, so task.completed=true if they just checked it
|
||||
*/
|
||||
$scope.changeCheck = function(task) {
|
||||
/* This is calculated post-change, so task.completed=true if they just checked it
|
||||
*/
|
||||
if (task.completed) {
|
||||
$scope.score(task, "up");
|
||||
} else {
|
||||
|
|
@ -66,27 +39,59 @@ habitrpg.controller("TasksCtrl", ['$scope', '$rootScope', '$location', 'User', '
|
|||
// uhoh! our first name conflict with habitrpg-shared/helpers, we gotta resovle that soon.
|
||||
$rootScope.clickRevive = function() {
|
||||
window.habitrpgShared.algos.revive(User.user);
|
||||
User.log({
|
||||
op: "revive"
|
||||
});
|
||||
User.log({ op: "revive" });
|
||||
};
|
||||
|
||||
$scope.toggleEdit = function(task){
|
||||
task._editing = !task._editing;
|
||||
if($rootScope.charts[task.id]) $rootScope.charts[task.id] = false;
|
||||
$scope.removeTask = function(list, $index) {
|
||||
if (!confirm("Are you sure you want to delete this task?")) return;
|
||||
User.log({ op: "delTask", data: list[$index] });
|
||||
list.splice($index, 1);
|
||||
};
|
||||
|
||||
$scope.remove = function(task) {
|
||||
var tasks;
|
||||
if (confirm("Are you sure you want to delete this task?") !== true) {
|
||||
return;
|
||||
$scope.saveTask = function(task) {
|
||||
var setVal = function(k, v) {
|
||||
var op;
|
||||
if (typeof v !== "undefined") {
|
||||
op = { op: "set", data: {} };
|
||||
op.data["tasks." + task.id + "." + k] = v;
|
||||
return log.push(op);
|
||||
}
|
||||
};
|
||||
var log = [];
|
||||
setVal("text", task.text);
|
||||
setVal("notes", task.notes);
|
||||
setVal("priority", task.priority);
|
||||
setVal("tags", task.tags);
|
||||
if (task.type === "habit") {
|
||||
setVal("up", task.up);
|
||||
setVal("down", task.down);
|
||||
} else if (task.type === "daily") {
|
||||
setVal("repeat", task.repeat);
|
||||
// TODO we'll remove this once rewrite's running for a while. This was a patch for derby issues
|
||||
setVal("streak", task.streak);
|
||||
|
||||
} else if (task.type === "todo") {
|
||||
setVal("date", task.date);
|
||||
} else {
|
||||
if (task.type === "reward") {
|
||||
setVal("value", task.value);
|
||||
}
|
||||
}
|
||||
tasks = User.user[task.type + "s"];
|
||||
User.log({
|
||||
op: "delTask",
|
||||
data: task
|
||||
});
|
||||
tasks.splice(tasks.indexOf(task), 1);
|
||||
User.log(log);
|
||||
task._editing = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Reset $scope.task to $scope.originalTask
|
||||
*/
|
||||
$scope.cancel = function() {
|
||||
var key;
|
||||
for (key in $scope.task) {
|
||||
$scope.task[key] = $scope.originalTask[key];
|
||||
}
|
||||
$scope.originalTask = null;
|
||||
$scope.editedTask = null;
|
||||
$scope.editing = false;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -123,4 +128,15 @@ habitrpg.controller("TasksCtrl", ['$scope', '$rootScope', '$location', 'User', '
|
|||
User.log({op: 'clear-completed'});
|
||||
}
|
||||
|
||||
/**
|
||||
* See conversation on http://productforums.google.com/forum/#!topic/adsense/WYkC_VzKwbA,
|
||||
* Adsense is very sensitive. It must be called once-and-only-once for every <ins>, else things break.
|
||||
* Additionally, angular won't run javascript embedded into a script template, so we can't copy/paste
|
||||
* the html provided by adsense - we need to run this function post-link
|
||||
*/
|
||||
$scope.initAds = function(){
|
||||
$.getScript('//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js');
|
||||
(window.adsbygoogle = window.adsbygoogle || []).push({});
|
||||
}
|
||||
|
||||
}]);
|
||||
|
|
|
|||
|
|
@ -109,3 +109,53 @@ habitrpg.directive('habitrpgSortable', ['User', function(User) {
|
|||
};
|
||||
});
|
||||
})()
|
||||
|
||||
habitrpg
|
||||
.directive('habitrpgTasks', ['$rootScope', 'User', function($rootScope, User) {
|
||||
return {
|
||||
restrict: 'EA',
|
||||
templateUrl: 'templates/habitrpg-tasks.html',
|
||||
//transclude: true,
|
||||
//scope: {
|
||||
// main: '@', // true if it's the user's main list
|
||||
// obj: '='
|
||||
//},
|
||||
controller: function($scope, $rootScope){
|
||||
$scope.editTask = function(task){
|
||||
task._editing = !task._editing;
|
||||
if($rootScope.charts[task.id]) $rootScope.charts[task.id] = false;
|
||||
};
|
||||
},
|
||||
link: function(scope, element, attrs) {
|
||||
scope.obj = scope[attrs.obj];
|
||||
scope.main = attrs.main;
|
||||
|
||||
|
||||
scope.lists = [
|
||||
{
|
||||
header: 'Habits',
|
||||
type: 'habit',
|
||||
placeHolder: 'New Habit',
|
||||
tasks: scope.obj.habits
|
||||
}, {
|
||||
header: 'Dailies',
|
||||
type: 'daily',
|
||||
placeHolder: 'New Daily',
|
||||
tasks: scope.obj.dailys
|
||||
}, {
|
||||
header: 'Todos',
|
||||
type: 'todo',
|
||||
placeHolder: 'New Todo',
|
||||
tasks: scope.obj.todos
|
||||
}, {
|
||||
header: 'Rewards',
|
||||
type: 'reward',
|
||||
placeHolder: 'New Reward',
|
||||
tasks: scope.obj.rewards
|
||||
}
|
||||
];
|
||||
scope.editable = true;
|
||||
}
|
||||
}
|
||||
}]);
|
||||
|
||||
|
|
|
|||
|
|
@ -58,7 +58,6 @@ angular.module('userServices', []).
|
|||
|
||||
$http.post(API_URL + '/api/v1/user/batch-update', sent, {params: {data:+new Date, _v:user._v}})
|
||||
.success(function (data, status, heacreatingders, config) {
|
||||
data.tasks = _.toArray(data.tasks);
|
||||
//make sure there are no pending actions to sync. If there are any it is not safe to apply model from server as we may overwrite user data.
|
||||
if (!queue.length) {
|
||||
//we can't do user=data as it will not update user references in all other angular controllers.
|
||||
|
|
|
|||
|
|
@ -55,98 +55,28 @@ api.marketBuy = function(req, res, next){
|
|||
---------------
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
// FIXME put this in helpers, so mobile & web can us it too
|
||||
// FIXME actually, move to mongoose
|
||||
*/
|
||||
|
||||
|
||||
function taskSanitizeAndDefaults(task) {
|
||||
var _ref;
|
||||
if (task.id == null) {
|
||||
task.id = helpers.uuid();
|
||||
}
|
||||
task.value = ~~task.value;
|
||||
if (task.type == null) {
|
||||
task.type = 'habit';
|
||||
}
|
||||
if (_.isString(task.text)) {
|
||||
task.text = sanitize(task.text).xss();
|
||||
}
|
||||
if (_.isString(task.text)) {
|
||||
task.notes = sanitize(task.notes).xss();
|
||||
}
|
||||
if (task.type === 'habit') {
|
||||
if (!_.isBoolean(task.up)) {
|
||||
task.up = true;
|
||||
}
|
||||
if (!_.isBoolean(task.down)) {
|
||||
task.down = true;
|
||||
}
|
||||
}
|
||||
if ((_ref = task.type) === 'daily' || _ref === 'todo') {
|
||||
if (!_.isBoolean(task.completed)) {
|
||||
task.completed = false;
|
||||
}
|
||||
}
|
||||
if (task.type === 'daily') {
|
||||
if (task.repeat == null) {
|
||||
task.repeat = {
|
||||
m: true,
|
||||
t: true,
|
||||
w: true,
|
||||
th: true,
|
||||
f: true,
|
||||
s: true,
|
||||
su: true
|
||||
};
|
||||
}
|
||||
}
|
||||
return task;
|
||||
};
|
||||
|
||||
/*
|
||||
Validate task
|
||||
*/
|
||||
|
||||
|
||||
api.verifyTaskExists = function(req, res, next) {
|
||||
/* If we're updating, get the task from the user*/
|
||||
|
||||
var task;
|
||||
task = res.locals.user.tasks[req.params.id];
|
||||
if (_.isEmpty(task)) {
|
||||
return res.json(400, {
|
||||
err: "No task found."
|
||||
});
|
||||
}
|
||||
// If we're updating, get the task from the user
|
||||
var task = res.locals.user.tasks[req.params.id];
|
||||
if (_.isEmpty(task)) return res.json(400, {err: "No task found."});
|
||||
res.locals.task = task;
|
||||
return next();
|
||||
};
|
||||
|
||||
function addTask(user, task) {
|
||||
taskSanitizeAndDefaults(task);
|
||||
user.tasks[task.id] = task;
|
||||
user["" + task.type + "Ids"].unshift(task.id);
|
||||
return task;
|
||||
};
|
||||
|
||||
/* Override current user.task with incoming values, then sanitize all values*/
|
||||
|
||||
|
||||
function updateTask(user, id, incomingTask) {
|
||||
return user.tasks[id] = taskSanitizeAndDefaults(_.defaults(incomingTask, user.tasks[id]));
|
||||
};
|
||||
|
||||
function deleteTask(user, task) {
|
||||
var i, ids;
|
||||
delete user.tasks[task.id];
|
||||
if ((ids = user["" + task.type + "Ids"]) && ~(i = ids.indexOf(task.id))) {
|
||||
return ids.splice(i, 1);
|
||||
}
|
||||
user[task.type+'s'].id(task.id).remove();
|
||||
};
|
||||
|
||||
function addTask(user, task) {
|
||||
var type = task.type || 'habit'
|
||||
user[type+'s'].unshift(task);
|
||||
// FIXME will likely have to use taskSchema instead, so we can populate the defaults, add the _id, and return the added task
|
||||
return user[task.type+'s'][0];
|
||||
}
|
||||
|
||||
/*
|
||||
API Routes
|
||||
---------------
|
||||
|
|
@ -158,52 +88,42 @@ function deleteTask(user, task) {
|
|||
Export it also so we can call it from deprecated.coffee
|
||||
*/
|
||||
api.scoreTask = function(req, res, next) {
|
||||
|
||||
// FIXME this is all uglified from coffeescript compile, clean this up
|
||||
|
||||
var delta, direction, existing, id, task, user, _ref, _ref1, _ref2, _ref3, _ref4;
|
||||
_ref = req.params, id = _ref.id, direction = _ref.direction;
|
||||
var id = req.params.id,
|
||||
direction = req.params.direction,
|
||||
user = res.locals.user,
|
||||
task;
|
||||
|
||||
// Send error responses for improper API call
|
||||
if (!id) {
|
||||
return res.json(500, {
|
||||
err: ':id required'
|
||||
});
|
||||
}
|
||||
if (!id) return res.json(500, {err: ':id required'});
|
||||
if (direction !== 'up' && direction !== 'down') {
|
||||
return res.json(500, {
|
||||
err: ":direction must be 'up' or 'down'"
|
||||
});
|
||||
return res.json(500, {err: ":direction must be 'up' or 'down'"});
|
||||
}
|
||||
user = res.locals.user;
|
||||
/* If exists already, score it*/
|
||||
|
||||
if ((existing = user.tasks[id])) {
|
||||
/* Set completed if type is daily or todo and task exists*/
|
||||
|
||||
if ((_ref1 = existing.type) === 'daily' || _ref1 === 'todo') {
|
||||
// If exists already, score it
|
||||
var existing;
|
||||
if (existing = user.tasks[id]) {
|
||||
// Set completed if type is daily or todo and task exists
|
||||
if (existing.type === 'daily' || existing.type === 'todo') {
|
||||
existing.completed = direction === 'up';
|
||||
}
|
||||
} else {
|
||||
/* If it doesn't exist, this is likely a 3rd party up/down - create a new one, then score it*/
|
||||
|
||||
// If it doesn't exist, this is likely a 3rd party up/down - create a new one, then score it
|
||||
task = {
|
||||
id: id,
|
||||
value: 0,
|
||||
type: ((_ref2 = req.body) != null ? _ref2.type : void 0) || 'habit',
|
||||
text: ((_ref3 = req.body) != null ? _ref3.title : void 0) || id,
|
||||
type: req.body.type || 'habit',
|
||||
text: req.body.title || id,
|
||||
notes: "This task was created by a third-party service. Feel free to edit, it won't harm the connection to that service. Additionally, multiple services may piggy-back off this task."
|
||||
};
|
||||
if (task.type === 'habit') {
|
||||
task.up = task.down = true;
|
||||
}
|
||||
if ((_ref4 = task.type) === 'daily' || _ref4 === 'todo') {
|
||||
if (task.type === 'daily' || task.type === 'todo') {
|
||||
task.completed = direction === 'up';
|
||||
}
|
||||
addTask(user, task);
|
||||
}
|
||||
task = user.tasks[id];
|
||||
delta = algos.score(user, task, direction);
|
||||
var delta = algos.score(user, task, direction);
|
||||
//user.markModified('flags');
|
||||
user.save(function(err, saved) {
|
||||
if (err) return res.json(500, {err: err});
|
||||
|
|
@ -213,42 +133,29 @@ api.scoreTask = function(req, res, next) {
|
|||
});
|
||||
};
|
||||
|
||||
/*
|
||||
Get all tasks
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Get all tasks
|
||||
*/
|
||||
api.getTasks = function(req, res, next) {
|
||||
var tasks, types, _ref;
|
||||
types = (_ref = req.query.type) === 'habit' || _ref === 'todo' || _ref === 'daily' || _ref === 'reward' ? [req.query.type] : ['habit', 'todo', 'daily', 'reward'];
|
||||
tasks = _.toArray(_.filter(res.locals.user.tasks, function(t) {
|
||||
var _ref1;
|
||||
return _ref1 = t.type, __indexOf.call(types, _ref1) >= 0;
|
||||
}));
|
||||
return res.json(200, tasks);
|
||||
if (req.query.type) {
|
||||
return res.json(user[req.query.type+'s']);
|
||||
} else {
|
||||
return res.json(_.toArray(user.tasks));
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Get Task
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Get Task
|
||||
*/
|
||||
api.getTask = function(req, res, next) {
|
||||
var task;
|
||||
task = res.locals.user.tasks[req.params.id];
|
||||
if (_.isEmpty(task)) {
|
||||
return res.json(400, {
|
||||
err: "No task found."
|
||||
});
|
||||
}
|
||||
var task = res.locals.user.tasks[req.params.id];
|
||||
if (_.isEmpty(task)) return res.json(400, {err: "No task found."});
|
||||
return res.json(200, task);
|
||||
};
|
||||
|
||||
/*
|
||||
Delete Task
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Delete Task
|
||||
*/
|
||||
api.deleteTask = function(req, res, next) {
|
||||
deleteTask(res.locals.user, res.locals.task);
|
||||
res.locals.user.save(function(err) {
|
||||
|
|
@ -263,113 +170,69 @@ api.deleteTask = function(req, res, next) {
|
|||
|
||||
|
||||
api.updateTask = function(req, res, next) {
|
||||
var id, user;
|
||||
user = res.locals.user;
|
||||
id = req.params.id;
|
||||
updateTask(user, id, req.body);
|
||||
return user.save(function(err, saved) {
|
||||
if (err) {
|
||||
return res.json(500, {
|
||||
err: err
|
||||
});
|
||||
}
|
||||
return res.json(200, _.findWhere(saved.toJSON().tasks, {
|
||||
id: id
|
||||
}));
|
||||
var user = res.locals.user;
|
||||
var task = user.tasks[req.params.id];
|
||||
user[task.type+'s'][_.findIndex(user[task.type+'s'],{id:task.id})] = req.body;
|
||||
user.save(function(err, saved) {
|
||||
if (err) return res.json(500, {err: err})
|
||||
return res.json(200, saved.tasks[id]);
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
Update tasks (plural). This will update, add new, delete, etc all at once.
|
||||
Should we keep this?
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Update tasks (plural). This will update, add new, delete, etc all at once.
|
||||
* TODO Should we keep this?
|
||||
*/
|
||||
api.updateTasks = function(req, res, next) {
|
||||
var tasks, user;
|
||||
user = res.locals.user;
|
||||
tasks = req.body;
|
||||
var user = res.locals.user;
|
||||
var tasks = req.body;
|
||||
_.each(tasks, function(task, idx) {
|
||||
if (task.id) {
|
||||
/*delete*/
|
||||
|
||||
// delete
|
||||
if (task.del) {
|
||||
deleteTask(user, task);
|
||||
task = {
|
||||
deleted: true
|
||||
};
|
||||
task = {deleted: true};
|
||||
} else {
|
||||
/* Update*/
|
||||
|
||||
updateTask(user, task.id, task);
|
||||
// Update
|
||||
// updateTask(user, task.id, task); //FIXME
|
||||
}
|
||||
} else {
|
||||
/* Create*/
|
||||
|
||||
// Create
|
||||
task = addTask(user, task);
|
||||
}
|
||||
return tasks[idx] = task;
|
||||
tasks[idx] = task;
|
||||
});
|
||||
return user.save(function(err, saved) {
|
||||
if (err) {
|
||||
return res.json(500, {
|
||||
err: err
|
||||
});
|
||||
}
|
||||
user.save(function(err, saved) {
|
||||
if (err) return res.json(500, {err: err});
|
||||
return res.json(201, tasks);
|
||||
});
|
||||
};
|
||||
|
||||
api.createTask = function(req, res, next) {
|
||||
var task, user;
|
||||
user = res.locals.user;
|
||||
task = addTask(user, req.body);
|
||||
return user.save(function(err) {
|
||||
if (err) {
|
||||
return res.json(500, {
|
||||
err: err
|
||||
});
|
||||
}
|
||||
var user = res.locals.user;
|
||||
var task = addTask(user, req.body);
|
||||
user.save(function(err, saved) {
|
||||
if (err) return res.json(500, {err: err});
|
||||
return res.json(201, task);
|
||||
});
|
||||
};
|
||||
|
||||
api.sortTask = function(req, res, next) {
|
||||
var from, id, path, to, type, user, _ref;
|
||||
id = req.params.id;
|
||||
_ref = req.body, to = _ref.to, from = _ref.from, type = _ref.type;
|
||||
user = res.locals.user;
|
||||
path = "" + type + "Ids";
|
||||
user[path].splice(to, 0, user[path].splice(from, 1)[0]);
|
||||
return user.save(function(err, saved) {
|
||||
if (err) {
|
||||
return res.json(500, {
|
||||
err: err
|
||||
});
|
||||
}
|
||||
return res.json(200, saved.toJSON()[path]);
|
||||
var id = req.params.id;
|
||||
var to = req.body.to, from = req.body.from, type = req.body.type;
|
||||
var user = res.locals.user;
|
||||
user[type+'s'].splice(to, 0, user[type+'s'].splice(from, 1)[0]);
|
||||
user.save(function(err, saved) {
|
||||
if (err) return res.json(500, {err: err});
|
||||
return res.json(200, saved.toJSON()[type+'s']);
|
||||
});
|
||||
};
|
||||
|
||||
api.clearCompleted = function(req, res, next) {
|
||||
var completedIds, todoIds, user;
|
||||
user = res.locals.user;
|
||||
completedIds = _.pluck(_.where(user.tasks, {
|
||||
type: 'todo',
|
||||
completed: true
|
||||
}), 'id');
|
||||
todoIds = user.todoIds;
|
||||
_.each(completedIds, function(id) {
|
||||
delete user.tasks[id];
|
||||
return true;
|
||||
});
|
||||
user.todoIds = _.difference(todoIds, completedIds);
|
||||
var user = res.locals.user;
|
||||
user.todos = _.where(user.todos, {completed: false});
|
||||
return user.save(function(err, saved) {
|
||||
if (err) {
|
||||
return res.json(500, {
|
||||
err: err
|
||||
});
|
||||
}
|
||||
if (err) return res.json(500, {err: err});
|
||||
return res.json(saved);
|
||||
});
|
||||
};
|
||||
|
|
@ -379,31 +242,21 @@ api.clearCompleted = function(req, res, next) {
|
|||
Items
|
||||
------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
api.buy = function(req, res, next) {
|
||||
var hasEnough, type, user;
|
||||
user = res.locals.user;
|
||||
type = req.params.type;
|
||||
if (type !== 'weapon' && type !== 'armor' && type !== 'head' && type !== 'shield' && type !== 'potion') {
|
||||
return res.json(400, {
|
||||
err: ":type must be in one of: 'weapon', 'armor', 'head', 'shield', 'potion'"
|
||||
});
|
||||
return res.json(400, {err: ":type must be in one of: 'weapon', 'armor', 'head', 'shield', 'potion'"});
|
||||
}
|
||||
hasEnough = items.buyItem(user, type);
|
||||
if (hasEnough) {
|
||||
return user.save(function(err, saved) {
|
||||
if (err) {
|
||||
return res.json(500, {
|
||||
err: err
|
||||
});
|
||||
}
|
||||
if (err) return res.json(500, {err: err});
|
||||
return res.json(200, saved.toJSON().items);
|
||||
});
|
||||
} else {
|
||||
return res.json(200, {
|
||||
err: "Not enough GP"
|
||||
});
|
||||
return res.json(200, {err: "Not enough GP"});
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -413,11 +266,9 @@ api.buy = function(req, res, next) {
|
|||
------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
Get User
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Get User
|
||||
*/
|
||||
api.getUser = function(req, res, next) {
|
||||
var user = res.locals.user.toJSON();
|
||||
user.stats.toNextLevel = algos.tnl(user.stats.lvl);
|
||||
|
|
@ -430,12 +281,10 @@ api.getUser = function(req, res, next) {
|
|||
return res.json(200, user);
|
||||
};
|
||||
|
||||
/*
|
||||
Update user
|
||||
FIXME add documentation here
|
||||
/**
|
||||
* Update user
|
||||
* FIXME add documentation here
|
||||
*/
|
||||
|
||||
|
||||
api.updateUser = function(req, res, next) {
|
||||
var acceptableAttrs, errors, user;
|
||||
user = res.locals.user;
|
||||
|
|
@ -483,8 +332,7 @@ api.updateUser = function(req, res, next) {
|
|||
};
|
||||
|
||||
api.cron = function(req, res, next) {
|
||||
var user;
|
||||
user = res.locals.user;
|
||||
var user = res.locals.user;
|
||||
algos.cron(user);
|
||||
if (user.isModified()) {
|
||||
res.locals.wasModified = true;
|
||||
|
|
@ -494,52 +342,36 @@ api.cron = function(req, res, next) {
|
|||
};
|
||||
|
||||
api.revive = function(req, res, next) {
|
||||
var user;
|
||||
user = res.locals.user;
|
||||
var user = res.locals.user;
|
||||
algos.revive(user);
|
||||
return user.save(function(err, saved) {
|
||||
if (err) {
|
||||
return res.json(500, {
|
||||
err: err
|
||||
});
|
||||
}
|
||||
user.save(function(err, saved) {
|
||||
if (err) return res.json(500, {err: err});
|
||||
return res.json(200, saved);
|
||||
});
|
||||
};
|
||||
|
||||
api.reroll = function(req, res, next) {
|
||||
var user;
|
||||
user = res.locals.user;
|
||||
if (user.balance < 1) {
|
||||
return res.json(401, {
|
||||
err: "Not enough tokens."
|
||||
});
|
||||
}
|
||||
var user = res.locals.user;
|
||||
if (user.balance < 1) return res.json(401, {err: "Not enough tokens."});
|
||||
user.balance -= 1;
|
||||
_.each(user.tasks, function(task) {
|
||||
if (task.type !== 'reward') {
|
||||
user.tasks[task.id].value = 0;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
_.each(['habits','dailys','todos'], function(type){
|
||||
_.each([user[type+'s']], function(task){
|
||||
task.value = 0;
|
||||
})
|
||||
})
|
||||
user.stats.hp = 50;
|
||||
return user.save(function(err, saved) {
|
||||
if (err) {
|
||||
return res.json(500, {
|
||||
err: err
|
||||
});
|
||||
}
|
||||
user.save(function(err, saved) {
|
||||
if (err) return res.json(500, {err: err});
|
||||
return res.json(200, saved);
|
||||
});
|
||||
};
|
||||
|
||||
api.reset = function(req, res){
|
||||
var user = res.locals.user;
|
||||
user.tasks = {};
|
||||
|
||||
_.each(['habit', 'daily', 'todo', 'reward'], function(type) {
|
||||
user[type + "Ids"] = [];
|
||||
});
|
||||
user.habits = [];
|
||||
user.dailys = [];
|
||||
user.todos = [];
|
||||
user.rewards = [];
|
||||
|
||||
user.stats.hp = 50;
|
||||
user.stats.lvl = 1;
|
||||
|
|
@ -675,9 +507,11 @@ api.deleteTag = function(req, res){
|
|||
delete user.filters[tag.id];
|
||||
user.tags.splice(i,1);
|
||||
// remove tag from all tasks
|
||||
_.each(user.tasks, function(task) {
|
||||
delete user.tasks[task.id].tags[tag.id];
|
||||
});
|
||||
_.each(['habits','dailys','todos','rewards'], function(type){
|
||||
_.each(user[type], function(task){
|
||||
delete task.tags[tag.id];
|
||||
})
|
||||
})
|
||||
user.save(function(err,saved){
|
||||
if (err) return res.json(500, {err: err});
|
||||
// Need to use this until we found a way to update the ui for tasks when a tag is deleted
|
||||
|
|
@ -695,22 +529,16 @@ api.deleteTag = function(req, res){
|
|||
Run a bunch of updates all at once
|
||||
------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
api.batchUpdate = function(req, res, next) {
|
||||
var actions, oldJson, oldSend, performAction, user, _ref;
|
||||
user = res.locals.user;
|
||||
oldSend = res.send;
|
||||
oldJson = res.json;
|
||||
performAction = function(action, cb) {
|
||||
/*
|
||||
# TODO come up with a more consistent approach here. like:
|
||||
# req.body=action.data; delete action.data; _.defaults(req.params, action)
|
||||
# Would require changing action.dir on mobile app
|
||||
*/
|
||||
var user = res.locals.user;
|
||||
var oldSend = res.send;
|
||||
var oldJson = res.json;
|
||||
var performAction = function(action, cb) {
|
||||
|
||||
var _ref;
|
||||
req.params.id = (_ref = action.data) != null ? _ref.id : void 0;
|
||||
// TODO come up with a more consistent approach here. like:
|
||||
// req.body=action.data; delete action.data; _.defaults(req.params, action)
|
||||
// Would require changing action.dir on mobile app
|
||||
req.params.id = action.data && action.data.id;
|
||||
req.params.direction = action.dir;
|
||||
req.params.type = action.type;
|
||||
req.body = action.data;
|
||||
|
|
@ -764,27 +592,22 @@ api.batchUpdate = function(req, res, next) {
|
|||
break;
|
||||
}
|
||||
};
|
||||
/* Setup the array of functions we're going to call in parallel with async*/
|
||||
|
||||
actions = _.transform((_ref = req.body) != null ? _ref : [], function(result, action) {
|
||||
// Setup the array of functions we're going to call in parallel with async
|
||||
var actions = _.transform(req.body || [], function(result, action) {
|
||||
if (!_.isEmpty(action)) {
|
||||
return result.push(function(cb) {
|
||||
return performAction(action, cb);
|
||||
result.push(function(cb) {
|
||||
performAction(action, cb);
|
||||
});
|
||||
}
|
||||
});
|
||||
/* call all the operations, then return the user object to the requester*/
|
||||
|
||||
return async.series(actions, function(err) {
|
||||
var response;
|
||||
// call all the operations, then return the user object to the requester
|
||||
async.series(actions, function(err) {
|
||||
res.json = oldJson;
|
||||
res.send = oldSend;
|
||||
if (err) {
|
||||
return res.json(500, {
|
||||
err: err
|
||||
});
|
||||
}
|
||||
response = user.toJSON();
|
||||
if (err) return res.json(500, {err: err});
|
||||
var response = user.toJSON();
|
||||
response.wasModified = res.locals.wasModified;
|
||||
if (response._tmp && response._tmp.drop) response.wasModified = true;
|
||||
|
||||
|
|
@ -794,7 +617,5 @@ api.batchUpdate = function(req, res, next) {
|
|||
}else{
|
||||
res.json(200, {_v: response._v});
|
||||
}
|
||||
|
||||
return;
|
||||
});
|
||||
};
|
||||
41
src/models/task.js
Normal file
41
src/models/task.js
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
// User.js
|
||||
// =======
|
||||
// Defines the user data model (schema) for use via the API.
|
||||
|
||||
// Dependencies
|
||||
// ------------
|
||||
var mongoose = require("mongoose");
|
||||
var Schema = mongoose.Schema;
|
||||
var helpers = require('habitrpg-shared/script/helpers');
|
||||
var _ = require('lodash');
|
||||
|
||||
// Task Schema
|
||||
// -----------
|
||||
|
||||
var TaskSchema = new Schema({
|
||||
history: [{date:Date, value:Number}],
|
||||
_id:{type: String,'default': helpers.uuid},
|
||||
text: String,
|
||||
notes: {type: String, 'default': ''},
|
||||
tags: Schema.Types.Mixed, //{ "4ddf03d9-54bd-41a3-b011-ca1f1d2e9371" : true },
|
||||
type: {type:String, 'default': 'habit'}, // habit, daily
|
||||
up: {type: Boolean, 'default': true},
|
||||
down: {type: Boolean, 'default': true},
|
||||
value: {type: Number, 'default': 0},
|
||||
completed: {type: Boolean, 'default': false},
|
||||
priority: {type: String, 'default': '!'}, //'!!' // FIXME this should be a number or something
|
||||
repeat: {type: Schema.Types.Mixed, 'default': {m:1, t:1, w:1, th:1, f:1, s:1, su:1} },
|
||||
streak: {type: Number, 'default': 0}
|
||||
});
|
||||
|
||||
TaskSchema.methods.toJSON = function() {
|
||||
var doc = this.toObject();
|
||||
doc.id = doc._id;
|
||||
return doc;
|
||||
}
|
||||
TaskSchema.virtual('id').get(function(){
|
||||
return this._id;
|
||||
})
|
||||
|
||||
module.exports.schema = TaskSchema;
|
||||
module.exports.model = mongoose.model("Task", TaskSchema);
|
||||
|
|
@ -8,6 +8,7 @@ var mongoose = require("mongoose");
|
|||
var Schema = mongoose.Schema;
|
||||
var helpers = require('habitrpg-shared/script/helpers');
|
||||
var _ = require('lodash');
|
||||
var TaskSchema = require('./task').schema;
|
||||
|
||||
// User Schema
|
||||
// -----------
|
||||
|
|
@ -204,26 +205,12 @@ var UserSchema = new Schema({
|
|||
}
|
||||
],
|
||||
|
||||
// ### Tasks Definition
|
||||
// We can't define `tasks` until we move off Derby, since Derby requires dictionary of objects. When we're off, migrate
|
||||
// to array of subdocs
|
||||
challenges: [{type: 'String', ref:'Challenge'}],
|
||||
|
||||
tasks: Schema.Types.Mixed
|
||||
/*
|
||||
# history: {date, value}
|
||||
# id
|
||||
# notes
|
||||
# tags { "4ddf03d9-54bd-41a3-b011-ca1f1d2e9371" : true },
|
||||
# text
|
||||
# type
|
||||
# up
|
||||
# down
|
||||
# value
|
||||
# completed
|
||||
# priority: '!!'
|
||||
# repeat {m: true, t: true}
|
||||
# streak
|
||||
*/
|
||||
habits: [TaskSchema],
|
||||
dailys: [TaskSchema],
|
||||
todos: [TaskSchema],
|
||||
rewards: [TaskSchema],
|
||||
|
||||
}, {
|
||||
strict: true,
|
||||
|
|
@ -237,7 +224,8 @@ var UserSchema = new Schema({
|
|||
// the underlying data will be modified too - so when we save back to the database, it saves it in the way Derby likes.
|
||||
// This will go away after the rewrite is complete
|
||||
|
||||
function transformTaskLists(doc) {
|
||||
//FIXME use this in migration
|
||||
/*function transformTaskLists(doc) {
|
||||
_.each(['habit', 'daily', 'todo', 'reward'], function(type) {
|
||||
// we use _.transform instead of a simple _.where in order to maintain sort-order
|
||||
doc[type + "s"] = _.reduce(doc[type + "Ids"], function(m, tid) {
|
||||
|
|
@ -247,36 +235,37 @@ function transformTaskLists(doc) {
|
|||
return m;
|
||||
}, []);
|
||||
});
|
||||
}
|
||||
|
||||
UserSchema.post('init', function(doc) {
|
||||
transformTaskLists(doc);
|
||||
});
|
||||
}*/
|
||||
|
||||
UserSchema.methods.toJSON = function() {
|
||||
var doc = this.toObject();
|
||||
doc.id = doc._id;
|
||||
transformTaskLists(doc); // we need to also transform for our server-side routes
|
||||
|
||||
// FIXME? Is this a reference to `doc.filters` or just disabled code? Remove?
|
||||
/*
|
||||
// Remove some unecessary data as far as client consumers are concerned
|
||||
//_.each(['habit', 'daily', 'todo', 'reward'], function(type) {
|
||||
// delete doc["#{type}Ids"]
|
||||
//});
|
||||
//delete doc.tasks
|
||||
*/
|
||||
doc.filters = {};
|
||||
doc._tmp = this._tmp; // be sure to send down drop notifs
|
||||
|
||||
// TODO why isnt' this happening automatically given the TaskSchema.methods.toJSON above?
|
||||
_.each(['habits','dailys','todos','rewards'], function(type){
|
||||
_.each(doc[type],function(task){
|
||||
task.id = task._id;
|
||||
})
|
||||
})
|
||||
|
||||
return doc;
|
||||
};
|
||||
|
||||
UserSchema.virtual('tasks').get(function () {
|
||||
var tasks = this.habits.concat(this.dailys).concat(this.todos).concat(this.rewards);
|
||||
var tasks = _.object(_.pluck(tasks,'id'), tasks);
|
||||
return tasks;
|
||||
});
|
||||
|
||||
// FIXME - since we're using special @post('init') above, we need to flag when the original path was modified.
|
||||
// Custom setter/getter virtuals?
|
||||
|
||||
UserSchema.pre('save', function(next) {
|
||||
this.markModified('tasks');
|
||||
//this.markModified('tasks'); //FIXME
|
||||
//our own version incrementer
|
||||
this._v++;
|
||||
next();
|
||||
|
|
|
|||
|
|
@ -11,14 +11,6 @@ router.get('/', function(req, res) {
|
|||
});
|
||||
});
|
||||
|
||||
router.get('/partials/tasks', function(req, res) {
|
||||
res.render('tasks/index', {env: res.locals.habitrpg});
|
||||
});
|
||||
|
||||
router.get('/partials/options', function(req, res) {
|
||||
res.render('options', {env: res.locals.habitrpg});
|
||||
});
|
||||
|
||||
// -------- Marketing --------
|
||||
|
||||
router.get('/splash.html', function(req, res) {
|
||||
|
|
|
|||
|
|
@ -71,7 +71,6 @@ html
|
|||
script(type='text/javascript', src='/js/controllers/settingsCtrl.js')
|
||||
script(type='text/javascript', src='/js/controllers/statsCtrl.js')
|
||||
script(type='text/javascript', src='/js/controllers/tasksCtrl.js')
|
||||
script(type='text/javascript', src='/js/controllers/taskDetailsCtrl.js')
|
||||
script(type='text/javascript', src='/js/controllers/filtersCtrl.js')
|
||||
script(type='text/javascript', src='/js/controllers/userCtrl.js')
|
||||
script(type='text/javascript', src='/js/controllers/groupsCtrl.js')
|
||||
|
|
@ -91,6 +90,10 @@ html
|
|||
include ./shared/modals/index
|
||||
include ./shared/header/header
|
||||
|
||||
include ./shared/tasks/lists
|
||||
include ./main/index
|
||||
include ./options/index
|
||||
|
||||
#notification-area(ng-controller='NotificationCtrl')
|
||||
#wrap
|
||||
|
||||
|
|
|
|||
4
views/main/index.jade
Normal file
4
views/main/index.jade
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
script(id='templates/habitrpg-main.html', type="text/ng-template")
|
||||
include ./filters
|
||||
div(ng-controller='TasksCtrl')
|
||||
habitrpg-tasks(main='true', obj='user')
|
||||
|
|
@ -1,60 +1,64 @@
|
|||
.grid
|
||||
.module.full-width
|
||||
span.option-box.pull-right.wallet
|
||||
include ../shared/gems
|
||||
script(id='templates/habitrpg-options.html', type="text/ng-template")
|
||||
.grid
|
||||
.module.full-width
|
||||
span.option-box.pull-right.wallet
|
||||
include ../shared/gems
|
||||
|
||||
ul.nav.nav-tabs
|
||||
li.active
|
||||
a(data-toggle='tab', data-target='#profile-tab')
|
||||
i.icon-user
|
||||
| Profile
|
||||
li
|
||||
a(data-toggle='tab',data-target='#groups-tab', ng-click='fetchParty()')
|
||||
i.icon-heart
|
||||
| Groups
|
||||
li(ng-show='user.flags.dropsEnabled')
|
||||
a(data-toggle='tab',data-target='#inventory-tab')
|
||||
i.icon-gift
|
||||
| Inventory
|
||||
li(ng-show='user.flags.dropsEnabled')
|
||||
a(data-toggle='tab',data-target='#stable-tab')
|
||||
i.icon-leaf
|
||||
| Stable
|
||||
li
|
||||
a(data-toggle='tab',data-target='#tavern-tab',ng-click='fetchTavern()')
|
||||
i.icon-eye-close
|
||||
| Tavern
|
||||
li
|
||||
a(data-toggle='tab',data-target='#achievements-tab')
|
||||
i.icon-certificate
|
||||
| Achievements
|
||||
ul.nav.nav-tabs
|
||||
li.active
|
||||
a(data-toggle='tab', data-target='#profile-tab')
|
||||
i.icon-user
|
||||
| Profile
|
||||
li
|
||||
a(data-toggle='tab',data-target='#groups-tab', ng-click='fetchParty()')
|
||||
i.icon-heart
|
||||
| Groups
|
||||
li(ng-show='user.flags.dropsEnabled')
|
||||
a(data-toggle='tab',data-target='#inventory-tab')
|
||||
i.icon-gift
|
||||
| Inventory
|
||||
li(ng-show='user.flags.dropsEnabled')
|
||||
a(data-toggle='tab',data-target='#stable-tab')
|
||||
i.icon-leaf
|
||||
| Stable
|
||||
li
|
||||
a(data-toggle='tab',data-target='#tavern-tab', ng-click='fetchTavern()')
|
||||
i.icon-eye-close
|
||||
| Tavern
|
||||
li
|
||||
a(data-toggle='tab',data-target='#achievements-tab')
|
||||
i.icon-certificate
|
||||
| Achievements
|
||||
//-li
|
||||
a(data-toggle='tab',data-target='#challenges-tab')
|
||||
i.icon-bullhorn
|
||||
| Challenges
|
||||
li
|
||||
a(data-toggle='tab',data-target='#settings-tab')
|
||||
i.icon-wrench
|
||||
| Settings
|
||||
|
||||
li
|
||||
a(data-toggle='tab',data-target='#settings-tab')
|
||||
i.icon-wrench
|
||||
| Settings
|
||||
.tab-content
|
||||
.tab-pane.active#profile-tab
|
||||
include ./profile
|
||||
|
||||
.tab-content
|
||||
.tab-pane.active#profile-tab
|
||||
include ./profile
|
||||
.tab-pane#groups-tab
|
||||
include ./groups/index
|
||||
|
||||
.tab-pane#groups-tab
|
||||
include ./groups/index
|
||||
.tab-pane#inventory-tab
|
||||
include ./inventory
|
||||
|
||||
.tab-pane#inventory-tab
|
||||
include ./inventory
|
||||
.tab-pane#stable-tab
|
||||
include ./pets
|
||||
|
||||
.tab-pane#stable-tab
|
||||
include ./pets
|
||||
.tab-pane#tavern-tab
|
||||
include ./groups/tavern
|
||||
|
||||
.tab-pane#tavern-tab
|
||||
include ./groups/tavern
|
||||
.tab-pane#achievements-tab(ng-controller='UserCtrl')
|
||||
include ../shared/profiles/achievements
|
||||
|
||||
.tab-pane#achievements-tab(ng-controller='UserCtrl')
|
||||
include ../shared/profiles/achievements
|
||||
.tab-pane#challenges-tab
|
||||
include ./challenges/index
|
||||
|
||||
// <li><a data-toggle='tab' data-target="#profile-challenges" id='profile-challenges-tab-link' ><i class='icon-bullhorn'></i> Challenges</a></li>
|
||||
// app:challenges:main
|
||||
|
||||
.tab-pane#settings-tab
|
||||
include ./settings
|
||||
.tab-pane#settings-tab
|
||||
include ./settings
|
||||
|
|
@ -1,12 +1,14 @@
|
|||
div(ng-controller='TasksCtrl')
|
||||
include ./filters
|
||||
// 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")
|
||||
.grid
|
||||
.module(ng-controller='TasksCtrl', ng-repeat='list in taskLists', ng-class='{"rewards-module": list.type==="reward"}')
|
||||
.module(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='list.main && list.type=="todo"')
|
||||
a.option-action(ng-show='user.history.todos', ng-click='toggleChart("todos")', tooltip='Progress')
|
||||
span.option-box.pull-right(ng-if='main && list.type=="todo"')
|
||||
a.option-action(ng-show='obj.history.todos', ng-click='toggleChart("todos")', tooltip='Progress')
|
||||
i.icon-signal
|
||||
//-a.option-action(ng-href='/v1/users/{{user.id}}/calendar.ics?apiToken={{user.apiToken}}', tooltip='iCal')
|
||||
a.option-action(ng-click='notPorted()', tooltip='iCal', ng-show='false')
|
||||
|
|
@ -14,7 +16,7 @@ div(ng-controller='TasksCtrl')
|
|||
// <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>
|
||||
|
||||
// Gold & Gems
|
||||
span.option-box.pull-right.wallet(ng-if='list.main && list.type=="reward"')
|
||||
span.option-box.pull-right.wallet(ng-if='main && list.type=="reward"')
|
||||
.money
|
||||
| {{gold(user.stats.gp)}}
|
||||
span.shop_gold(tooltip='Gold')
|
||||
|
|
@ -29,18 +31,18 @@ div(ng-controller='TasksCtrl')
|
|||
.todos-chart(ng-if='list.type == "todo"', ng-show='charts.todos')
|
||||
|
||||
// Add New
|
||||
form.addtask-form.form-inline.new-task-form(name='new{{list.type}}form', ng-show='list.editable', ng-hide='list.showCompleted && list.type=="todo"', data-task-type='{{list.type}}', ng-submit='addTask(list)')
|
||||
form.addtask-form.form-inline.new-task-form(name='new{{list.type}}form', ng-show='editable', ng-hide='list.showCompleted && list.type=="todo"', ng-submit='addTask(list)')
|
||||
span.addtask-field
|
||||
input(type='text', ng-model='list.newTask', placeholder='{{list.placeHolder}}', required)
|
||||
input.addtask-btn(type='submit', value='+', ng-disabled='new{{list.type}}form.$invalid')
|
||||
hr
|
||||
|
||||
// Actual List
|
||||
ul(class='{{list.type}}s', ng-show='user[list.type + "s"].length > 0', habitrpg-sortable)
|
||||
ul(class='{{list.type}}s', ng-show='obj[list.type + "s"].length > 0', habitrpg-sortable)
|
||||
include ./task
|
||||
|
||||
// Static Rewards
|
||||
ul.items(ng-show='list.main && list.type=="reward" && user.flags.itemsEnabled')
|
||||
ul.items(ng-show='main && list.type=="reward" && user.flags.itemsEnabled')
|
||||
li.task.reward-item(ng-hide='item.hide', ng-repeat='item in itemStore')
|
||||
// right-hand side control buttons
|
||||
.task-meta-controls
|
||||
|
|
@ -59,14 +61,20 @@ div(ng-controller='TasksCtrl')
|
|||
|
||||
br
|
||||
|
||||
include ./ads
|
||||
// Ads
|
||||
div(ng-if='main && !user.purchased.ads && list.type!="reward"')
|
||||
span.pull-right
|
||||
a(ng-click='modals.buyGems=true', tooltip='Remove Ads')
|
||||
i.icon-remove
|
||||
// Habit3
|
||||
ins.adsbygoogle(ng-init='initAds()', style='display: inline-block; width: 234px; height: 60px;', data-ad-client='ca-pub-3242350243827794', data-ad-slot='9529624576')
|
||||
|
||||
// Todo Tabs
|
||||
div(ng-if='list.type=="todo"', ng-class='{"tabbable tabs-below": list.type=="todo"}')
|
||||
div(ng-if='main && list.type=="todo"', ng-class='{"tabbable tabs-below": list.type=="todo"}')
|
||||
button.task-action-btn.tile.spacious.bright(ng-show='list.showCompleted', ng-click='clearCompleted()') Clear Completed
|
||||
// remaining/completed tabs
|
||||
ul.nav.nav-tabs
|
||||
li(ng-class='{active: !list.showCompleted}')
|
||||
a(ng-click='list.showCompleted = false') Remaining
|
||||
li(ng-class='{active: list.showCompleted}')
|
||||
a(ng-click='list.showCompleted= true') Complete
|
||||
a(ng-click='list.showCompleted= true') Complete
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
li(ng-repeat='task in user[list.type + "s"]', class='task {{taskClasses(task,user.filters,user.preferences.dayStart,user.lastCron,list.showCompleted,list.main)}}', data-id='{{task.id}}')
|
||||
li(ng-repeat='task in list.tasks', class='task {{taskClasses(task, user.filters, user.preferences.dayStart, user.lastCron, list.showCompleted, main)}}', data-id='{{task.id}}')
|
||||
// right-hand side control buttons
|
||||
.task-meta-controls
|
||||
// Due Date
|
||||
|
|
@ -12,25 +12,25 @@ li(ng-repeat='task in user[list.type + "s"]', class='task {{taskClasses(task,use
|
|||
i.icon-tags(tooltip='{{appliedTags(user.tags, task.tags)}}', ng-hide='noTags(task.tags)')
|
||||
|
||||
// edit
|
||||
a(ng-hide='task._editing', ng-click='toggleEdit(task)', tooltip='Edit')
|
||||
a(ng-hide='task._editing', ng-click='editTask(task)', tooltip='Edit')
|
||||
i.icon-pencil(ng-hide='task._editing')
|
||||
// cancel
|
||||
a(ng-hide='!task._editing', ng-click='toggleEdit(task)', tooltip='Cancel')
|
||||
a(ng-hide='!task._editing', ng-click='editTask(task)', tooltip='Cancel')
|
||||
i.icon-remove(ng-hide='!task._editing')
|
||||
//- challenges
|
||||
// {{#if :task.challenge}}
|
||||
// {{#if brokenChallengeLink(:task)}}
|
||||
// <i class='icon-bullhorn' style='background-color:red;' x-bind=click:tasks.toggleTaskEdit rel=tooltip title="Broken Challenge Link"></i>
|
||||
// {{else}}
|
||||
// <i class='icon-bullhorn' rel=tooltip title="Challenge Task"></i>
|
||||
// {{/}}
|
||||
// {{else}}
|
||||
// <!-- delete -->
|
||||
// <a x-bind="click:tasks.del" rel=tooltip title="Delete"><i class="icon-trash"></i></a>
|
||||
// {{/}}
|
||||
//- {{#if :task.challenge}}
|
||||
//- {{#if brokenChallengeLink(:task)}}
|
||||
//- <i class='icon-bullhorn' style='background-color:red;' x-bind=click:tasks.toggleTaskEdit rel=tooltip title="Broken Challenge Link"></i>
|
||||
//- {{else}}
|
||||
//- <i class='icon-bullhorn' rel=tooltip title="Challenge Task"></i>
|
||||
//- {{/}}
|
||||
//- {{else}}
|
||||
//- <!-- delete -->
|
||||
//- <a x-bind="click:tasks.del" rel=tooltip title="Delete"><i class="icon-trash"></i></a>
|
||||
//- {{/}}
|
||||
|
||||
// delete
|
||||
a(ng-click='remove(task)', tooltip='Delete')
|
||||
a(ng-click='removeTask(list.tasks, $index)', tooltip='Delete')
|
||||
i.icon-trash
|
||||
// chart
|
||||
a(ng-show='task.history', ng-click='toggleChart(task.id, task)', tooltip='Progress')
|
||||
|
|
@ -43,34 +43,20 @@ li(ng-repeat='task in user[list.type + "s"]', class='task {{taskClasses(task,use
|
|||
.task-controls.task-primary
|
||||
|
||||
// Habits
|
||||
span(ng-if='list.main && task.type=="habit"')
|
||||
// only allow scoring on main tasks, not when viewing others' public tasks or when creating challenges
|
||||
span(ng-if='task.type=="habit"')
|
||||
a.task-action-btn(ng-if='task.up', ng-click='score(task,"up")') +
|
||||
a.task-action-btn(ng-if='task.down', ng-click='score(task,"down")') -
|
||||
//span(ng-if='!list.main')
|
||||
// span.task-action-btn(ng-show='task.up') +
|
||||
// span.task-action-btn(ng-show='task.down') =
|
||||
|
||||
// Rewards
|
||||
span(ng-show='list.main && task.type=="reward"')
|
||||
// only allow scoring on main tasks, not when viewing others' public tasks or when creating challenges
|
||||
span(ng-show='task.type=="reward"')
|
||||
a.money.btn-buy(ng-click='score(task, "down")')
|
||||
span.reward-cost {{task.value}}
|
||||
span.shop_gold
|
||||
//span(ng-if='!list.main')
|
||||
// span.money.btn-buy
|
||||
// span.reward-cost {{task.value}}
|
||||
// span.shop_gold
|
||||
|
||||
// Daily & Todos
|
||||
span.task-checker.action-yesno(ng-if='task.type=="daily" || task.type=="todo"')
|
||||
// only allow scoring on main tasks, not when viewing others' public tasks or when creating challenges
|
||||
//span(ng-if='list.main')
|
||||
input.visuallyhidden.focusable(id='box-{{task.id}}', type='checkbox', ng-model='task.completed', ng-change='changeCheck(task)')
|
||||
label(for='box-{{task.id}}')
|
||||
//span(ng-if='!list.main')
|
||||
// input.visuallyhidden.focusable(id='box-{{task.id}}-static',type='checkbox', checked='false')
|
||||
// label(for='box-{{task.id}}-static')
|
||||
// main content
|
||||
p.task-text
|
||||
// {{#if taskInChallenge(task)}}
|
||||
|
|
@ -99,7 +85,7 @@ li(ng-repeat='task in user[list.type + "s"]', class='task {{taskClasses(task,use
|
|||
// {{/}}
|
||||
// </div>
|
||||
// {/}
|
||||
form(ng-controller="TaskDetailsCtrl", ng-submit='save(task)')
|
||||
form(ng-submit='saveTask(task)')
|
||||
// text & notes
|
||||
fieldset.option-group
|
||||
// {{#unless taskInChallenge(task)}}
|
||||
|
|
@ -146,7 +132,7 @@ li(ng-repeat='task in user[list.type + "s"]', class='task {{taskClasses(task,use
|
|||
legend.option-title Due Date
|
||||
input.option-content.datepicker(type='text', data-date-format='mm/dd/yyyy', ng-model='task.date')
|
||||
|
||||
fieldset.option-group(ng-if='list.main')
|
||||
fieldset.option-group
|
||||
legend.option-title Tags
|
||||
label.checkbox(ng-repeat='tag in user.tags')
|
||||
input(type='checkbox', ng-model='task.tags[tag.id]')
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
div(ng-if='authenticated() && !user.purchased.ads')
|
||||
span.pull-right(ng-if='list.type!="reward"')
|
||||
a(ng-click='modals.buyGems=true', tooltip='Remove Ads')
|
||||
i.icon-remove
|
||||
|
||||
div(ng-if='list.type=="habit"', habitrpg-adsense)
|
||||
script(async='async', src='//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js')
|
||||
// Habit3
|
||||
ins.adsbygoogle(style='display: inline-block; width: 234px; height: 60px;', data-ad-client='ca-pub-3242350243827794', data-ad-slot='9529624576')
|
||||
script.
|
||||
(adsbygoogle = window.adsbygoogle || []).push({});
|
||||
|
||||
div(ng-if='list.type=="daily"', habitrpg-adsense)
|
||||
script(async='async', src='//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js')
|
||||
// Habit3
|
||||
ins.adsbygoogle(style='display: inline-block; width: 234px; height: 60px;', data-ad-client='ca-pub-3242350243827794', data-ad-slot='9529624576')
|
||||
script.
|
||||
(adsbygoogle = window.adsbygoogle || []).push({});
|
||||
|
||||
div(ng-if='list.type=="todo"', habitrpg-adsense)
|
||||
script(async='async', src='//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js')
|
||||
// Habit3
|
||||
ins.adsbygoogle(style='display: inline-block; width: 234px; height: 60px;', data-ad-client='ca-pub-3242350243827794', data-ad-slot='9529624576')
|
||||
script.
|
||||
(adsbygoogle = window.adsbygoogle || []).push({});
|
||||
Loading…
Reference in a new issue