mirror of
https://github.com/sudoxnym/habitica-self-host.git
synced 2026-04-14 19:47:03 +00:00
rewrite2 WIP
This commit is contained in:
parent
a00bd3dcf1
commit
3c45220e1f
130 changed files with 3452 additions and 558 deletions
|
|
@ -1,5 +0,0 @@
|
|||
.DS_Store
|
||||
public/gen/
|
||||
#lib/
|
||||
*.swp
|
||||
.idea/
|
||||
3
.bowerrc
Normal file
3
.bowerrc
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"directory": "assets/bower_components"
|
||||
}
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -1,12 +1,12 @@
|
|||
.DS_Store
|
||||
public/gen
|
||||
node_modules
|
||||
#lib/
|
||||
*.swp
|
||||
.idea*
|
||||
config.json
|
||||
npm-debug.log
|
||||
lib
|
||||
assets/bower_components
|
||||
|
||||
src/*/*.js
|
||||
src/*/*.map
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
@import "nib/vendor";
|
||||
//@import "nib/vendor";
|
||||
|
||||
// Vendor Includes - include first so we can override
|
||||
@import "../../public/vendor/bootstrap/css/bootstrap.min.css";
|
||||
@import "../../public/vendor/bootstrap/css/bootstrap-responsive.min.css";
|
||||
@import "../../public/vendor/datepicker/css/datepicker.css";
|
||||
@import "../../../public/vendor/datepicker/css/datepicker.css";
|
||||
|
||||
// Custom includes
|
||||
@import "./female_sprites.styl";
|
||||
|
|
@ -15,8 +13,8 @@
|
|||
@import "./items.styl";
|
||||
@import "./inventory.styl";
|
||||
@import "./alerts.styl";
|
||||
@import "../../public/img/sprites/pet_sprites.css";
|
||||
@import "../../public/img/sprites/PetEggs.css";
|
||||
@import "../../../public/img/sprites/pet_sprites.css";
|
||||
@import "../../../public/img/sprites/PetEggs.css";
|
||||
@import "./helpers.styl";
|
||||
@import "./responsive.styl";
|
||||
@import "./header.styl";
|
||||
12
assets/js/app.coffee
Normal file
12
assets/js/app.coffee
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
"use strict"
|
||||
|
||||
###
|
||||
The main HabitRPG app module.
|
||||
|
||||
@type {angular.Module}
|
||||
###
|
||||
|
||||
# .constant('API_URL', 'https://beta.habitrpg.com')
|
||||
# userServices handles redirect to /login if not authenticated
|
||||
window.habitrpg = angular.module('habitrpg', ['userServices', 'sharedServices', 'authServices', 'notificationServices', 'ui.bootstrap'])
|
||||
.constant("API_URL", "http://localhost:3000")
|
||||
|
|
@ -14,19 +14,19 @@ loadJavaScripts = (model) ->
|
|||
###
|
||||
Internal Scripts
|
||||
###
|
||||
require "../../public/vendor/jquery-ui-1.10.2/jquery-1.9.1"
|
||||
require "../../public/vendor/jquery.cookie.min"
|
||||
require "../../public/vendor/bootstrap/js/bootstrap.min"
|
||||
require "../../public/vendor/jquery.bootstrap-growl.min"
|
||||
require "../../public/vendor/datepicker/js/bootstrap-datepicker"
|
||||
require "../../public/vendor/bootstrap-tour/bootstrap-tour"
|
||||
require "../vendor/jquery-ui-1.10.2/jquery-1.9.1.js"
|
||||
require "../vendor/jquery.cookie.min.js"
|
||||
require "../vendor/bootstrap/js/bootstrap.min.js"
|
||||
require "../vendor/jquery.bootstrap-growl.min.js"
|
||||
require "../vendor/datepicker/js/bootstrap-datepicker"
|
||||
require "../vendor/bootstrap-tour/bootstrap-tour"
|
||||
|
||||
unless (model.get('_mobileDevice') is true)
|
||||
require "../../public/vendor/jquery-ui-1.10.2/ui/jquery.ui.core"
|
||||
require "../../public/vendor/jquery-ui-1.10.2/ui/jquery.ui.widget"
|
||||
require "../../public/vendor/jquery-ui-1.10.2/ui/jquery.ui.mouse"
|
||||
require "../../public/vendor/jquery-ui-1.10.2/ui/jquery.ui.sortable"
|
||||
require "../../public/vendor/sticky"
|
||||
require "../vendor/jquery-ui-1.10.2/ui/jquery.ui.core.js"
|
||||
require "../vendor/jquery-ui-1.10.2/ui/jquery.ui.widget.js"
|
||||
require "../vendor/jquery-ui-1.10.2/ui/jquery.ui.mouse.js"
|
||||
require "../vendor/jquery-ui-1.10.2/ui/jquery.ui.sortable.js"
|
||||
require "../vendor/sticky"
|
||||
|
||||
# note: external script loading is handled in app.on('render') near the bottom of this file (see https://groups.google.com/forum/?fromgroups=#!topic/derbyjs/x8FwdTLEuXo)
|
||||
|
||||
304
assets/js/browser.js
Normal file
304
assets/js/browser.js
Normal file
|
|
@ -0,0 +1,304 @@
|
|||
// Generated by CoffeeScript 1.6.3
|
||||
(function() {
|
||||
var amazonAffiliate, googleAnalytics, googleCharts, growlNotification, initStickyHeader, loadJavaScripts, moment, setupGrowlNotifications, setupSortable, setupTooltips, setupTour, _;
|
||||
|
||||
_ = require('lodash');
|
||||
|
||||
moment = require('moment');
|
||||
|
||||
/*
|
||||
Loads JavaScript files from public/vendor/*
|
||||
Use require() to min / concatinate for faster page load
|
||||
*/
|
||||
|
||||
|
||||
loadJavaScripts = function(model) {
|
||||
/*
|
||||
Internal Scripts
|
||||
*/
|
||||
|
||||
require("../vendor/jquery-ui-1.10.2/jquery-1.9.1.js");
|
||||
require("../vendor/jquery.cookie.min.js");
|
||||
require("../vendor/bootstrap/js/bootstrap.min.js");
|
||||
require("../vendor/jquery.bootstrap-growl.min.js");
|
||||
require("../vendor/datepicker/js/bootstrap-datepicker");
|
||||
require("../vendor/bootstrap-tour/bootstrap-tour");
|
||||
if (!(model.get('_mobileDevice') === true)) {
|
||||
require("../vendor/jquery-ui-1.10.2/ui/jquery.ui.core.js");
|
||||
require("../vendor/jquery-ui-1.10.2/ui/jquery.ui.widget.js");
|
||||
require("../vendor/jquery-ui-1.10.2/ui/jquery.ui.mouse.js");
|
||||
require("../vendor/jquery-ui-1.10.2/ui/jquery.ui.sortable.js");
|
||||
return require("../vendor/sticky");
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Setup jQuery UI Sortable
|
||||
*/
|
||||
|
||||
|
||||
setupSortable = function(model) {
|
||||
if (!(model.get('_mobileDevice') === true)) {
|
||||
return ['habit', 'daily', 'todo', 'reward'].forEach(function(type) {
|
||||
return $("ul." + type + "s").sortable({
|
||||
dropOnEmpty: false,
|
||||
cursor: "move",
|
||||
items: "li",
|
||||
scroll: true,
|
||||
axis: 'y',
|
||||
update: function(e, ui) {
|
||||
var domId, id, item, to;
|
||||
item = ui.item[0];
|
||||
domId = item.id;
|
||||
id = item.getAttribute('data-id');
|
||||
to = $("ul." + type + "s").children().index(item);
|
||||
return model.at("_" + type + "List").pass({
|
||||
ignore: domId
|
||||
}).move({
|
||||
id: id
|
||||
}, to);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
setupTooltips = module.exports.setupTooltips = function() {
|
||||
$('[rel=tooltip]').tooltip();
|
||||
$('[rel=popover]').popover();
|
||||
$('.popover-auto-show').popover('show');
|
||||
return $('.priority-multiplier-help').popover({
|
||||
title: "How difficult is this task?",
|
||||
trigger: "hover",
|
||||
content: "This multiplies its point value. Use sparingly, rely instead on our organic value-adjustment algorithms. But some tasks are grossly more valuable (Write Thesis vs Floss Teeth). Click for more info."
|
||||
});
|
||||
};
|
||||
|
||||
setupTour = function(model) {
|
||||
var tour, tourSteps;
|
||||
tourSteps = [
|
||||
{
|
||||
element: ".main-herobox",
|
||||
title: "Welcome to HabitRPG",
|
||||
content: "Welcome to HabitRPG, a habit-tracker which treats your goals like a Role Playing Game."
|
||||
}, {
|
||||
element: "#bars",
|
||||
title: "Achieve goals and level up",
|
||||
content: "As you accomplish goals, you level up. If you fail your goals, you lose hit points. Lose all your HP and you die."
|
||||
}, {
|
||||
element: "ul.habits",
|
||||
title: "Habits",
|
||||
content: "Habits are goals that you constantly track.",
|
||||
placement: "bottom"
|
||||
}, {
|
||||
element: "ul.dailys",
|
||||
title: "Dailies",
|
||||
content: "Dailies are goals that you want to complete once a day.",
|
||||
placement: "bottom"
|
||||
}, {
|
||||
element: "ul.todos",
|
||||
title: "Todos",
|
||||
content: "Todos are one-off goals which need to be completed eventually.",
|
||||
placement: "bottom"
|
||||
}, {
|
||||
element: "ul.rewards",
|
||||
title: "Rewards",
|
||||
content: "As you complete goals, you earn gold to buy rewards. Buy them liberally - rewards are integral in forming good habits.",
|
||||
placement: "bottom"
|
||||
}, {
|
||||
element: "ul.habits li:first-child",
|
||||
title: "Hover over comments",
|
||||
content: "Different task-types have special properties. Hover over each task's comment for more information. When you're ready to get started, delete the existing tasks and add your own.",
|
||||
placement: "right"
|
||||
}
|
||||
];
|
||||
$('.main-herobox').popover('destroy');
|
||||
tour = new Tour();
|
||||
tourSteps.forEach(function(step) {
|
||||
return tour.addStep(_.defaults(step, {
|
||||
html: true
|
||||
}));
|
||||
});
|
||||
if (isNaN(tour._current)) {
|
||||
tour._current = 0;
|
||||
}
|
||||
return tour.start();
|
||||
};
|
||||
|
||||
initStickyHeader = function(model) {
|
||||
return $('.header-wrap').sticky({
|
||||
topSpacing: 0
|
||||
});
|
||||
};
|
||||
|
||||
growlNotification = module.exports.growlNotification = function(html, type) {
|
||||
return $.bootstrapGrowl(html, {
|
||||
ele: '#notification-area',
|
||||
type: type,
|
||||
top_offset: 20,
|
||||
align: 'right',
|
||||
width: 250,
|
||||
delay: 3000,
|
||||
allow_dismiss: true,
|
||||
stackup_spacing: 10
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
Sets up "+1 Exp", "Level Up", etc notifications
|
||||
*/
|
||||
|
||||
|
||||
setupGrowlNotifications = function(model) {
|
||||
var showCoins, statsNotification, user;
|
||||
if (typeof jQuery === "undefined" || jQuery === null) {
|
||||
return;
|
||||
}
|
||||
user = model.at('_user');
|
||||
statsNotification = function(html, type) {
|
||||
if (user.get('stats.lvl') === 0) {
|
||||
return;
|
||||
}
|
||||
return growlNotification(html, type);
|
||||
};
|
||||
user.on('set', 'stats.hp', function(captures, args) {
|
||||
var num, rounded;
|
||||
num = captures - args;
|
||||
rounded = Math.abs(num.toFixed(1));
|
||||
if (num < 0) {
|
||||
return statsNotification("<i class='icon-heart'></i> - " + rounded + " HP", 'hp');
|
||||
} else if (num > 0) {
|
||||
return statsNotification("<i class='icon-heart'></i> + " + rounded + " HP", 'hp');
|
||||
}
|
||||
});
|
||||
user.on('set', 'stats.exp', function(captures, args, isLocal, silent) {
|
||||
var num, rounded;
|
||||
if (silent == null) {
|
||||
silent = false;
|
||||
}
|
||||
num = captures - args;
|
||||
rounded = Math.abs(num.toFixed(1));
|
||||
if (num < 0 && num > -50) {
|
||||
return statsNotification("<i class='icon-star'></i> - " + rounded + " XP", 'xp');
|
||||
} else if (num > 0) {
|
||||
return statsNotification("<i class='icon-star'></i> + " + rounded + " XP", 'xp');
|
||||
}
|
||||
});
|
||||
/*
|
||||
Show "+ 5 {gold_coin} 3 {silver_coin}"
|
||||
*/
|
||||
|
||||
showCoins = function(money) {
|
||||
var absolute, gold, silver;
|
||||
absolute = Math.abs(money);
|
||||
gold = Math.floor(absolute);
|
||||
silver = Math.floor((absolute - gold) * 100);
|
||||
if (gold && silver > 0) {
|
||||
return "" + gold + " <i class='icon-gold'></i> " + silver + " <i class='icon-silver'></i>";
|
||||
} else if (gold > 0) {
|
||||
return "" + gold + " <i class='icon-gold'></i>";
|
||||
} else if (silver > 0) {
|
||||
return "" + silver + " <i class='icon-silver'></i>";
|
||||
}
|
||||
};
|
||||
user.on('set', 'stats.gp', function(captures, args) {
|
||||
var bonus, money, sign;
|
||||
money = captures - args;
|
||||
if (!money) {
|
||||
return;
|
||||
}
|
||||
sign = money < 0 ? '-' : '+';
|
||||
statsNotification("" + sign + " " + (showCoins(money)), 'gp');
|
||||
bonus = model.get('_streakBonus');
|
||||
if ((money > 0) && !!bonus) {
|
||||
if (bonus < 0.01) {
|
||||
bonus = 0.01;
|
||||
}
|
||||
statsNotification("+ " + (showCoins(bonus)) + " Streak Bonus!");
|
||||
return model.del('_streakBonus');
|
||||
}
|
||||
});
|
||||
user.on('set', 'items.*', function(item, after, before) {
|
||||
if ((item === 'armor' || item === 'weapon' || item === 'shield' || item === 'head') && parseInt(after) < parseInt(before)) {
|
||||
if (item === 'head') {
|
||||
item = 'helm';
|
||||
}
|
||||
return statsNotification("<i class='icon-death'></i> Respawn!", "death");
|
||||
}
|
||||
});
|
||||
return user.on('set', 'stats.lvl', function(captures, args) {
|
||||
if (captures > args) {
|
||||
return statsNotification('<i class="icon-chevron-up"></i> Level Up!', 'lvl');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
module.exports.resetDom = function(model) {
|
||||
window.DERBY.app.dom.clear();
|
||||
return window.DERBY.app.view.render(model, window.DERBY.app.view._lastRender.ns, window.DERBY.app.view._lastRender.context);
|
||||
};
|
||||
|
||||
googleAnalytics = function(model) {
|
||||
if (model.flags.nodeEnv === 'production') {
|
||||
window._gaq = [["_setAccount", "UA-33510635-1"], ["_setDomainName", "habitrpg.com"], ["_trackPageview"]];
|
||||
return $.getScript(("https:" === document.location.protocol ? "https://ssl" : "http://www") + ".google-analytics.com/ga.js");
|
||||
}
|
||||
};
|
||||
|
||||
amazonAffiliate = function(model) {
|
||||
if (model.get('_loggedIn') && (model.get('_user.flags.ads') !== 'hide')) {
|
||||
return $.getScript('//wms.assoc-amazon.com/20070822/US/js/link-enhancer-common.js?tag=ha0d2-20').fail(function() {
|
||||
return $('body').append('<img src="//wms.assoc-amazon.com/20070822/US/img/noscript.gif?tag=ha0d2-20" alt="" />');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
googleCharts = function() {
|
||||
return $.getScript("//www.google.com/jsapi", function() {
|
||||
return google.load("visualization", "1", {
|
||||
packages: ["corechart"],
|
||||
callback: function() {}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
module.exports.app = function(appExports, model, app) {
|
||||
loadJavaScripts(model);
|
||||
if (!model.get('_mobileDevice')) {
|
||||
setupGrowlNotifications(model);
|
||||
}
|
||||
return app.on('render', function(ctx) {
|
||||
if (!model.get('_mobileDevice')) {
|
||||
setupTooltips(model);
|
||||
initStickyHeader(model);
|
||||
setupSortable(model);
|
||||
setupTour(model);
|
||||
}
|
||||
$('.datepicker').datepicker({
|
||||
autoclose: true,
|
||||
todayBtn: true
|
||||
}).on('changeDate', function(ev) {
|
||||
return model.at(ev.target).set('date', moment(ev.date).format('MM/DD/YYYY'));
|
||||
});
|
||||
/*
|
||||
External Scripts
|
||||
JS files not needed right away (google charts) or entirely optional (analytics)
|
||||
Each file getsload asyncronously via $.getScript, so it doesn't bog page-load
|
||||
These need to be handled in app.on('render'), see https://groups.google.com/forum/?fromgroups=#!topic/derbyjs/x8FwdTLEuXo
|
||||
*/
|
||||
|
||||
$.getScript('//checkout.stripe.com/v2/checkout.js');
|
||||
if (!(model.get('_mobileDevice') === true)) {
|
||||
$.getScript("//s7.addthis.com/js/250/addthis_widget.js#pubid=lefnire");
|
||||
googleCharts();
|
||||
}
|
||||
googleAnalytics(model);
|
||||
return amazonAffiliate(model);
|
||||
});
|
||||
};
|
||||
|
||||
}).call(this);
|
||||
|
||||
/*
|
||||
//@ sourceMappingURL=browser.map
|
||||
*/
|
||||
10
assets/js/browser.map
Normal file
10
assets/js/browser.map
Normal file
File diff suppressed because one or more lines are too long
148
assets/js/challenges.js
Normal file
148
assets/js/challenges.js
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
// Generated by CoffeeScript 1.6.3
|
||||
(function() {
|
||||
var helpers, _;
|
||||
|
||||
_ = require('lodash');
|
||||
|
||||
helpers = require('habitrpg-shared/script/helpers');
|
||||
|
||||
module.exports.app = function(appExports, model) {
|
||||
var browser, challengeDiscard, user;
|
||||
browser = require('./browser');
|
||||
user = model.at('_user');
|
||||
$('#profile-challenges-tab-link').on('show', function(e) {
|
||||
return _.each(model.get('groups'), function(g) {
|
||||
return _.each(g.challenges, function(chal) {
|
||||
return _.each(['habit', 'daily', 'todo'], function(type) {
|
||||
return _.each(chal["" + type + "s"], function(task) {
|
||||
return _.each(chal.users, function(member) {
|
||||
var chart, data, history, options, _ref, _ref1;
|
||||
if ((history = member != null ? (_ref = member["" + type + "s"]) != null ? (_ref1 = _ref[task.id]) != null ? _ref1.history : void 0 : void 0 : void 0) && !!history) {
|
||||
data = google.visualization.arrayToDataTable(_.map(history, function(h) {
|
||||
return [h.date, h.value];
|
||||
}));
|
||||
options = {
|
||||
backgroundColor: {
|
||||
fill: 'transparent'
|
||||
},
|
||||
width: 150,
|
||||
height: 50,
|
||||
chartArea: {
|
||||
width: '80%',
|
||||
height: '80%'
|
||||
},
|
||||
axisTitlePosition: 'none',
|
||||
legend: {
|
||||
position: 'bottom'
|
||||
},
|
||||
hAxis: {
|
||||
gridlines: {
|
||||
color: 'transparent'
|
||||
}
|
||||
},
|
||||
vAxis: {
|
||||
gridlines: {
|
||||
color: 'transparent'
|
||||
}
|
||||
}
|
||||
};
|
||||
chart = new google.visualization.LineChart($(".challenge-" + chal.id + "-member-" + member.id + "-history-" + task.id)[0]);
|
||||
return chart.draw(data, options);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
appExports.challengeCreate = function(e, el) {
|
||||
var gid, type, _ref;
|
||||
_ref = [$(el).attr('data-type'), $(el).attr('data-gid')], type = _ref[0], gid = _ref[1];
|
||||
return model.set('_challenge.new', {
|
||||
name: '',
|
||||
habits: [],
|
||||
dailys: [],
|
||||
todos: [],
|
||||
rewards: [],
|
||||
id: model.id(),
|
||||
uid: user.get('id'),
|
||||
user: helpers.username(model.get('_user.auth'), model.get('_user.profile.name')),
|
||||
group: {
|
||||
type: type,
|
||||
id: gid
|
||||
},
|
||||
timestamp: +(new Date)
|
||||
});
|
||||
};
|
||||
appExports.challengeSave = function() {
|
||||
var gid;
|
||||
gid = model.get('_challenge.new.group.id');
|
||||
return model.unshift("groups." + gid + ".challenges", model.get('_challenge.new'), function() {
|
||||
browser.growlNotification('Challenge Created', 'success');
|
||||
return challengeDiscard();
|
||||
});
|
||||
};
|
||||
appExports.toggleChallengeEdit = function(e, el) {
|
||||
var path;
|
||||
path = "_editing.challenges." + ($(el).attr('data-id'));
|
||||
return model.set(path, !model.get(path));
|
||||
};
|
||||
appExports.challengeDiscard = challengeDiscard = function() {
|
||||
return model.del('_challenge.new');
|
||||
};
|
||||
appExports.challengeSubscribe = function(e) {
|
||||
var chal, tags, userChallenges;
|
||||
chal = e.get();
|
||||
tags = user.get('tags');
|
||||
if (!(tags && _.find(tags, {
|
||||
id: chal.id
|
||||
}))) {
|
||||
model.push('_user.tags', {
|
||||
id: chal.id,
|
||||
name: chal.name,
|
||||
challenge: true
|
||||
});
|
||||
}
|
||||
tags = {};
|
||||
tags[chal.id] = true;
|
||||
userChallenges = user.get('challenges');
|
||||
if (!(userChallenges && (userChallenges.indexOf(chal.id) !== -1))) {
|
||||
user.unshift('challenges', chal.id);
|
||||
}
|
||||
return _.each(['habit', 'daily', 'todo', 'reward'], function(type) {
|
||||
return _.each(chal["" + type + "s"], function(task) {
|
||||
task.tags = tags;
|
||||
task.challenge = chal.id;
|
||||
task.group = {
|
||||
id: chal.group.id,
|
||||
type: chal.group.type
|
||||
};
|
||||
model.push("_" + type + "List", task);
|
||||
return true;
|
||||
});
|
||||
});
|
||||
};
|
||||
return appExports.challengeUnsubscribe = function(e) {
|
||||
var chal, i, _ref;
|
||||
chal = e.get();
|
||||
i = (_ref = user.get('challenges')) != null ? _ref.indexOf(chal.id) : void 0;
|
||||
if ((i != null) && i !== -1) {
|
||||
user.remove("challenges." + i);
|
||||
}
|
||||
return _.each(['habit', 'daily', 'todo', 'reward'], function(type) {
|
||||
return _.each(chal["" + type + "s"], function(task) {
|
||||
model.remove("_" + type + "List", _.findIndex(model.get("_" + type + "List", {
|
||||
id: task.id
|
||||
})));
|
||||
model.del("_user.tasks." + task.id);
|
||||
return true;
|
||||
});
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
}).call(this);
|
||||
|
||||
/*
|
||||
//@ sourceMappingURL=challenges.map
|
||||
*/
|
||||
10
assets/js/challenges.map
Normal file
10
assets/js/challenges.map
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"version": 3,
|
||||
"file": "challenges.js",
|
||||
"sourceRoot": "",
|
||||
"sources": [
|
||||
"challenges.coffee"
|
||||
],
|
||||
"names": [],
|
||||
"mappings": "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"
|
||||
}
|
||||
13
assets/js/controllers/RootCtrl.coffee
Normal file
13
assets/js/controllers/RootCtrl.coffee
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
"use strict"
|
||||
|
||||
# Make user and settings available for everyone through root scope.
|
||||
habitrpg.controller "RootCtrl", ($scope, $rootScope, $location, User) ->
|
||||
$rootScope.User = User
|
||||
$rootScope.user = User.user
|
||||
$rootScope.settings = User.settings
|
||||
|
||||
# FIXME this is dangerous, organize helpers.coffee better, so we can group them by which controller needs them,
|
||||
# and then simply _.defaults($scope, Helpers.user) kinda thing
|
||||
_.defaults $rootScope, window.habitrpgShared.helpers
|
||||
$rootScope.authenticated = ->
|
||||
User.settings.auth.apiId isnt ""
|
||||
55
assets/js/controllers/authCtrl.coffee
Normal file
55
assets/js/controllers/authCtrl.coffee
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
"use strict"
|
||||
|
||||
###
|
||||
The authentication controller (login & facebook)
|
||||
###
|
||||
habitrpg.controller "AuthCtrl", ($scope, $rootScope, Facebook, LocalAuth, User, $http, $location, API_URL) ->
|
||||
$scope.useUUID = false
|
||||
debugger
|
||||
$scope.toggleUUID = ->
|
||||
if showedFacebookMessage is false
|
||||
alert "Until we add Facebook, use your UUID and API Token to log in (found at https://habitrpg.com > Options > Settings)."
|
||||
showedFacebookMessage = true
|
||||
$scope.useUUID = not $scope.useUUID
|
||||
|
||||
$scope.register = ->
|
||||
#TODO highlight invalid inputs
|
||||
# we have this as a workaround for https://github.com/HabitRPG/habitrpg-mobile/issues/64
|
||||
return if $scope.registrationForm.$invalid
|
||||
$http.post(API_URL + "/api/v1/register", $scope.registerVals).success((data, status, headers, config) ->
|
||||
User.authenticate data.id, data.apiToken, (err) ->
|
||||
$location.path "/habit"
|
||||
|
||||
).error (data, status, headers, config) ->
|
||||
if status is 0
|
||||
alert "Server not currently reachable, try again later"
|
||||
else if !!data and !!data.err
|
||||
alert data.err
|
||||
else
|
||||
alert "ERROR: " + status
|
||||
|
||||
|
||||
$scope.auth = ->
|
||||
data =
|
||||
username: $scope.loginUsername
|
||||
password: $scope.loginPassword
|
||||
|
||||
runAuth = (id, token) ->
|
||||
User.authenticate id, token, (err) ->
|
||||
$location.path "/habit"
|
||||
|
||||
|
||||
if $scope.useUUID
|
||||
runAuth $scope.loginUsername, $scope.loginPassword
|
||||
else
|
||||
$http.post(API_URL + "/api/v1/user/auth/local", data)
|
||||
.success((data, status, headers, config) ->
|
||||
runAuth data.id, data.token
|
||||
$scope.showing = false
|
||||
).error (data, status, headers, config) ->
|
||||
if status is 0
|
||||
alert "Server not currently reachable, try again later"
|
||||
else if !!data and !!data.err
|
||||
alert data.err
|
||||
else
|
||||
alert "ERROR: " + status
|
||||
40
assets/js/controllers/characterCtrl.js
Normal file
40
assets/js/controllers/characterCtrl.js
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
'use strict';
|
||||
|
||||
/**
|
||||
* The character controller:
|
||||
*
|
||||
*/
|
||||
|
||||
habitrpg.controller('CharacterCtrl',
|
||||
['$scope', '$location', 'User',
|
||||
function($scope, $location, User) {
|
||||
|
||||
$scope.user = User.user;
|
||||
|
||||
$scope.equipped = function(user, type) {
|
||||
var tier = (user.backer && user.backer.tier)
|
||||
return window.habitrpgShared.helpers.equipped(type, user.items[type], user.preferences, tier);
|
||||
}
|
||||
|
||||
$scope.$watch('user.tasks', function(){
|
||||
$scope.hpPercent = function(hp) {
|
||||
return (hp / 50) * 100;
|
||||
}
|
||||
|
||||
$scope.expPercent = function(exp, level) {
|
||||
return (exp / window.habitrpgShared.algos.tnl(level)) * 100;
|
||||
}
|
||||
})
|
||||
|
||||
$scope.floor = Math.floor;
|
||||
$scope.count = function(arr) {
|
||||
return _.size(arr);
|
||||
}
|
||||
$scope.tnl = window.habitrpgShared.algos.tnl;
|
||||
|
||||
$scope.showUserAvatar = function() {
|
||||
$('.userAvatar').show()
|
||||
}
|
||||
|
||||
}
|
||||
]);
|
||||
66
assets/js/controllers/menuCtrl.js
Normal file
66
assets/js/controllers/menuCtrl.js
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
'use strict';
|
||||
|
||||
/**
|
||||
* The menu controller:
|
||||
* - sets the menu options, should we do it dynamic so it generates the menu like: width = 1/elements * 100 ?
|
||||
* - exposes the model to the template and provides event handlers
|
||||
*/
|
||||
|
||||
habitrpg.controller('MenuCtrl',
|
||||
['$scope', '$rootScope', '$location', 'User',
|
||||
function($scope, $rootScope, $location, User) {
|
||||
|
||||
$scope.swiperight = function(){
|
||||
$scope.menuopen = true;
|
||||
}
|
||||
|
||||
$scope.swipeleft = function(){
|
||||
$scope.menuopen = false;
|
||||
}
|
||||
|
||||
$scope.menuClick = function(button) {
|
||||
$scope.menuopen = false;
|
||||
$location.url(button.link);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show title according to the location
|
||||
*/
|
||||
$rootScope.$on('$routeChangeSuccess', function(){
|
||||
var found = _.find($scope.nav, function(obj){
|
||||
return obj.link === $location.path();
|
||||
});
|
||||
if (found) {
|
||||
$rootScope.taskContext = {
|
||||
name: found.name,
|
||||
type: found.link.substr(1) // remove trailing /
|
||||
};
|
||||
$rootScope.menuopen = false;
|
||||
}
|
||||
});
|
||||
|
||||
$scope.nav = [
|
||||
{ link:'/habit', name:'Habits', lowercase:'habits' },
|
||||
{ link:'/daily', name:'Dailies', lowercase:'dailies' },
|
||||
{ link:'/todo', name:'Todos', lowercase:'todos' },
|
||||
{ link:'/reward', name:'Rewards', lowercase:'rewards' },
|
||||
{ link:'/profile', name:'Profile', lowercase:'profile' },
|
||||
{ link:'/settings', name:'Settings',lowercase:'settings' },
|
||||
{ link:'/help', name:'Help', lowercase:'help' }
|
||||
]
|
||||
|
||||
$scope.refreshing = function () {
|
||||
return User.settings.fetching ? "spin" : ""
|
||||
};
|
||||
|
||||
$scope.queueLength = function () {
|
||||
return User.settings.sync.queue.length || User.settings.sync.sent.length
|
||||
};
|
||||
|
||||
$scope.stats = User.user.stats;
|
||||
|
||||
$('#main_nav').css('height', $(window).height())
|
||||
$('#wrapper').css('height', $(window).height())
|
||||
|
||||
}
|
||||
]);
|
||||
9
assets/js/controllers/notificationCtrl.js
Normal file
9
assets/js/controllers/notificationCtrl.js
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
'use strict';
|
||||
|
||||
habitrpg.controller('NotificationCtrl',
|
||||
['$scope', 'Notification',
|
||||
function ($scope, Notification) {
|
||||
$scope.data = Notification.get();
|
||||
|
||||
}
|
||||
]);
|
||||
21
assets/js/controllers/settingsCtrl.js
Normal file
21
assets/js/controllers/settingsCtrl.js
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
'use strict';
|
||||
|
||||
// Make user and settings available for everyone through root scope.
|
||||
habitrpg.controller('SettingsCtrl',
|
||||
['$scope', 'User', '$location',
|
||||
function($scope, User, $location) {
|
||||
$scope.resetApp = function () {
|
||||
localStorage.clear();
|
||||
location.reload();
|
||||
};
|
||||
$scope.auth = function (id, token) {
|
||||
User.authenticate(id, token, function (err) {
|
||||
if (!err) {
|
||||
alert('Login successful!');
|
||||
$location.path("/habit");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
]);
|
||||
14
assets/js/controllers/statsCtrl.js
Normal file
14
assets/js/controllers/statsCtrl.js
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
'use strict';
|
||||
|
||||
habitrpg.controller('StatsCtrl',
|
||||
['$scope', 'User',
|
||||
function($scope, User) {
|
||||
$scope.refreshing = function () {
|
||||
return User.settings.fetching ? "spin" : ""
|
||||
};
|
||||
$scope.queueLength = function () {
|
||||
return User.settings.sync.queue.length || User.settings.sync.sent.length
|
||||
};
|
||||
$scope.stats = User.user.stats;
|
||||
}
|
||||
]);
|
||||
78
assets/js/controllers/taskDetailsCtrl.js
Normal file
78
assets/js/controllers/taskDetailsCtrl.js
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
'use strict';
|
||||
|
||||
habitrpg.controller('TaskDetailsCtrl',
|
||||
['$scope', '$rootScope', '$location', 'User',
|
||||
function($scope, $rootScope, $location, User) {
|
||||
|
||||
$scope.task = $rootScope.selectedTask;
|
||||
$scope.editing = false;
|
||||
$scope.editedTask = null;
|
||||
|
||||
$scope.goBack = function () {
|
||||
$rootScope.selectedTask = null;
|
||||
$location.path('/' + $scope.task.type);
|
||||
};
|
||||
|
||||
$scope.edit = function () {
|
||||
$scope.originalTask = _.clone($scope.task); // TODO deep clone?;
|
||||
$scope.editedTask = $scope.task;
|
||||
$scope.editing = true;
|
||||
};
|
||||
|
||||
$scope.save = function () {
|
||||
var task = $scope.task,
|
||||
log = [];
|
||||
|
||||
function setVal(k,v){
|
||||
if (typeof v !== "undefined") {
|
||||
var op = {op: 'set', data:{}};
|
||||
op.data["tasks." + task.id + "." + k] = v;
|
||||
log.push(op);
|
||||
}
|
||||
}
|
||||
|
||||
setVal("text", task.text);
|
||||
setVal("notes", task.notes);
|
||||
setVal("priority", task.priority);
|
||||
if (task.type == 'habit') {
|
||||
setVal("up", task.up);
|
||||
setVal("down", task.down);
|
||||
} else if (task.type == 'daily') {
|
||||
setVal("repeat", task.repeat);
|
||||
// _.each(task.repeat, function(v, k) {
|
||||
// setVal("repeat." + k, v);
|
||||
// })
|
||||
} else if (task.type == 'todo') {
|
||||
setVal("date", task.date);
|
||||
} else if (task.type == 'reward') {
|
||||
setVal("value", task.value);
|
||||
}
|
||||
|
||||
|
||||
User.log(log);
|
||||
$rootScope.selectedTask = null;
|
||||
$location.path('/' + $scope.task.type);
|
||||
$scope.editing = false;
|
||||
};
|
||||
|
||||
$scope.cancel = function () {
|
||||
// reset $scope.task to $scope.originalTask
|
||||
for (var key in $scope.task) {
|
||||
$scope.task[key] = $scope.originalTask[key];
|
||||
}
|
||||
$scope.originalTask = null;
|
||||
$scope.editedTask = null;
|
||||
$scope.editing = false;
|
||||
};
|
||||
|
||||
$scope.delete = function () {
|
||||
var confirmed = window.confirm("Delete this task?");
|
||||
if (confirmed !== true) return;
|
||||
var task = $scope.task;
|
||||
var tasks = User.user[task.type+'s'];
|
||||
User.log({op: 'delTask', data: task});
|
||||
$scope.goBack();
|
||||
delete tasks.splice(tasks.indexOf(task),1);
|
||||
};
|
||||
}
|
||||
]);
|
||||
188
assets/js/controllers/tasksCtrl.js
Normal file
188
assets/js/controllers/tasksCtrl.js
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
'use strict';
|
||||
|
||||
habitrpg.controller('TasksCtrl',
|
||||
['$scope', '$rootScope', '$location', 'filterFilter', 'User', 'Algos', 'Helpers', 'Notification',
|
||||
function($scope, $rootScope, $location, filterFilter, User, Algos, Helpers, Notification) {
|
||||
|
||||
$scope.user = User.user;
|
||||
|
||||
$scope.taskTypeTitleSingular = function () {
|
||||
// show title according to the location, singular form
|
||||
return $rootScope.taskContext.type.charAt(0).toUpperCase() + $rootScope.taskContext.type.slice(1);
|
||||
};
|
||||
|
||||
$scope.taskType = function () {
|
||||
return $location.path().split('/')[1]
|
||||
};
|
||||
|
||||
$scope.tasks = function () {
|
||||
//return task array based on our location i.e. /habit will return user.habits[]
|
||||
return User.user[$scope.taskType() + 's'];
|
||||
};
|
||||
|
||||
$scope.showedTasks = []
|
||||
|
||||
$scope.taskFilter = function (task) {
|
||||
return ($location.path() == '/todo') ? !task.completed :
|
||||
($location.path() == '/todo/completed') ? task.completed :
|
||||
true;
|
||||
};
|
||||
|
||||
$scope.score = function (task, direction) {
|
||||
//save current stats to compute the difference after scoring.
|
||||
var statsDiff = {};
|
||||
var oldStats = _.clone(User.user.stats);
|
||||
|
||||
Algos.score(User.user, task, direction);
|
||||
|
||||
//compute the stats change.
|
||||
_.each(oldStats, function (value, key) {
|
||||
var newValue = User.user.stats[key];
|
||||
if (newValue !== value) {
|
||||
statsDiff[key] = newValue - value;
|
||||
}
|
||||
});
|
||||
//notify user if there are changes in stats.
|
||||
if (Object.keys(statsDiff).length > 0) {
|
||||
Notification.push({type: 'stats', stats: statsDiff});
|
||||
}
|
||||
|
||||
if (task.type == 'reward' && _.isEmpty(statsDiff)) {
|
||||
Notification.push({type: 'text', text: 'Not enough GP.'});
|
||||
}
|
||||
|
||||
User.log({op: 'score', data: task, dir: direction});
|
||||
};
|
||||
|
||||
$scope.notDue = function(task) {
|
||||
if (task.type == 'daily') {
|
||||
return !window.habitrpgShared.helpers.shouldDo(moment(), task.repeat);
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
$scope.getClass = function(value) {
|
||||
|
||||
var out = ''
|
||||
if (value < -20)
|
||||
out += ' color-worst'
|
||||
else if (value < -10)
|
||||
out += ' color-worse'
|
||||
else if (value < -1)
|
||||
out += ' color-bad'
|
||||
else if (value < 1)
|
||||
out += ' color-neutral'
|
||||
else if (value < 5)
|
||||
out += ' color-good'
|
||||
else if (value < 10)
|
||||
out += ' color-better'
|
||||
else
|
||||
out += ' color-best'
|
||||
return out
|
||||
}
|
||||
|
||||
$scope.addTask = function () {
|
||||
if (!$scope.newTask.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
var defaults = {
|
||||
text: $scope.newTask,
|
||||
type: $scope.taskType(),
|
||||
value: $scope.taskType() == 'reward' ? 20 : 0
|
||||
},
|
||||
extra = {};
|
||||
|
||||
switch ($scope.taskType()) {
|
||||
case 'habit':
|
||||
extra = {up: true, down: true};
|
||||
break;
|
||||
case 'daily':
|
||||
case 'todo':
|
||||
extra = {completed: false};
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
var newTask = _.defaults(extra, defaults);
|
||||
newTask.id = Helpers.uuid();
|
||||
User.user[newTask.type + 's'].unshift(newTask)
|
||||
$scope.showedTasks.unshift(newTask)
|
||||
User.log({op: 'addTask', data: newTask});
|
||||
$scope.newTask = '';
|
||||
//Add the new task to the actions log
|
||||
|
||||
};
|
||||
|
||||
$scope.clearDoneTodos = function () {
|
||||
//We can't alter $scope.user.tasks here. We have to invoke API call.
|
||||
//To be implemented
|
||||
};
|
||||
|
||||
$scope.selectTask = function (task) {
|
||||
$rootScope.selectedTask = task;
|
||||
$location.path('/tasks/' + task.id)
|
||||
}
|
||||
|
||||
$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 {
|
||||
$scope.score(task, 'down')
|
||||
}
|
||||
}
|
||||
|
||||
$('.taskWell').css('height', $(window).height() - 61)
|
||||
|
||||
// TODO this should be somewhere else, but fits the html location better here
|
||||
$rootScope.revive = function() {
|
||||
window.habitrpgShared.algos.revive(User.user);
|
||||
User.log({op:'revive'});
|
||||
}
|
||||
|
||||
var counter = 0;
|
||||
|
||||
|
||||
/**
|
||||
* ------------------------
|
||||
* Items
|
||||
* ------------------------
|
||||
*/
|
||||
|
||||
$scope.$watch('user.items', function(){
|
||||
$scope.itemStore = window.habitrpgShared.items.updateStore($scope.user);
|
||||
});
|
||||
|
||||
$scope.buy = function(type) {
|
||||
var hasEnough = window.habitrpgShared.items.buyItem($scope.user, type);
|
||||
if (hasEnough) {
|
||||
User.log({op:'buy', type:type});
|
||||
Notification.push({type:'text', text:"Item bought!"})
|
||||
} else {
|
||||
Notification.push({type:'text', text:"Not enough GP."})
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
$scope.loadMore = function() {
|
||||
|
||||
var length = $scope.showedTasks.length
|
||||
if (typeof $scope.tasks() != 'undefined') {
|
||||
for (var i = length; i < length+7; i++) {
|
||||
if (typeof $scope.tasks()[i] != 'undefined') {
|
||||
$scope.showedTasks.push($scope.tasks()[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
$scope.loadMore()
|
||||
|
||||
*/
|
||||
|
||||
}
|
||||
]);
|
||||
33
assets/js/controllers/userAvatarCtrl.js
Normal file
33
assets/js/controllers/userAvatarCtrl.js
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
'use strict';
|
||||
|
||||
habitrpg.controller('userAvatarCtrl',
|
||||
['$scope', '$location', 'filterFilter', 'User',
|
||||
function($scope, $location, filterFilter, User) {
|
||||
|
||||
$scope.user = User.user;
|
||||
|
||||
$scope.changeHair = function(color) {
|
||||
User.user.preferences.hair = color;
|
||||
User.log({op:"set",data:{"preferences.hair":color}})
|
||||
}
|
||||
|
||||
$scope.changeSkin = function(color) {
|
||||
User.user.preferences.skin = color
|
||||
User.log({op:"set",data:{"preferences.skin":color}})
|
||||
}
|
||||
|
||||
$scope.changeSex = function(gender) {
|
||||
User.user.preferences.gender = gender
|
||||
User.log({op:"set",data:{"preferences.gender":gender}})
|
||||
}
|
||||
|
||||
$scope.changeArmor = function(armor) {
|
||||
User.user.preferences.armorSet = armor
|
||||
User.log({op:"set",data:{"preferences.armorSet":armor}})
|
||||
}
|
||||
|
||||
$scope.hideUserAvatar = function() {
|
||||
$('.userAvatar').hide()
|
||||
}
|
||||
}
|
||||
]);
|
||||
34
assets/js/debug.js
Normal file
34
assets/js/debug.js
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
// Generated by CoffeeScript 1.6.3
|
||||
(function() {
|
||||
var algos, moment;
|
||||
|
||||
moment = require('moment');
|
||||
|
||||
algos = require('habitrpg-shared/script/algos');
|
||||
|
||||
module.exports.app = function(appExports, model) {
|
||||
var user;
|
||||
user = model.at('_user');
|
||||
appExports.emulateNextDay = function() {
|
||||
var yesterday;
|
||||
yesterday = +moment().subtract('days', 1).toDate();
|
||||
user.set('lastCron', yesterday);
|
||||
return window.location.reload();
|
||||
};
|
||||
appExports.emulateTenDays = function() {
|
||||
var yesterday;
|
||||
yesterday = +moment().subtract('days', 10).toDate();
|
||||
user.set('lastCron', yesterday);
|
||||
return window.location.reload();
|
||||
};
|
||||
return appExports.cheat = function() {
|
||||
user.incr('stats.exp', algos.tnl(user.get('stats.lvl')));
|
||||
return user.incr('stats.gp', 1000);
|
||||
};
|
||||
};
|
||||
|
||||
}).call(this);
|
||||
|
||||
/*
|
||||
//@ sourceMappingURL=debug.map
|
||||
*/
|
||||
10
assets/js/debug.map
Normal file
10
assets/js/debug.map
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"version": 3,
|
||||
"file": "debug.js",
|
||||
"sourceRoot": "",
|
||||
"sources": [
|
||||
"debug.coffee"
|
||||
],
|
||||
"names": [],
|
||||
"mappings": ";AAAA;CAAA,KAAA,OAAA;;CAAA,CAAA,CAAS,GAAT,CAAS,CAAA;;CAAT,CACA,CAAQ,EAAR,EAAQ,uBAAA;;CADR,CAGA,CAAA,EAAqB,CAAf,CAAQ,EAAQ,CAAD;CACnB,GAAA,IAAA;CAAA,CAAO,CAAA,CAAP,CAAY,EAAL;CAAP,EAE4B,CAA5B,KAA4B,CAAlB,IAAV;CACE,QAAA,CAAA;AAAa,CAAb,CAAuC,CAA3B,GAAZ,EAAa,CAAb;CAAA,CACqB,CAArB,CAAI,EAAJ,GAAA,CAAA;CACO,KAAD,EAAS,KAAf;CALF,IAE4B;CAF5B,EAO4B,CAA5B,KAA4B,CAAlB,IAAV;CACE,QAAA,CAAA;AAAa,CAAb,CAAuC,CAA3B,GAAZ,EAAa,CAAb;CAAA,CACqB,CAArB,CAAI,EAAJ,GAAA,CAAA;CACO,KAAD,EAAS,KAAf;CAVF,IAO4B;CAKjB,EAAQ,EAAnB,IAAmB,CAAT,CAAV;CACE,CAAuB,CAAA,CAAnB,CAAwB,CAA5B,KAAA;CACK,CAAiB,EAAlB,MAAJ,GAAA;CAfiB,IAaA;CAhBrB,EAGqB;CAHrB"
|
||||
}
|
||||
63
assets/js/directives/directives.js
Normal file
63
assets/js/directives/directives.js
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
'use strict';
|
||||
|
||||
/**
|
||||
* Directive that places focus on the element it is applied to when the expression it binds to evaluates to true.
|
||||
*/
|
||||
habitrpg.directive('taskFocus',
|
||||
['$timeout',
|
||||
function($timeout) {
|
||||
return function(scope, elem, attrs) {
|
||||
scope.$watch(attrs.taskFocus, function(newval) {
|
||||
if ( newval ) {
|
||||
$timeout(function() {
|
||||
elem[0].focus();
|
||||
}, 0, false);
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
]);
|
||||
|
||||
/**
|
||||
* Directive that executes an expression when the element it is applied to loses focus.
|
||||
*/
|
||||
habitrpg.directive('taskBlur', function() {
|
||||
return function(scope, elem, attrs) {
|
||||
elem.bind('blur', function() {
|
||||
scope.$apply(attrs.taskBlur);
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
habitrpg.directive('whenScrolled', function() {
|
||||
return function(scope, elm, attr) {
|
||||
var raw = elm[0];
|
||||
|
||||
elm.bind('scroll', function() {
|
||||
if (raw.scrollTop + raw.offsetHeight >= raw.scrollHeight) {
|
||||
scope.$apply(attr.whenScrolled);
|
||||
}
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
/**
|
||||
* Add sortable
|
||||
*/
|
||||
habitrpg.directive('sort', function (User) {
|
||||
return ['$scope', '$rootScope', 'element', 'attrs', 'ngModel',
|
||||
function($scope, $rootScope, element, attrs, ngModel) {
|
||||
$(element).sortable({
|
||||
axis: "y",
|
||||
start: function (event, ui) {
|
||||
ui.item.data('startIndex', ui.item.index());
|
||||
},
|
||||
stop: function (event, ui) {
|
||||
var taskType = $rootScope.taskContext.type;
|
||||
var startIndex = ui.item.data('startIndex');
|
||||
var task = User.user[taskType][startIndex];
|
||||
User.log({op: 'sortTask', data: task, from: startIndex, to: ui.item.index()});
|
||||
}
|
||||
});
|
||||
}]
|
||||
});
|
||||
55
assets/js/filters.js
Normal file
55
assets/js/filters.js
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
// Generated by CoffeeScript 1.6.3
|
||||
(function() {
|
||||
var _;
|
||||
|
||||
_ = require('lodash');
|
||||
|
||||
module.exports.app = function(appExports, model) {
|
||||
var user;
|
||||
user = model.at('_user');
|
||||
appExports.toggleFilterByTag = function(e, el) {
|
||||
var path, tagId;
|
||||
tagId = $(el).attr('data-tag-id');
|
||||
path = 'filters.' + tagId;
|
||||
return user.set(path, !(user.get(path)));
|
||||
};
|
||||
appExports.filtersNewTag = function() {
|
||||
user.setNull('tags', []);
|
||||
user.push('tags', {
|
||||
id: model.id(),
|
||||
name: model.get("_newTag")
|
||||
});
|
||||
return model.set('_newTag', '');
|
||||
};
|
||||
appExports.toggleEditingTags = function() {
|
||||
return model.set('_editingTags', !model.get('_editingTags'));
|
||||
};
|
||||
appExports.clearFilters = function() {
|
||||
return user.set('filters', {});
|
||||
};
|
||||
return appExports.filtersDeleteTag = function(e, el) {
|
||||
var tag, tagId, tags;
|
||||
tags = user.get('tags');
|
||||
tag = e.at("_user.tags." + $(el).attr('data-index'));
|
||||
tagId = tag.get('id');
|
||||
if (!tagId) {
|
||||
user.set('tags', _.filter(tags, (function(t) {
|
||||
return t != null ? t.id : void 0;
|
||||
})));
|
||||
user.set('filters', {});
|
||||
return;
|
||||
}
|
||||
model.del("_user.filters." + tagId);
|
||||
tag.remove();
|
||||
return _.each(user.get("tasks"), function(task) {
|
||||
user.del("tasks." + task.id + ".tags." + tagId);
|
||||
return true;
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
}).call(this);
|
||||
|
||||
/*
|
||||
//@ sourceMappingURL=filters.map
|
||||
*/
|
||||
10
assets/js/filters.map
Normal file
10
assets/js/filters.map
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"version": 3,
|
||||
"file": "filters.js",
|
||||
"sourceRoot": "",
|
||||
"sources": [
|
||||
"filters.coffee"
|
||||
],
|
||||
"names": [],
|
||||
"mappings": ";AAAA;CAAA,KAAA;;CAAA,CAAA,CAAI,IAAA,CAAA;;CAAJ,CAEA,CAAA,EAAqB,CAAf,CAAQ,EAAQ,CAAD;CACnB,GAAA,IAAA;CAAA,CAAO,CAAA,CAAP,CAAY,EAAL;CAAP,CAEmC,CAAJ,CAA/B,KAAgC,CAAtB,OAAV;CACE,SAAA,CAAA;CAAA,CAAQ,CAAA,CAAA,CAAR,CAAA,OAAQ;CAAR,EACO,CAAP,CADA,CACA,IAAO;AACS,CAAX,CAAU,CAAf,CAAI,SAAJ;CALF,IAE+B;CAF/B,EAO2B,CAA3B,KAA2B,CAAjB,GAAV;CACE,CAAqB,EAAjB,EAAJ,CAAA;CAAA,CACkB,EAAd,EAAJ;CAAkB,CAAC,GAAS,GAAT;CAAD,CAAuB,CAAA,CAAN,CAAW,GAAX,CAAM;CADzC,OACA;CACM,CAAe,CAArB,EAAK,IAAL,IAAA;CAVF,IAO2B;CAP3B,EAY+B,CAA/B,KAA+B,CAArB,OAAV;AAC6B,CAArB,CAAoB,CAA1B,EAAK,QAAL,CAAA;CAbF,IAY+B;CAZ/B,EAe0B,CAA1B,KAA0B,CAAhB,EAAV;CACO,CAAe,CAApB,CAAI,KAAJ,IAAA;CAhBF,IAe0B;CAGf,CAAuB,CAAJ,MAAC,CAArB,CAAV,KAAA;CACE,SAAA,MAAA;CAAA,EAAO,CAAP,EAAA;CAAA,CACM,CAAN,CAA2B,EAA3B,MAA2B,CAAhB;CADX,EAEQ,CAAA,CAAR,CAAA;AAGO,CAAP,GAAA,CAAA,CAAA;CACE,CAAiB,CAAjB,CAAI,EAAJ,EAAA,CAAmC;CAAM,EAAD;CAAP,QAAC;CAAlC,CACoB,CAApB,CAAI,IAAJ,CAAA;CACA,aAAA;QARF;CAAA,EAUA,EAAK,CAAL,UAAW;CAVX,EAWG,GAAH;CAGC,CAAyB,CAAnB,CAAP,GAAO,EAAoB,IAA3B;CAAoC,CAAU,CAAV,CAAI,CAAJ,GAAA;CAAV,cAAqD;CAA/E,MAA0B;CAlCT,IAmBW;CArBhC,EAEqB;CAFrB"
|
||||
}
|
||||
10
assets/js/filters/filters.js
Normal file
10
assets/js/filters/filters.js
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
angular.module('habitrpg')
|
||||
.filter('gold', function () {
|
||||
return function (gp) {
|
||||
return Math.floor(gp);
|
||||
}
|
||||
}).filter('silver', function () {
|
||||
return function (gp) {
|
||||
return Math.floor((gp - Math.floor(gp))*100);
|
||||
}
|
||||
});
|
||||
280
assets/js/groups.js
Normal file
280
assets/js/groups.js
Normal file
|
|
@ -0,0 +1,280 @@
|
|||
// Generated by CoffeeScript 1.6.3
|
||||
(function() {
|
||||
var helpers, _,
|
||||
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
|
||||
|
||||
_ = require('lodash');
|
||||
|
||||
helpers = require('habitrpg-shared/script/helpers');
|
||||
|
||||
module.exports.app = function(appExports, model, app) {
|
||||
var browser, joinGroup, user, _currentTime;
|
||||
browser = require('./browser');
|
||||
_currentTime = model.at('_currentTime');
|
||||
_currentTime.setNull(+(new Date));
|
||||
setInterval((function() {
|
||||
return _currentTime.set(+(new Date));
|
||||
}), 60000);
|
||||
user = model.at('_user');
|
||||
appExports.groupCreate = function(e, el) {
|
||||
var newGroup, type;
|
||||
type = $(el).attr('data-type');
|
||||
newGroup = {
|
||||
name: model.get("_new.group.name"),
|
||||
description: model.get("_new.group.description"),
|
||||
leader: user.get('id'),
|
||||
members: [user.get('id')],
|
||||
type: type
|
||||
};
|
||||
if (type === 'party') {
|
||||
return model.add('groups', newGroup, function() {
|
||||
return location.reload();
|
||||
});
|
||||
}
|
||||
if (!(user.get('balance') >= 1)) {
|
||||
return $('#more-gems-modal').modal('show');
|
||||
}
|
||||
if (confirm("Create Guild for 4 Gems?")) {
|
||||
if (type === 'guild') {
|
||||
newGroup.privacy = model.get("_new.group.privacy") || 'public';
|
||||
}
|
||||
newGroup.balance = 1;
|
||||
return model.add('groups', newGroup, function() {
|
||||
return user.incr('balance', -1, function() {
|
||||
return location.reload();
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
appExports.toggleGroupEdit = function(e, el) {
|
||||
var path;
|
||||
path = "_editing.groups." + ($(el).attr('data-gid'));
|
||||
return model.set(path, !model.get(path));
|
||||
};
|
||||
appExports.toggleLeaderMessageEdit = function(e, el) {
|
||||
var path;
|
||||
path = "_editing.leaderMessage." + ($(el).attr('data-gid'));
|
||||
return model.set(path, !model.get(path));
|
||||
};
|
||||
appExports.groupAddWebsite = function(e, el) {
|
||||
var test;
|
||||
test = e.get();
|
||||
e.at().unshift('websites', model.get('_newGroupWebsite'));
|
||||
return model.del('_newGroupWebsite');
|
||||
};
|
||||
appExports.groupInvite = function(e, el) {
|
||||
var uid;
|
||||
uid = model.get('_groupInvitee').replace(/[\s"]/g, '');
|
||||
model.set('_groupInvitee', '');
|
||||
if (_.isEmpty(uid)) {
|
||||
return;
|
||||
}
|
||||
return model.query('users').publicInfo([uid]).fetch(function(err, profiles) {
|
||||
var profile;
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
profile = profiles.at(0).get();
|
||||
if (!profile) {
|
||||
return model.set("_groupError", "User with id " + uid + " not found.");
|
||||
}
|
||||
return model.query('groups').withMember(uid).fetch(function(err, g) {
|
||||
var gid, group, groupError, groups, invite, name, type, _ref, _ref1;
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
group = e.get();
|
||||
groups = g.get();
|
||||
type = group.type, name = group.name;
|
||||
gid = group.id;
|
||||
groupError = function(msg) {
|
||||
return model.set("_groupError", msg);
|
||||
};
|
||||
invite = function() {
|
||||
$.bootstrapGrowl("Invitation Sent.");
|
||||
switch (type) {
|
||||
case 'guild':
|
||||
return model.push("users." + uid + ".invitations.guilds", {
|
||||
id: gid,
|
||||
name: name
|
||||
}, function() {
|
||||
return location.reload();
|
||||
});
|
||||
case 'party':
|
||||
return model.set("users." + uid + ".invitations.party", {
|
||||
id: gid,
|
||||
name: name
|
||||
}, function() {
|
||||
return location.reload();
|
||||
});
|
||||
}
|
||||
};
|
||||
switch (type) {
|
||||
case 'guild':
|
||||
if (((_ref = profile.invitations) != null ? _ref.guilds : void 0) && _.find(profile.invitations.guilds, {
|
||||
id: gid
|
||||
})) {
|
||||
return groupError("User already invited to that group");
|
||||
} else if (__indexOf.call(group.members, uid) >= 0) {
|
||||
return groupError("User already in that group");
|
||||
} else {
|
||||
return invite();
|
||||
}
|
||||
break;
|
||||
case 'party':
|
||||
if ((_ref1 = profile.invitations) != null ? _ref1.party : void 0) {
|
||||
return groupError("User already pending invitation.");
|
||||
} else if (_.find(groups, {
|
||||
type: 'party'
|
||||
})) {
|
||||
return groupError("User already in a party.");
|
||||
} else {
|
||||
return invite();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
joinGroup = function(gid) {
|
||||
return model.push("groups." + gid + ".members", user.get('id'), function() {
|
||||
return location.reload();
|
||||
});
|
||||
};
|
||||
appExports.joinGroup = function(e, el) {
|
||||
return joinGroup(e.get('id'));
|
||||
};
|
||||
appExports.acceptInvitation = function(e, el) {
|
||||
var gid;
|
||||
gid = e.get('id');
|
||||
if ($(el).attr('data-type') === 'party') {
|
||||
return user.set('invitations.party', null, function() {
|
||||
return joinGroup(gid);
|
||||
});
|
||||
} else {
|
||||
return e.at().remove(function() {
|
||||
return joinGroup(gid);
|
||||
});
|
||||
}
|
||||
};
|
||||
appExports.rejectInvitation = function(e, el) {
|
||||
var clear;
|
||||
clear = function() {
|
||||
return browser.resetDom(model);
|
||||
};
|
||||
if (e.at().path().indexOf('party') !== -1) {
|
||||
return model.del(e.at().path(), clear);
|
||||
} else {
|
||||
return e.at().remove(clear);
|
||||
}
|
||||
};
|
||||
appExports.groupLeave = function(e, el) {
|
||||
var group, index, uid;
|
||||
if (confirm("Leave this group, are you sure?") === true) {
|
||||
uid = user.get('id');
|
||||
group = model.at("groups." + ($(el).attr('data-id')));
|
||||
index = group.get('members').indexOf(uid);
|
||||
if (index !== -1) {
|
||||
return group.remove('members', index, 1, function() {
|
||||
var updated;
|
||||
updated = group.get();
|
||||
if (_.isEmpty(updated.members) && (updated.type === 'party')) {
|
||||
return group.del(function() {
|
||||
return location.reload();
|
||||
});
|
||||
} else if (updated.leader === uid) {
|
||||
return group.set("leader", updated.members[0], function() {
|
||||
return location.reload();
|
||||
});
|
||||
} else {
|
||||
return location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
/*
|
||||
Chat Functionality
|
||||
*/
|
||||
|
||||
model.on('unshift', '_party.chat', function() {
|
||||
return $('.chat-message').tooltip();
|
||||
});
|
||||
model.on('unshift', '_habitrpg.chat', function() {
|
||||
return $('.chat-message').tooltip();
|
||||
});
|
||||
appExports.sendChat = function(e, el) {
|
||||
var chat, group, members, message, messages, text, type, uniqMembers;
|
||||
text = model.get('_chatMessage');
|
||||
if (!/\S/.test(text)) {
|
||||
return;
|
||||
}
|
||||
group = e.at();
|
||||
members = group.get('members');
|
||||
uniqMembers = _.uniq(members);
|
||||
if (!_.isEqual(uniqMembers, members)) {
|
||||
group.set('members', uniqMembers);
|
||||
}
|
||||
chat = group.at('chat');
|
||||
model.set('_chatMessage', '');
|
||||
message = {
|
||||
id: model.id(),
|
||||
uuid: user.get('id'),
|
||||
contributor: user.get('backer.contributor'),
|
||||
npc: user.get('backer.npc'),
|
||||
text: text,
|
||||
user: helpers.username(model.get('_user.auth'), model.get('_user.profile.name')),
|
||||
timestamp: +(new Date)
|
||||
};
|
||||
messages = chat.get() || [];
|
||||
messages.unshift(message);
|
||||
messages.splice(200);
|
||||
chat.set(messages);
|
||||
type = $(el).attr('data-type');
|
||||
if (group.get('type') === 'party') {
|
||||
return model.set('_user.party.lastMessageSeen', chat.get()[0].id);
|
||||
}
|
||||
};
|
||||
appExports.chatKeyup = function(e, el, next) {
|
||||
if (e.keyCode !== 13) {
|
||||
return next();
|
||||
}
|
||||
return appExports.sendChat(e, el);
|
||||
};
|
||||
appExports.deleteChatMessage = function(e) {
|
||||
if (confirm("Delete chat message?") === true) {
|
||||
return e.at().remove();
|
||||
}
|
||||
};
|
||||
app.on('render', function(ctx) {
|
||||
return $('#party-tab-link').on('shown', function(e) {
|
||||
var messages;
|
||||
messages = model.get('_party.chat');
|
||||
if (!((messages != null ? messages.length : void 0) > 0)) {
|
||||
return false;
|
||||
}
|
||||
return model.set('_user.party.lastMessageSeen', messages[0].id);
|
||||
});
|
||||
});
|
||||
appExports.gotoPartyChat = function() {
|
||||
return model.set('_gamePane', true, function() {
|
||||
return $('#party-tab-link').tab('show');
|
||||
});
|
||||
};
|
||||
return appExports.assignGroupLeader = function(e, el) {
|
||||
var newLeader;
|
||||
newLeader = model.get('_new.groupLeader');
|
||||
if (newLeader && (confirm("Assign new leader, you sure?") === true)) {
|
||||
if (newLeader) {
|
||||
return e.at().set('leader', newLeader, function() {
|
||||
return browser.resetDom(model);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
}).call(this);
|
||||
|
||||
/*
|
||||
//@ sourceMappingURL=groups.map
|
||||
*/
|
||||
10
assets/js/groups.map
Normal file
10
assets/js/groups.map
Normal file
File diff suppressed because one or more lines are too long
25
assets/js/i18n.js
Normal file
25
assets/js/i18n.js
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
// Generated by CoffeeScript 1.6.3
|
||||
(function() {
|
||||
var i18n;
|
||||
|
||||
i18n = require('derby-i18n');
|
||||
|
||||
i18n.plurals.add('he', function(n) {
|
||||
return n;
|
||||
});
|
||||
|
||||
i18n.plurals.add('bg', function(n) {
|
||||
return n;
|
||||
});
|
||||
|
||||
i18n.plurals.add('nl', function(n) {
|
||||
return n;
|
||||
});
|
||||
|
||||
module.exports = i18n;
|
||||
|
||||
}).call(this);
|
||||
|
||||
/*
|
||||
//@ sourceMappingURL=i18n.map
|
||||
*/
|
||||
10
assets/js/i18n.map
Normal file
10
assets/js/i18n.map
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"version": 3,
|
||||
"file": "i18n.js",
|
||||
"sourceRoot": "",
|
||||
"sources": [
|
||||
"i18n.coffee"
|
||||
],
|
||||
"names": [],
|
||||
"mappings": ";AAAA;CAAA,GAAA,EAAA;;CAAA,CAAA,CAAO,CAAP,GAAO,KAAA;;CAAP,CAEA,CAAA,CAAI,GAAQ,EAAY;CAAD,UAAO;CAA9B,EAAuB;;CAFvB,CAGA,CAAA,CAAI,GAAQ,EAAY;CAAD,UAAO;CAA9B,EAAuB;;CAHvB,CAIA,CAAA,CAAI,GAAQ,EAAY;CAAD,UAAO;CAA9B,EAAuB;;CAJvB,CAMA,CAAiB,CANjB,EAMM,CAAN;CANA"
|
||||
}
|
||||
|
|
@ -2,7 +2,7 @@ derby = require 'derby'
|
|||
|
||||
# Include library components
|
||||
derby.use require('derby-ui-boot'), {styles: []}
|
||||
derby.use require '../../ui'
|
||||
derby.use require '../'
|
||||
derby.use require 'derby-auth/components'
|
||||
|
||||
# Init app & reference its functions
|
||||
184
assets/js/index.js
Normal file
184
assets/js/index.js
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
// Generated by CoffeeScript 1.6.3
|
||||
(function() {
|
||||
var algos, app, async, derby, get, i18n, misc, ready, view, _;
|
||||
|
||||
derby = require('derby');
|
||||
|
||||
derby.use(require('derby-ui-boot'), {
|
||||
styles: []
|
||||
});
|
||||
|
||||
derby.use(require('../'));
|
||||
|
||||
derby.use(require('derby-auth/components'));
|
||||
|
||||
app = derby.createApp(module);
|
||||
|
||||
get = app.get, view = app.view, ready = app.ready;
|
||||
|
||||
i18n = require('./i18n');
|
||||
|
||||
i18n.localize(app, {
|
||||
availableLocales: ['en', 'he', 'bg', 'nl'],
|
||||
defaultLocale: 'en',
|
||||
urlScheme: false,
|
||||
checkHeader: true
|
||||
});
|
||||
|
||||
misc = require('./misc');
|
||||
|
||||
misc.viewHelpers(view);
|
||||
|
||||
_ = require('lodash');
|
||||
|
||||
algos = require('habitrpg-shared/script/algos');
|
||||
|
||||
async = require('async');
|
||||
|
||||
get('/', function(page, model, params, next) {
|
||||
var uuid, _ref, _ref1;
|
||||
if (((_ref = page.params) != null ? (_ref1 = _ref.query) != null ? _ref1.play : void 0 : void 0) != null) {
|
||||
return page.redirect('/');
|
||||
}
|
||||
/*
|
||||
Subscribe to the user, the users's party (meta info like party name, member ids, etc), and the party's members. 3 subscriptions.
|
||||
*/
|
||||
|
||||
uuid = model.get('_userId') || model.session.userId;
|
||||
return async.waterfall([
|
||||
function(cb) {
|
||||
var myGroupsQuery, publicGroupsQuery;
|
||||
publicGroupsQuery = model.query('groups').publicGroups();
|
||||
myGroupsQuery = model.query('groups').withMember(uuid);
|
||||
return model.fetch(publicGroupsQuery, myGroupsQuery, cb);
|
||||
}, function(publicGroups, groups, cb) {
|
||||
var groupsInfo, groupsObj, guildsQ, membersQ, partyQ;
|
||||
model.set('_publicGroups', _.sortBy(publicGroups.get(), function(g) {
|
||||
return -_.size(g.members);
|
||||
}));
|
||||
groupsObj = groups.get();
|
||||
if (_.isEmpty(groupsObj)) {
|
||||
return cb(true);
|
||||
}
|
||||
groupsInfo = _.reduce(groupsObj, (function(m, g) {
|
||||
if (g.type === 'guild') {
|
||||
m.guildIds.push(g.id);
|
||||
} else {
|
||||
m.partyId = g.id;
|
||||
}
|
||||
m.members = m.members.concat(g.members);
|
||||
return m;
|
||||
}), {
|
||||
guildIds: [],
|
||||
partyId: null,
|
||||
members: []
|
||||
});
|
||||
membersQ = model.query('users').publicInfo(groupsInfo.members);
|
||||
partyQ = model.query('groups').withIds(groupsInfo.partyId);
|
||||
guildsQ = model.query('groups').withIds(groupsInfo.guildIds);
|
||||
return model.fetch(membersQ, partyQ, guildsQ, cb);
|
||||
}
|
||||
], function(err, members, party, guilds) {
|
||||
var mObj;
|
||||
if (err && err !== true) {
|
||||
return next(err);
|
||||
}
|
||||
if (members) {
|
||||
mObj = members.get();
|
||||
model.set("_members", _.object(_.pluck(mObj, 'id'), mObj));
|
||||
model.set("_membersArray", mObj);
|
||||
}
|
||||
if (party) {
|
||||
model.ref('_party', party);
|
||||
}
|
||||
if (guilds) {
|
||||
model.ref('_guilds', guilds);
|
||||
}
|
||||
return model.subscribe("users." + uuid, 'groups.habitrpg', function(err, user, tavern) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
model.ref('_user', user);
|
||||
model.ref('_habitRPG', tavern);
|
||||
if (!user.get()) {
|
||||
console.error("User not found - this shouldn't be happening!");
|
||||
return page.redirect('/logout');
|
||||
}
|
||||
require('./items').server(model);
|
||||
_.each(['habit', 'daily', 'todo', 'reward'], function(type) {
|
||||
model.refList("_" + type + "List", "_user.tasks", "_user." + type + "Ids");
|
||||
return true;
|
||||
});
|
||||
return page.render();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
ready(function(model) {
|
||||
var browser, tz, user;
|
||||
user = model.at('_user');
|
||||
misc.fixCorruptUser(model);
|
||||
browser = require('./browser');
|
||||
require('./tasks').app(exports, model);
|
||||
require('./items').app(exports, model);
|
||||
require('./groups').app(exports, model, app);
|
||||
require('./profile').app(exports, model);
|
||||
require('./pets').app(exports, model);
|
||||
require('../server/private').app(exports, model);
|
||||
if (model.flags.nodeEnv !== 'production') {
|
||||
require('./debug').app(exports, model);
|
||||
}
|
||||
browser.app(exports, model, app);
|
||||
require('./unlock').app(exports, model);
|
||||
require('./filters').app(exports, model);
|
||||
require('./challenges').app(exports, model);
|
||||
exports.removeAt = function(e, el) {
|
||||
var confirmMessage;
|
||||
if ((confirmMessage = $(el).attr('data-confirm')) != null) {
|
||||
if (confirm(confirmMessage) !== true) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
e.at().remove();
|
||||
if ($(el).attr('data-refresh')) {
|
||||
return browser.resetDom(model);
|
||||
}
|
||||
};
|
||||
tz = user.get("preferences.timezoneOffset");
|
||||
if (!(tz && tz === (new Date()).getTimezoneOffset())) {
|
||||
user.set('preferences.timezoneOffset', (new Date()).getTimezoneOffset());
|
||||
}
|
||||
/*
|
||||
Cron
|
||||
*/
|
||||
|
||||
return misc.batchTxn(model, function(uObj, paths) {
|
||||
_.each(['habit', 'daily', 'todo', 'reward'], function(type) {
|
||||
uObj["" + type + "s"] = _.where(uObj.tasks, {
|
||||
type: type
|
||||
});
|
||||
return true;
|
||||
});
|
||||
algos.cron(uObj, {
|
||||
paths: paths
|
||||
});
|
||||
if (_.isEmpty(paths) || (paths['lastCron'] && _.size(paths) === 1)) {
|
||||
return;
|
||||
}
|
||||
if (paths['stats.hp']) {
|
||||
delete paths['stats.hp'];
|
||||
return setTimeout(function() {
|
||||
browser.resetDom(model);
|
||||
return user.set('stats.hp', uObj.stats.hp);
|
||||
}, 750);
|
||||
}
|
||||
}, {
|
||||
cron: true
|
||||
});
|
||||
});
|
||||
|
||||
}).call(this);
|
||||
|
||||
/*
|
||||
//@ sourceMappingURL=index.map
|
||||
*/
|
||||
10
assets/js/index.map
Normal file
10
assets/js/index.map
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"version": 3,
|
||||
"file": "index.js",
|
||||
"sourceRoot": "",
|
||||
"sources": [
|
||||
"index.coffee"
|
||||
],
|
||||
"names": [],
|
||||
"mappings": "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"
|
||||
}
|
||||
64
assets/js/items.js
Normal file
64
assets/js/items.js
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
// Generated by CoffeeScript 1.6.3
|
||||
(function() {
|
||||
var items, updateStore, _;
|
||||
|
||||
items = require('habitrpg-shared/script/items');
|
||||
|
||||
_ = require('lodash');
|
||||
|
||||
updateStore = function(model) {
|
||||
var nextItems;
|
||||
nextItems = items.updateStore(model.get('_user'));
|
||||
return _.each(nextItems, function(v, k) {
|
||||
model.set("_items.next." + k, v);
|
||||
return true;
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
server exports
|
||||
*/
|
||||
|
||||
|
||||
module.exports.server = function(model) {
|
||||
model.set('_items', items.items);
|
||||
return updateStore(model);
|
||||
};
|
||||
|
||||
/*
|
||||
app exports
|
||||
*/
|
||||
|
||||
|
||||
module.exports.app = function(appExports, model) {
|
||||
var misc;
|
||||
misc = require('./misc');
|
||||
model.on("set", "_user.items.*", function() {
|
||||
return updateStore(model);
|
||||
});
|
||||
appExports.buyItem = function(e, el) {
|
||||
return misc.batchTxn(model, function(uObj, paths) {
|
||||
var ret;
|
||||
ret = items.buyItem(uObj, $(el).attr('data-type'), {
|
||||
paths: paths
|
||||
});
|
||||
if (ret === false) {
|
||||
return alert("Not enough GP");
|
||||
}
|
||||
});
|
||||
};
|
||||
appExports.activateRewardsTab = function() {
|
||||
model.set('_activeTabRewards', true);
|
||||
return model.set('_activeTabPets', false);
|
||||
};
|
||||
return appExports.activatePetsTab = function() {
|
||||
model.set('_activeTabPets', true);
|
||||
return model.set('_activeTabRewards', false);
|
||||
};
|
||||
};
|
||||
|
||||
}).call(this);
|
||||
|
||||
/*
|
||||
//@ sourceMappingURL=items.map
|
||||
*/
|
||||
10
assets/js/items.map
Normal file
10
assets/js/items.map
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"version": 3,
|
||||
"file": "items.js",
|
||||
"sourceRoot": "",
|
||||
"sources": [
|
||||
"items.coffee"
|
||||
],
|
||||
"names": [],
|
||||
"mappings": ";AAAA;CAAA,KAAA,eAAA;;CAAA,CAAA,CAAQ,EAAR,EAAQ,uBAAA;;CAAR,CACA,CAAI,IAAA,CAAA;;CADJ,CAGA,CAAc,EAAA,IAAC,EAAf;CACE,OAAA,CAAA;CAAA,EAAY,CAAZ,CAAiB,EAAa,EAA9B,EAAY;CACX,CAAiB,CAAA,CAAlB,KAAA,EAAA;CAA2B,CAA6B,CAA7B,EAAK,CAAL,QAAW;CAApB,YAA0C;CAA5D,IAAkB;CALpB,EAGc;;CAId;;;CAPA;;CAAA,CAUA,CAAwB,EAAA,CAAlB,CAAQ,EAAW;CACvB,CAAoB,CAApB,CAAA,CAAK,GAAL;CACY,IAAZ,MAAA;CAZF,EAUwB;;CAIxB;;;CAdA;;CAAA,CAiBA,CAAA,EAAqB,CAAf,CAAQ,EAAQ,CAAD;CACnB,GAAA,IAAA;CAAA,EAAO,CAAP,GAAO,CAAA;CAAP,CAEA,CAAiC,CAAjC,CAAK,IAA4B,MAAjC;CAAgD,IAAZ,MAAA,EAAA;CAApC,IAAiC;CAFjC,CAIyB,CAAJ,CAArB,GAAA,EAAsB,CAAZ;CACH,CAAgB,CAAA,CAAjB,CAAJ,GAAA,CAAsB,IAAtB;CACE,EAAA,SAAA;CAAA,CAA0B,CAA1B,CAAM,CAAK,EAAL,CAAN,GAA0B;CAAyB,CAAC,GAAD,KAAC;CAApD,SAAM;CACN,EAA0B,CAAA,CAAO,GAAjC;CAAM,IAAN,UAAA,EAAA;UAFmB;CAArB,MAAqB;CALvB,IAIqB;CAJrB,EASgC,CAAhC,KAAgC,CAAtB,QAAV;CACE,CAA+B,CAA/B,CAAA,CAAK,CAAL,aAAA;CACM,CAAsB,CAA5B,EAAK,QAAL,GAAA;CAXF,IASgC;CAGrB,EAAkB,MAAA,CAAnB,CAAV,IAAA;CACE,CAA4B,CAA5B,CAAA,CAAK,CAAL,UAAA;CACM,CAAyB,CAA/B,EAAK,QAAL,MAAA;CAfiB,IAaU;CA9B/B,EAiBqB;CAjBrB"
|
||||
}
|
||||
323
assets/js/misc.js
Normal file
323
assets/js/misc.js
Normal file
|
|
@ -0,0 +1,323 @@
|
|||
// 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
|
||||
*/
|
||||
10
assets/js/misc.map
Normal file
10
assets/js/misc.map
Normal file
File diff suppressed because one or more lines are too long
103
assets/js/pets.js
Normal file
103
assets/js/pets.js
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
// Generated by CoffeeScript 1.6.3
|
||||
(function() {
|
||||
var hatchingPotions, pets, randomVal, _, _ref;
|
||||
|
||||
_ = require('lodash');
|
||||
|
||||
randomVal = require('habitrpg-shared/script/helpers').randomVal;
|
||||
|
||||
_ref = require('habitrpg-shared/script/items').items, pets = _ref.pets, hatchingPotions = _ref.hatchingPotions;
|
||||
|
||||
/*
|
||||
app exports
|
||||
*/
|
||||
|
||||
|
||||
module.exports.app = function(appExports, model) {
|
||||
var user;
|
||||
user = model.at('_user');
|
||||
appExports.chooseEgg = function(e, el) {
|
||||
return model.ref('_hatchEgg', e.at());
|
||||
};
|
||||
appExports.hatchEgg = function(e, el) {
|
||||
var egg, eggIdx, eggs, hatchingPotionIdx, hatchingPotionName, myHatchingPotion, myPets;
|
||||
hatchingPotionName = $(el).children('select').val();
|
||||
myHatchingPotion = user.get('items.hatchingPotions');
|
||||
egg = model.get('_hatchEgg');
|
||||
eggs = user.get('items.eggs');
|
||||
myPets = user.get('items.pets');
|
||||
hatchingPotionIdx = myHatchingPotion.indexOf(hatchingPotionName);
|
||||
eggIdx = eggs.indexOf(egg);
|
||||
if (hatchingPotionIdx === -1) {
|
||||
return alert("You don't own that hatching potion yet, complete more tasks!");
|
||||
}
|
||||
if (eggIdx === -1) {
|
||||
return alert("You don't own that egg yet, complete more tasks!");
|
||||
}
|
||||
if (myPets && myPets.indexOf("" + egg.name + "-" + hatchingPotionName) !== -1) {
|
||||
return alert("You already have that pet, hatch a different combo.");
|
||||
}
|
||||
user.push('items.pets', egg.name + '-' + hatchingPotionName, function() {
|
||||
eggs.splice(eggIdx, 1);
|
||||
myHatchingPotion.splice(hatchingPotionIdx, 1);
|
||||
user.set('items.eggs', eggs);
|
||||
return user.set('items.hatchingPotions', myHatchingPotion);
|
||||
});
|
||||
return alert('Your egg hatched! Visit your stable to equip your pet.');
|
||||
};
|
||||
appExports.choosePet = function(e, el, next) {
|
||||
var modifier, name, pet, petStr, _ref1;
|
||||
petStr = $(el).attr('data-pet');
|
||||
if (user.get('items.pets').indexOf(petStr) === -1) {
|
||||
return next();
|
||||
}
|
||||
if (user.get('items.currentPet.str') === petStr) {
|
||||
return user.set('items.currentPet', {});
|
||||
}
|
||||
_ref1 = petStr.split('-'), name = _ref1[0], modifier = _ref1[1];
|
||||
pet = _.find(pets, {
|
||||
name: name
|
||||
});
|
||||
pet.modifier = modifier;
|
||||
pet.str = petStr;
|
||||
return user.set('items.currentPet', pet);
|
||||
};
|
||||
appExports.buyHatchingPotion = function(e, el) {
|
||||
var gems, name, newHatchingPotion;
|
||||
name = $(el).attr('data-hatchingPotion');
|
||||
newHatchingPotion = _.find(hatchingPotions, {
|
||||
name: name
|
||||
});
|
||||
gems = user.get('balance') * 4;
|
||||
if (gems >= newHatchingPotion.value) {
|
||||
if (confirm("Buy this hatching potion with " + newHatchingPotion.value + " of your " + gems + " Gems?")) {
|
||||
user.push('items.hatchingPotions', newHatchingPotion.name);
|
||||
return user.set('balance', (gems - newHatchingPotion.value) / 4);
|
||||
}
|
||||
} else {
|
||||
return $('#more-gems-modal').modal('show');
|
||||
}
|
||||
};
|
||||
return appExports.buyEgg = function(e, el) {
|
||||
var gems, name, newEgg;
|
||||
name = $(el).attr('data-egg');
|
||||
newEgg = _.find(pets, {
|
||||
name: name
|
||||
});
|
||||
gems = user.get('balance') * 4;
|
||||
if (gems >= newEgg.value) {
|
||||
if (confirm("Buy this egg with " + newEgg.value + " of your " + gems + " Gems?")) {
|
||||
user.push('items.eggs', newEgg);
|
||||
return user.set('balance', (gems - newEgg.value) / 4);
|
||||
}
|
||||
} else {
|
||||
return $('#more-gems-modal').modal('show');
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
}).call(this);
|
||||
|
||||
/*
|
||||
//@ sourceMappingURL=pets.map
|
||||
*/
|
||||
10
assets/js/pets.map
Normal file
10
assets/js/pets.map
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"version": 3,
|
||||
"file": "pets.js",
|
||||
"sourceRoot": "",
|
||||
"sources": [
|
||||
"pets.coffee"
|
||||
],
|
||||
"names": [],
|
||||
"mappings": "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"
|
||||
}
|
||||
135
assets/js/profile.js
Normal file
135
assets/js/profile.js
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
// Generated by CoffeeScript 1.6.3
|
||||
(function() {
|
||||
var algos, browser, helpers, items, misc, _;
|
||||
|
||||
helpers = require('habitrpg-shared/script/helpers');
|
||||
|
||||
algos = require('habitrpg-shared/script/algos');
|
||||
|
||||
browser = require('./browser');
|
||||
|
||||
items = require('./items');
|
||||
|
||||
misc = require('./misc');
|
||||
|
||||
_ = require('lodash');
|
||||
|
||||
module.exports.app = function(appExports, model) {
|
||||
var toggleGamePane, user;
|
||||
user = model.at('_user');
|
||||
appExports.revive = function() {
|
||||
var paths, uObj, _ref;
|
||||
_ref = [user.get(), {}], uObj = _ref[0], paths = _ref[1];
|
||||
algos.revive(uObj, {
|
||||
paths: paths
|
||||
});
|
||||
return _.each(paths, (function(v, k) {
|
||||
return user.set(k, helpers.dotGet(k, uObj));
|
||||
}));
|
||||
};
|
||||
appExports.reset = function(e, el) {
|
||||
misc.batchTxn(model, function(uObj, paths, batch) {
|
||||
batch.set('tasks', {});
|
||||
['habit', 'daily', 'todo', 'reward'].forEach(function(type) {
|
||||
return batch.set("" + type + "Ids", []);
|
||||
});
|
||||
_.each({
|
||||
hp: 50,
|
||||
lvl: 1,
|
||||
gp: 0,
|
||||
exp: 0
|
||||
}, function(v, k) {
|
||||
return batch.set("stats." + k, v);
|
||||
});
|
||||
return _.each({
|
||||
armor: 0,
|
||||
weapon: 0,
|
||||
head: 0,
|
||||
shield: 0
|
||||
}, function(v, k) {
|
||||
return batch.set("items." + k, v);
|
||||
});
|
||||
});
|
||||
return browser.resetDom(model);
|
||||
};
|
||||
appExports.closeNewStuff = function(e, el) {
|
||||
return user.set('flags.newStuff', 'hide');
|
||||
};
|
||||
appExports.customizeGender = function(e, el) {
|
||||
return user.set('preferences.gender', $(el).attr('data-value'));
|
||||
};
|
||||
appExports.customizeHair = function(e, el) {
|
||||
return user.set('preferences.hair', $(el).attr('data-value'));
|
||||
};
|
||||
appExports.customizeSkin = function(e, el) {
|
||||
return user.set('preferences.skin', $(el).attr('data-value'));
|
||||
};
|
||||
appExports.customizeArmorSet = function(e, el) {
|
||||
return user.set('preferences.armorSet', $(el).attr('data-value'));
|
||||
};
|
||||
appExports.restoreSave = function() {
|
||||
return misc.batchTxn(model, function(uObj, paths, batch) {
|
||||
return $('#restore-form input').each(function() {
|
||||
var path, val, _ref;
|
||||
_ref = [$(this).attr('data-for'), parseInt($(this).val() || 1)], path = _ref[0], val = _ref[1];
|
||||
return batch.set(path, val);
|
||||
});
|
||||
});
|
||||
};
|
||||
appExports.toggleHeader = function(e, el) {
|
||||
return user.set('preferences.hideHeader', !user.get('preferences.hideHeader'));
|
||||
};
|
||||
appExports.deleteAccount = function(e, el) {
|
||||
return model.del("users." + (user.get('id')), function() {
|
||||
return location.href = "/logout";
|
||||
});
|
||||
};
|
||||
appExports.profileAddWebsite = function(e, el) {
|
||||
var newWebsite;
|
||||
newWebsite = model.get('_newProfileWebsite');
|
||||
if (/^(\s)*$/.test(newWebsite)) {
|
||||
return;
|
||||
}
|
||||
user.unshift('profile.websites', newWebsite);
|
||||
return model.set('_newProfileWebsite', '');
|
||||
};
|
||||
appExports.profileEdit = function(e, el) {
|
||||
return model.set('_profileEditing', true);
|
||||
};
|
||||
appExports.profileSave = function(e, el) {
|
||||
return model.set('_profileEditing', false);
|
||||
};
|
||||
appExports.profileRemoveWebsite = function(e, el) {
|
||||
var i, sites;
|
||||
sites = user.get('profile.websites');
|
||||
i = sites.indexOf($(el).attr('data-website'));
|
||||
sites.splice(i, 1);
|
||||
return user.set('profile.websites', sites);
|
||||
};
|
||||
toggleGamePane = function() {
|
||||
return model.set('_gamePane', !model.get('_gamePane'), function() {
|
||||
return browser.setupTooltips();
|
||||
});
|
||||
};
|
||||
appExports.clickAvatar = function(e, el) {
|
||||
var uid;
|
||||
uid = $(el).attr('data-uid');
|
||||
if (uid === model.get('_userId')) {
|
||||
return toggleGamePane();
|
||||
} else {
|
||||
return $("#avatar-modal-" + uid).modal('show');
|
||||
}
|
||||
};
|
||||
appExports.toggleGamePane = function() {
|
||||
return toggleGamePane();
|
||||
};
|
||||
return appExports.toggleResting = function() {
|
||||
return model.set('_user.flags.rest', !model.get('_user.flags.rest'));
|
||||
};
|
||||
};
|
||||
|
||||
}).call(this);
|
||||
|
||||
/*
|
||||
//@ sourceMappingURL=profile.map
|
||||
*/
|
||||
10
assets/js/profile.map
Normal file
10
assets/js/profile.map
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"version": 3,
|
||||
"file": "profile.js",
|
||||
"sourceRoot": "",
|
||||
"sources": [
|
||||
"profile.coffee"
|
||||
],
|
||||
"names": [],
|
||||
"mappings": "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"
|
||||
}
|
||||
103
assets/js/services/authServices.js
Normal file
103
assets/js/services/authServices.js
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
'use strict';
|
||||
|
||||
/**
|
||||
* Services that persists and retrieves user from localStorage.
|
||||
*/
|
||||
|
||||
var facebook = {}
|
||||
|
||||
angular.module('authServices', ['userServices']).
|
||||
factory('Facebook',
|
||||
['$http', '$location', 'User', 'API_URL',
|
||||
function($http, $location, User, API_URL) {
|
||||
//TODO FB.init({appId: '${section.parameters['facebook.app.id']}', status: true, cookie: true, xfbml: true});
|
||||
var auth, user = User.user;
|
||||
|
||||
facebook.handleStatusChange = function(session) {
|
||||
if (session.authResponse) {
|
||||
|
||||
FB.api('/me', {
|
||||
fields: 'name, picture, email'
|
||||
}, function(response) {
|
||||
console.log(response.error)
|
||||
if (!response.error) {
|
||||
|
||||
var data = {
|
||||
name: response.name,
|
||||
facebook_id: response.id,
|
||||
email: response.email
|
||||
}
|
||||
|
||||
$http.post(API_URL + '/api/v1/user/auth/facebook', data).success(function(data, status, headers, config) {
|
||||
User.authenticate(data.id, data.token, function(err) {
|
||||
if (!err) {
|
||||
alert('Login successful!');
|
||||
$location.path("/habit");
|
||||
}
|
||||
});
|
||||
}).error(function(response) {
|
||||
console.log('error')
|
||||
})
|
||||
|
||||
} else {
|
||||
alert('napaka')
|
||||
}
|
||||
//clearAction();
|
||||
});
|
||||
} else {
|
||||
document.body.className = 'not_connected';
|
||||
//clearAction();
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
authUser: function() {
|
||||
FB.Event.subscribe('auth.statusChange', facebook.handleStatusChange);
|
||||
},
|
||||
|
||||
getAuth: function() {
|
||||
return auth;
|
||||
},
|
||||
|
||||
login: function() {
|
||||
|
||||
FB.login(null, {
|
||||
scope: 'email'
|
||||
});
|
||||
},
|
||||
|
||||
logout: function() {
|
||||
FB.logout(function(response) {
|
||||
window.location.reload();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
])
|
||||
|
||||
.factory('LocalAuth',
|
||||
['$http', 'User',
|
||||
function($http, User) {
|
||||
var auth,
|
||||
user = User.user;
|
||||
|
||||
return {
|
||||
getAuth: function() {
|
||||
return auth;
|
||||
},
|
||||
|
||||
login: function() {
|
||||
user.id = '';
|
||||
user.apiToken = '';
|
||||
User.authenticate();
|
||||
return;
|
||||
|
||||
},
|
||||
|
||||
logout: function() {}
|
||||
}
|
||||
|
||||
}
|
||||
]);
|
||||
75
assets/js/services/notificationServices.js
Normal file
75
assets/js/services/notificationServices.js
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
angular.module('notificationServices', []).
|
||||
factory('Notification', function () {
|
||||
var data = {message:''};
|
||||
var active = false;
|
||||
var timer = null;
|
||||
|
||||
return {
|
||||
|
||||
hide: function () {
|
||||
$('#notification').fadeOut(function () {
|
||||
$('#notification').css('webkit-transform', 'none')
|
||||
$('#notification').css('top', '-63px')
|
||||
$('#notification').css('left', '0px');
|
||||
|
||||
setTimeout(function() {
|
||||
$('#notification').show()
|
||||
}, 190)
|
||||
});
|
||||
|
||||
active = false;
|
||||
timer = null;
|
||||
},
|
||||
|
||||
animate: function () {
|
||||
|
||||
if (timer) {
|
||||
clearTimeout(timer);
|
||||
timer = setTimeout(this.hide, 2000)
|
||||
}
|
||||
|
||||
if (active == false) {
|
||||
active = true;
|
||||
|
||||
$('#notification').transition({ y: 63, x: 0 });
|
||||
timer = setTimeout(this.hide, 2000);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
push: function (message) {
|
||||
data.message = ''
|
||||
switch(message.type) {
|
||||
case 'stats':
|
||||
if (message.stats.exp != null && message.stats.gp != null)
|
||||
data.message = 'Experience: ' + message.stats.exp + '<br />GP: ' + message.stats.gp.toFixed(2)
|
||||
if (message.stats.hp)
|
||||
data.message = 'HP: ' + message.stats.hp.toFixed(2)
|
||||
if (message.stats.gp && message.stats.exp == null)
|
||||
data.message = '<br />GP: ' + message.stats.gp.toFixed(2)
|
||||
break;
|
||||
case 'text':
|
||||
data.message = message.text
|
||||
break;
|
||||
}
|
||||
|
||||
this.animate()
|
||||
},
|
||||
|
||||
get: function () {
|
||||
return data;
|
||||
},
|
||||
|
||||
clearTimer: function () {
|
||||
clearTimeout(timer);
|
||||
timer = null;
|
||||
active = false;
|
||||
},
|
||||
|
||||
init: function () {
|
||||
timer = setTimeout(this.hide, 2000);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
16
assets/js/services/sharedServices.js
Normal file
16
assets/js/services/sharedServices.js
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
'use strict';
|
||||
|
||||
/**
|
||||
* Services that persists and retrieves user from localStorage.
|
||||
*/
|
||||
|
||||
angular.module('sharedServices', [] ).
|
||||
factory("Items", ['$rootScope', function($rootScope){
|
||||
return window.habitrpgShared.items;
|
||||
}]).
|
||||
factory("Algos", ['$rootScope', function($rootScope){
|
||||
return window.habitrpgShared.algos;
|
||||
}]).
|
||||
factory("Helpers", ['$rootScope', function($rootScope){
|
||||
return window.habitrpgShared.helpers;
|
||||
}]);
|
||||
169
assets/js/services/userServices.js
Normal file
169
assets/js/services/userServices.js
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
'use strict';
|
||||
|
||||
/**
|
||||
* Services that persists and retrieves user from localStorage.
|
||||
*/
|
||||
|
||||
angular.module('userServices', []).
|
||||
factory('User', ['$http', '$location', 'Notification', 'API_URL',
|
||||
function($http, $location, Notification, API_URL) {
|
||||
var STORAGE_ID = 'habitrpg-user',
|
||||
HABIT_MOBILE_SETTINGS = 'habit-mobile-settings',
|
||||
authenticated = false,
|
||||
defaultSettings = {
|
||||
auth: { apiId: '', apiToken: ''},
|
||||
sync: {
|
||||
queue: [], //here OT will be queued up, this is NOT call-back queue!
|
||||
sent: [] //here will be OT which have been sent, but we have not got reply from server yet.
|
||||
},
|
||||
fetching: false, // whether fetch() was called or no. this is to avoid race conditions
|
||||
online: false
|
||||
},
|
||||
settings = {}, //habit mobile settings (like auth etc.) to be stored here
|
||||
user = {}; // this is stored as a reference accessible to all controllers, that way updates propagate
|
||||
|
||||
//first we populate user with schema
|
||||
_.extend(user, window.habitrpgShared.helpers.newUser());
|
||||
user.apiToken = user._id = ''; // we use id / apitoken to determine if registered
|
||||
|
||||
//than we try to load localStorage
|
||||
|
||||
if (localStorage.getItem(STORAGE_ID)) {
|
||||
_.extend(user, JSON.parse(localStorage.getItem(STORAGE_ID)));
|
||||
}
|
||||
|
||||
var syncQueue = function (cb) {
|
||||
if (!authenticated) {
|
||||
alert("Not authenticated, can't sync, go to settings first.");
|
||||
return;
|
||||
}
|
||||
|
||||
var queue = settings.sync.queue;
|
||||
var sent = settings.sync.sent;
|
||||
if (queue.length === 0) {
|
||||
console.log('Sync: Queue is empty');
|
||||
return;
|
||||
}
|
||||
if (settings.fetching) {
|
||||
console.log('Sync: Already fetching');
|
||||
return;
|
||||
}
|
||||
if (settings.online!==true) {
|
||||
console.log('Sync: Not online');
|
||||
return;
|
||||
}
|
||||
|
||||
settings.fetching = true;
|
||||
// move all actions from queue array to sent array
|
||||
_.times(queue.length, function () {
|
||||
sent.push(queue.shift());
|
||||
});
|
||||
|
||||
|
||||
$http.post(API_URL + '/api/v1/user/batch-update' + '?date=' + new Date().getTime(), sent)
|
||||
.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.
|
||||
_.extend(user, data);
|
||||
|
||||
// FIXME handle this somewhere else, we don't need to check every single time
|
||||
var offset = moment().zone(); // eg, 240 - this will be converted on server as -(offset/60)
|
||||
if (!user.preferences.timezoneOffset || user.preferences.timezoneOffset !== offset) {
|
||||
userServices.log({op:'set', data: {'preferences.timezoneOffset': offset}});
|
||||
}
|
||||
}
|
||||
sent.length = 0;
|
||||
settings.fetching = false;
|
||||
save();
|
||||
if (cb) {
|
||||
cb(false)
|
||||
}
|
||||
|
||||
syncQueue(); // call syncQueue to check if anyone pushed more actions to the queue while we were talking to server.
|
||||
})
|
||||
.error(function (data, status, headers, config) {
|
||||
//move sent actions back to queue
|
||||
_.times(sent.length, function () {
|
||||
queue.push(sent.shift())
|
||||
});
|
||||
settings.fetching = false;
|
||||
Notification.push({type:'text', text:"We're offline"})
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
var save = function () {
|
||||
localStorage.setItem(STORAGE_ID, JSON.stringify(user));
|
||||
localStorage.setItem(HABIT_MOBILE_SETTINGS, JSON.stringify(settings));
|
||||
};
|
||||
var userServices = {
|
||||
user: user,
|
||||
online: function (status) {
|
||||
if (status===true) {
|
||||
settings.online = true;
|
||||
syncQueue();
|
||||
} else {
|
||||
settings.online = false;
|
||||
};
|
||||
},
|
||||
|
||||
authenticate: function (uuid, token, cb) {
|
||||
if (!!uuid && !!token) {
|
||||
$http.defaults.headers.common = {'Content-Type': "application/json;charset=utf-8"};
|
||||
$http.defaults.headers.common['x-api-user'] = uuid;
|
||||
$http.defaults.headers.common['x-api-key'] = token;
|
||||
authenticated = true;
|
||||
settings.auth.apiId = uuid;
|
||||
settings.auth.apiToken = token;
|
||||
settings.online = true;
|
||||
this.log({}, cb);
|
||||
} else {
|
||||
alert('Please enter your ID and Token in settings.')
|
||||
}
|
||||
},
|
||||
|
||||
log: function (action, cb) {
|
||||
//push by one buy one if an array passed in.
|
||||
if (_.isArray(action)) {
|
||||
action.forEach(function (a) {
|
||||
settings.sync.queue.push(a);
|
||||
});
|
||||
} else {
|
||||
settings.sync.queue.push(action);
|
||||
}
|
||||
|
||||
save();
|
||||
syncQueue(cb);
|
||||
},
|
||||
settings: settings
|
||||
};
|
||||
|
||||
|
||||
//load settings if we have them
|
||||
if (localStorage.getItem(HABIT_MOBILE_SETTINGS)) {
|
||||
//use extend here to make sure we keep object reference in other angular controllers
|
||||
_.extend(settings, JSON.parse(localStorage.getItem(HABIT_MOBILE_SETTINGS)));
|
||||
|
||||
//if settings were saved while fetch was in process reset the flag.
|
||||
settings.fetching = false;
|
||||
//create and load if not
|
||||
} else {
|
||||
localStorage.setItem(HABIT_MOBILE_SETTINGS, JSON.stringify(defaultSettings));
|
||||
_.extend(settings, defaultSettings);
|
||||
}
|
||||
|
||||
//If user does not have ApiID that forward him to settings.
|
||||
if (!settings.auth.apiId || !settings.auth.apiToken) {
|
||||
$location.path("/login");
|
||||
} else {
|
||||
userServices.authenticate(settings.auth.apiId, settings.auth.apiToken)
|
||||
}
|
||||
|
||||
return userServices;
|
||||
|
||||
}
|
||||
]);
|
||||
222
assets/js/tasks.js
Normal file
222
assets/js/tasks.js
Normal file
|
|
@ -0,0 +1,222 @@
|
|||
// Generated by CoffeeScript 1.6.3
|
||||
(function() {
|
||||
var algos, helpers, misc, moment, _;
|
||||
|
||||
algos = require('habitrpg-shared/script/algos');
|
||||
|
||||
helpers = require('habitrpg-shared/script/helpers');
|
||||
|
||||
_ = require('lodash');
|
||||
|
||||
moment = require('moment');
|
||||
|
||||
misc = require('./misc');
|
||||
|
||||
/*
|
||||
Make scoring functionality available to the app
|
||||
*/
|
||||
|
||||
|
||||
module.exports.app = function(appExports, model) {
|
||||
var user;
|
||||
user = model.at('_user');
|
||||
appExports.addTask = function(e, el) {
|
||||
var newModel, newTask, text, type;
|
||||
type = $(el).attr('data-task-type');
|
||||
newModel = model.at('_new' + type.charAt(0).toUpperCase() + type.slice(1));
|
||||
text = newModel.get();
|
||||
if (/^(\s)*$/.test(text) || text === void 0) {
|
||||
return;
|
||||
}
|
||||
newTask = {
|
||||
id: model.id(),
|
||||
type: type,
|
||||
text: text,
|
||||
notes: '',
|
||||
value: 0
|
||||
};
|
||||
newTask.tags = _.reduce(user.get('filters'), (function(memo, v, k) {
|
||||
if (v) {
|
||||
memo[k] = v;
|
||||
}
|
||||
return memo;
|
||||
}), {});
|
||||
switch (type) {
|
||||
case 'habit':
|
||||
newTask = _.defaults({
|
||||
up: true,
|
||||
down: true
|
||||
}, newTask);
|
||||
break;
|
||||
case 'reward':
|
||||
newTask = _.defaults({
|
||||
value: 20
|
||||
}, newTask);
|
||||
break;
|
||||
case 'daily':
|
||||
newTask = _.defaults({
|
||||
repeat: {
|
||||
su: true,
|
||||
m: true,
|
||||
t: true,
|
||||
w: true,
|
||||
th: true,
|
||||
f: true,
|
||||
s: true
|
||||
},
|
||||
completed: false
|
||||
}, newTask);
|
||||
break;
|
||||
case 'todo':
|
||||
newTask = _.defaults({
|
||||
completed: false
|
||||
}, newTask);
|
||||
}
|
||||
e.at().unshift(newTask);
|
||||
return newModel.set('');
|
||||
};
|
||||
appExports.del = function(e) {
|
||||
if (confirm("Are you sure you want to delete this task?") !== true) {
|
||||
return;
|
||||
}
|
||||
$('[rel=tooltip]').tooltip('hide');
|
||||
user.del("tasks." + (e.get('id')));
|
||||
return e.at().remove();
|
||||
};
|
||||
appExports.clearCompleted = function(e, el) {
|
||||
var completedIds, todoIds;
|
||||
completedIds = _.pluck(_.where(model.get('_todoList'), {
|
||||
completed: true
|
||||
}), 'id');
|
||||
todoIds = user.get('todoIds');
|
||||
_.each(completedIds, function(id) {
|
||||
user.del("tasks." + id);
|
||||
return true;
|
||||
});
|
||||
return user.set('todoIds', _.difference(todoIds, completedIds));
|
||||
};
|
||||
appExports.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);
|
||||
}
|
||||
};
|
||||
appExports.toggleTaskEdit = function(e, el) {
|
||||
var chartPath, editPath, id, _ref;
|
||||
id = e.get('id');
|
||||
_ref = ["_tasks.editing." + id, "_page.charts." + id], editPath = _ref[0], chartPath = _ref[1];
|
||||
model.set(editPath, !(model.get(editPath)));
|
||||
return model.set(chartPath, false);
|
||||
};
|
||||
appExports.toggleChart = function(e, el) {
|
||||
var chart, data, history, historyPath, id, matrix, options, togglePath, _ref, _ref1, _ref2, _ref3;
|
||||
id = $(el).attr('data-id');
|
||||
_ref = ['', ''], historyPath = _ref[0], togglePath = _ref[1];
|
||||
switch (id) {
|
||||
case 'exp':
|
||||
_ref1 = ['_page.charts.exp', '_user.history.exp'], togglePath = _ref1[0], historyPath = _ref1[1];
|
||||
break;
|
||||
case 'todos':
|
||||
_ref2 = ['_page.charts.todos', '_user.history.todos'], togglePath = _ref2[0], historyPath = _ref2[1];
|
||||
break;
|
||||
default:
|
||||
_ref3 = ["_page.charts." + id, "_user.tasks." + id + ".history"], togglePath = _ref3[0], historyPath = _ref3[1];
|
||||
model.set("_tasks.editing." + id, false);
|
||||
}
|
||||
history = model.get(historyPath);
|
||||
model.set(togglePath, !(model.get(togglePath)));
|
||||
matrix = [['Date', 'Score']];
|
||||
_.each(history, function(obj) {
|
||||
return matrix.push([moment(obj.date).format('MM/DD/YY'), obj.value]);
|
||||
});
|
||||
data = google.visualization.arrayToDataTable(matrix);
|
||||
options = {
|
||||
title: 'History',
|
||||
backgroundColor: {
|
||||
fill: 'transparent'
|
||||
}
|
||||
};
|
||||
chart = new google.visualization.LineChart($("." + id + "-chart")[0]);
|
||||
return chart.draw(data, options);
|
||||
};
|
||||
appExports.todosShowRemaining = function() {
|
||||
return model.set('_showCompleted', false);
|
||||
};
|
||||
appExports.todosShowCompleted = function() {
|
||||
return model.set('_showCompleted', true);
|
||||
};
|
||||
/*
|
||||
Call scoring functions for habits & rewards (todos & dailies handled below)
|
||||
*/
|
||||
|
||||
appExports.score = function(e, el) {
|
||||
var direction, id;
|
||||
id = $(el).parents('li').attr('data-id');
|
||||
direction = $(el).attr('data-direction');
|
||||
return misc.score(model, id, direction, true);
|
||||
};
|
||||
/*
|
||||
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', function(i, completed, previous, isLocal, passed) {
|
||||
var direction;
|
||||
if (!isLocal || (passed != null ? passed.cron : void 0)) {
|
||||
return;
|
||||
}
|
||||
direction = completed ? 'up' : 'down';
|
||||
return misc.score(model, i, direction, true);
|
||||
});
|
||||
/*
|
||||
Undo
|
||||
*/
|
||||
|
||||
appExports.undo = function() {
|
||||
var taskPath, undo;
|
||||
undo = model.get('_undo');
|
||||
if (undo != null ? undo.timeoutId : void 0) {
|
||||
clearTimeout(undo.timeoutId);
|
||||
}
|
||||
model.del('_undo');
|
||||
_.each(undo.stats, function(val, key) {
|
||||
user.set("stats." + key, val);
|
||||
return true;
|
||||
});
|
||||
taskPath = "tasks." + undo.task.id;
|
||||
return _.each(undo.task, function(val, key) {
|
||||
if (key === 'id' || key === 'type') {
|
||||
return true;
|
||||
}
|
||||
if (key === 'completed') {
|
||||
user.pass({
|
||||
cron: true
|
||||
}).set("" + taskPath + ".completed", val);
|
||||
} else {
|
||||
user.set("" + taskPath + "." + key, val);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
};
|
||||
appExports.tasksToggleAdvanced = function(e, el) {
|
||||
return $(el).next('.advanced-option').toggleClass('visuallyhidden');
|
||||
};
|
||||
appExports.tasksSaveAndClose = function() {
|
||||
$('[rel=tooltip]').tooltip();
|
||||
return $('[rel=popover]').popover();
|
||||
};
|
||||
return appExports.tasksSetPriority = function(e, el) {
|
||||
var dataId;
|
||||
dataId = $(el).parent('[data-id]').attr('data-id');
|
||||
return model.at(e.target).set('priority', $(el).attr('data-priority'));
|
||||
};
|
||||
};
|
||||
|
||||
}).call(this);
|
||||
|
||||
/*
|
||||
//@ sourceMappingURL=tasks.map
|
||||
*/
|
||||
10
assets/js/tasks.map
Normal file
10
assets/js/tasks.map
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"version": 3,
|
||||
"file": "tasks.js",
|
||||
"sourceRoot": "",
|
||||
"sources": [
|
||||
"tasks.coffee"
|
||||
],
|
||||
"names": [],
|
||||
"mappings": "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"
|
||||
}
|
||||
135
assets/js/unlock.js
Normal file
135
assets/js/unlock.js
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
// Generated by CoffeeScript 1.6.3
|
||||
(function() {
|
||||
var hatchingPotions, pets, randomVal, _, _ref;
|
||||
|
||||
_ = require('lodash');
|
||||
|
||||
randomVal = require('habitrpg-shared/script/helpers').randomVal;
|
||||
|
||||
_ref = require('habitrpg-shared/script/items').items, pets = _ref.pets, hatchingPotions = _ref.hatchingPotions;
|
||||
|
||||
/*
|
||||
Listeners to enabled flags, set notifications to the user when they've unlocked features
|
||||
*/
|
||||
|
||||
|
||||
module.exports.app = function(appExports, model) {
|
||||
var alreadyShown, showPopover, user;
|
||||
user = model.at('_user');
|
||||
alreadyShown = function(before, after) {
|
||||
return !(!before && after === true);
|
||||
};
|
||||
showPopover = function(selector, title, html, placement) {
|
||||
if (placement == null) {
|
||||
placement = 'bottom';
|
||||
}
|
||||
$(selector).popover('destroy');
|
||||
html += " <a href='#' onClick=\"$('" + selector + "').popover('hide');return false;\">[Close]</a>";
|
||||
return $(selector).popover({
|
||||
title: title,
|
||||
placement: placement,
|
||||
trigger: 'manual',
|
||||
html: true,
|
||||
content: html
|
||||
}).popover('show');
|
||||
};
|
||||
user.on('set', 'flags.customizationsNotification', function(after, before) {
|
||||
var html;
|
||||
if (alreadyShown(before, after)) {
|
||||
return;
|
||||
}
|
||||
$('.main-herobox').popover('destroy');
|
||||
html = "Click your avatar to customize your appearance.";
|
||||
return showPopover('.main-herobox', 'Customize Your Avatar', html, 'bottom');
|
||||
});
|
||||
user.on('set', 'flags.itemsEnabled', function(after, before) {
|
||||
var html;
|
||||
if (alreadyShown(before, after)) {
|
||||
return;
|
||||
}
|
||||
html = "<img src='/vendor/BrowserQuest/client/img/1/chest.png' />\nCongratulations, you have unlocked the Item Store! You can now buy weapons, armor, potions, etc. Read each item's comment for more information.";
|
||||
return showPopover('div.rewards', 'Item Store Unlocked', html, 'left');
|
||||
});
|
||||
user.on('set', 'flags.petsEnabled', function(after, before) {
|
||||
var html;
|
||||
if (alreadyShown(before, after)) {
|
||||
return;
|
||||
}
|
||||
html = "<img src='/img/sprites/wolf_border.png' style='width:30px;height:30px;float:left;padding-right:5px' />\nYou have unlocked Pets! You can now buy pets with Gems (note, you replenish Gems with real-life money - so chose your pets wisely!)";
|
||||
return showPopover('#rewardsTabs', 'Pets Unlocked', html, 'left');
|
||||
});
|
||||
user.on('set', 'flags.partyEnabled', function(after, before) {
|
||||
var html;
|
||||
if (user.get('party.current') || alreadyShown(before, after)) {
|
||||
return;
|
||||
}
|
||||
html = "Be social, join a party and play Habit with your friends! You'll be better at your habits with accountability partners. Click User -> Options -> Party, and follow the instructions. LFG anyone?";
|
||||
return showPopover('.user-menu', 'Party System', html, 'bottom');
|
||||
});
|
||||
user.on('set', 'flags.dropsEnabled', function(after, before) {
|
||||
var dontPersist, egg;
|
||||
if (alreadyShown(before, after)) {
|
||||
return;
|
||||
}
|
||||
egg = randomVal(pets);
|
||||
dontPersist = model._dontPersist;
|
||||
model._dontPersist = false;
|
||||
user.push('items.eggs', egg);
|
||||
model._dontPersist = dontPersist;
|
||||
return $('#drops-enabled-modal').modal('show');
|
||||
});
|
||||
user.on('push', 'items.pets', function(after, before) {
|
||||
var dontPersist;
|
||||
if (user.get('achievements.beastMaster')) {
|
||||
return;
|
||||
}
|
||||
if (before >= 90) {
|
||||
dontPersist = model._dontPersist;
|
||||
model._dontPersist = false;
|
||||
user.set('achievements.beastMaster', true, (function() {
|
||||
return model._dontPersist = dontPersist;
|
||||
}));
|
||||
return $('#beastmaster-achievement-modal').modal('show');
|
||||
}
|
||||
});
|
||||
user.on('set', 'items.*', function(after, before) {
|
||||
var dontPersist, items;
|
||||
if (user.get('achievements.ultimateGear')) {
|
||||
return;
|
||||
}
|
||||
items = user.get('items');
|
||||
if (parseInt(items.weapon) >= 6 && parseInt(items.armor) >= 5 && parseInt(items.head) >= 5 && parseInt(items.shield) >= 5) {
|
||||
dontPersist = model._dontPersist;
|
||||
model._dontPersist = false;
|
||||
user.set('achievements.ultimateGear', true, (function() {
|
||||
return model._dontPersist = dontPersist;
|
||||
}));
|
||||
return $('#max-gear-achievement-modal').modal('show');
|
||||
}
|
||||
});
|
||||
return user.on('set', 'tasks.*.streak', function(id, after, before) {
|
||||
var dontPersist;
|
||||
if (after > 0) {
|
||||
if ((after % 21) === 0) {
|
||||
dontPersist = model._dontPersist;
|
||||
model._dontPersist = false;
|
||||
user.incr('achievements.streak', 1, (function() {
|
||||
return model._dontPersist = dontPersist;
|
||||
}));
|
||||
return $('#streak-achievement-modal').modal('show');
|
||||
} else if ((before - after === 1) && (before % 21 === 0)) {
|
||||
dontPersist = model._dontPersist;
|
||||
model._dontPersist = false;
|
||||
return user.incr('achievements.streak', -1, (function() {
|
||||
return model._dontPersist = dontPersist;
|
||||
}));
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
}).call(this);
|
||||
|
||||
/*
|
||||
//@ sourceMappingURL=unlock.map
|
||||
*/
|
||||
10
assets/js/unlock.map
Normal file
10
assets/js/unlock.map
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"version": 3,
|
||||
"file": "unlock.js",
|
||||
"sourceRoot": "",
|
||||
"sources": [
|
||||
"unlock.coffee"
|
||||
],
|
||||
"names": [],
|
||||
"mappings": ";AAAA;CAAA,KAAA,mCAAA;;CAAA,CAAA,CAAI,IAAA,CAAA;;CAAJ,CACE,CAAc,IAAA,EADhB,uBACgB;;CADhB,CAEA,EAAA,CAAA,EAA4B,QAF5B,eAE4B;;CAE5B;;;CAJA;;CAAA,CAQA,CAAA,EAAqB,CAAf,CAAQ,EAAQ,CAAD;CACnB,OAAA,uBAAA;CAAA,CAAO,CAAA,CAAP,CAAY,EAAL;CAAP,CAEwB,CAAT,CAAf,CAAe,CAAA,GAAC,GAAhB;AAAmC,CAAD,GAAc,CAAA,CAAZ,OAAF;CAFlC,IAEe;CAFf,CAIyB,CAAX,CAAd,CAAc,GAAA,CAAC,EAAf;;GAAgD,KAAV;QACpC;CAAA,KAAA,CAAA,CAAA,CAAA;CAAA,EACoC,CAApC,EAAA,EAAS,oBAAA,oBADT;CAEA,MAAA,CAAA,KAAA;CAAoB,CACX,GAAP,GAAA;CADkB,CAEP,MAAX,CAAA;CAFkB,CAGT,KAAT,CAAA;CAHkB,CAIZ,EAAN,IAAA;CAJkB,CAKT,EALS,GAKlB,CAAA;CACA,KANF,CAAA,CAAA;CAPF,IAIc;CAJd,CAgBA,CAAmD,CAAnD,CAAA,CAAmD,GAAC,yBAApD;CACE,GAAA,MAAA;CAAA,CAA8B,EAApB,CAAA,CAAV,MAAU;CAAV,aAAA;QAAA;CAAA,KACA,CAAA,EAAA,MAAA;CADA,EAEO,CAAP,EAAA,2CAFA;CAGY,CAAiB,EAA7B,IAAA,GAAA,EAAA,EAAA,QAAA;CAJF,IAAmD;CAhBnD,CAsBA,CAAqC,CAArC,CAAA,CAAqC,GAAC,WAAtC;CACE,GAAA,MAAA;CAAA,CAA8B,EAApB,CAAA,CAAV,MAAU;CAAV,aAAA;QAAA;CAAA,EACO,CAAP,EAAA,sMADA;CAKY,CAAe,EAA3B,EAAA,KAAA,EAAA,QAAA;CANF,IAAqC;CAtBrC,CA8BA,CAAoC,CAApC,CAAA,CAAoC,GAAC,UAArC;CACE,GAAA,MAAA;CAAA,CAA8B,EAApB,CAAA,CAAV,MAAU;CAAV,aAAA;QAAA;CAAA,EACO,CAAP,EAAA,uOADA;CAKY,CAAgB,EAA5B,EAAA,KAAA,EAAA,CAAA,CAAA;CANF,IAAoC;CA9BpC,CAsCA,CAAqC,CAArC,CAAA,CAAqC,GAAC,WAAtC;CACE,GAAA,MAAA;CAAA,CAA2D,CAAjD,CAAA,CAA6B,CAAvC,MAAuC,GAA7B;CAAV,aAAA;QAAA;CAAA,EACO,CAAP,EAAA,4LADA;CAIY,CAAc,EAA1B,IAAA,GAAA,CAAA,CAAA,CAAA;CALF,IAAqC;CAtCrC,CA6CA,CAAqC,CAArC,CAAA,CAAqC,GAAC,WAAtC;CACE,SAAA,MAAA;CAAA,CAA8B,EAApB,CAAA,CAAV,MAAU;CAAV,aAAA;QAAA;CAAA,EAEA,CAAM,EAAN,GAAM;CAFN,EAIe,EAAK,CAApB,KAAA,CAJA;CAAA,EAMqB,EAAhB,CAAL,MAAA;CANA,CAOwB,CAAxB,CAAI,EAAJ,MAAA;CAPA,EAQqB,EAAhB,CAAL,KARA,CAQA;CAEA,IAAA,CAAA,OAAA,SAAA;CAXF,IAAqC;CA7CrC,CA0DA,CAA8B,CAA9B,CAA8B,CAA9B,GAA+B,GAA/B;CACE,SAAA,CAAA;CAAA,EAAU,CAAA,EAAV,oBAAU;CAAV,aAAA;QAAA;CACA,CAAA,EAAG,EAAH;CACE,EAAe,EAAK,GAApB,GAAA,CAAA;CAAA,EAAwD,EAAhB,GAAL,IAAA;CAAnC,CACqC,CAArC,CAAI,IAAJ,CAA4C,iBAA5C;CAAqD,EAAe,EAAhB,OAAL,KAAA;CAAJ,QAAC;CAC5C,IAAA,CAAA,SAAA,iBAAA;QAL0B;CAA9B,IAA8B;CA1D9B,CAiEA,CAA0B,CAA1B,CAAA,CAA0B,GAA1B;CACE,SAAA,QAAA;CAAA,EAAU,CAAA,EAAV,qBAAU;CAAV,aAAA;QAAA;CAAA,EACQ,CAAI,CAAZ,CAAA,CAAQ;CACR,GAAG,CAAc,CAAjB,EAAG;CACD,EAAc,EAAK,GAAnB,GAAA,CAAA;CAAA,EAAuD,EAAhB,GAAL,IAAA;CAAlC,CACsC,CAAtC,CAAI,IAAJ,CAA6C,kBAA7C;CAAqD,EAAe,EAAhB,OAAL,KAAA;CAAH,QAAC;CAC7C,IAAA,CAAA,SAAA,cAAA;QANsB;CAA1B,IAA0B;CAQrB,CAAL,CAAiC,CAA7B,CAAJ,CAAiC,GAAC,EAAlC,KAAA;CACE,SAAA,CAAA;CAAA,EAAW,CAAR,CAAA,CAAH;CAGE,CAAG,CAAS,CAAT,CAAC,GAAJ;CACE,EAAe,EAAK,KAApB,CAAA,CAAA;CAAA,EAAwD,EAAhB,KAAL,EAAA;CAAnC,CACiC,CAAI,CAAjC,KAAiC,CAArC,WAAA;CAA8C,EAAe,EAAhB,OAAL,OAAA;CAAJ,UAAC;CACrC,IAAA,CAAA,WAAA,UAAA;CAGO,CAA0B,CAAjB,CAAV,CAAC,CANT,IAAA;CAOE,EAAe,EAAK,KAApB,CAAA,CAAA;CAAA,EAAwD,EAAhB,KAAL,EAAA;AACD,CAA7B,CAA4B,CAAK,CAAlC,KAAkC,QAAtC,IAAA;CAA+C,EAAe,EAAhB,OAAL,OAAA;CAAJ,UAAC;UAX1C;QAD+B;CAAjC,IAAiC;CAlFnC,EAQqB;CARrB"
|
||||
}
|
||||
27
bower.json
Normal file
27
bower.json
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"name": "HabitRPG",
|
||||
"version": "0.1.1",
|
||||
"homepage": "https://github.com/lefnire/habitrpg",
|
||||
"authors": [
|
||||
"Tyler Renelle <tylerrenelle@gmail.com>"
|
||||
],
|
||||
"private": true,
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"node_modules",
|
||||
"public/bower_components",
|
||||
"test",
|
||||
"tests"
|
||||
],
|
||||
"dependencies": {
|
||||
"jquery": "~2.0.3",
|
||||
"angular": "1.2.0-rc.1",
|
||||
"angular-resource": "1.2.0-rc.1",
|
||||
"habitrpg-shared": "git://github.com/HabitRPG/habitrpg-shared.git#master",
|
||||
"bootstrap": "v2.3.2",
|
||||
"angular-ui": "~0.4.0",
|
||||
"angular-bootstrap": "~0.5.0",
|
||||
"lodash": "~1.3.1",
|
||||
"moment": "~2.1.0"
|
||||
}
|
||||
}
|
||||
15
package.json
15
package.json
|
|
@ -5,10 +5,6 @@
|
|||
"main": "./server.js",
|
||||
"dependencies": {
|
||||
"habitrpg-shared": "git://github.com/HabitRPG/habitrpg-shared#master",
|
||||
"derby": "git://github.com/lefnire/derby#habitrpg",
|
||||
"racer": "git://github.com/lefnire/racer#habitrpg",
|
||||
"racer-db-mongo": "git://github.com/lefnire/racer-db-mongo#habitrpg",
|
||||
"derby-ui-boot": "git://github.com/HabitRPG/derby-ui-boot#habit0.3",
|
||||
"derby-auth": "git://github.com/lefnire/derby-auth#master",
|
||||
"connect-mongo": "*",
|
||||
"passport-facebook": "*",
|
||||
|
|
@ -17,19 +13,20 @@
|
|||
"guid": "*",
|
||||
"moment": "*",
|
||||
"stripe": "*",
|
||||
"coffee-script": "1.4.x",
|
||||
"mongoskin": "*",
|
||||
"coffee-script": "*",
|
||||
"nconf": "*",
|
||||
"icalendar": "git://github.com/lefnire/node-icalendar#master",
|
||||
"superagent": "~0.12.4",
|
||||
"resolve": "~0.2.3",
|
||||
"expect.js": "~0.2.0",
|
||||
"derby-i18n": "git://github.com/switz/derby-i18n#master",
|
||||
"relative-date": "~1.1.1",
|
||||
"lodash": "~1.3.1",
|
||||
"async": "~0.2.9",
|
||||
"optimist": "~0.5.2",
|
||||
"mongoose": "~3.6.18"
|
||||
"mongoose": "~3.6.18",
|
||||
"stylus": "~0.37.0",
|
||||
"connect-assets": "~2.5.2",
|
||||
"bower": "~1.2.4"
|
||||
},
|
||||
"private": true,
|
||||
"subdomain": "habitrpg",
|
||||
|
|
@ -42,7 +39,7 @@
|
|||
"npm": "1.1.x"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "server.js",
|
||||
"start": "nodemon src/server.coffee",
|
||||
"test": "mocha test/api.mocha.coffee"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
78
server.js
78
server.js
|
|
@ -1,78 +0,0 @@
|
|||
// Load nconf and define default configuration values if config.json or ENV vars are not found
|
||||
var conf = require('nconf');
|
||||
conf.argv().env().file({ file: __dirname + "/config.json" }).defaults({
|
||||
'PORT': 3000,
|
||||
'IP': '0.0.0.0',
|
||||
'BASE_URL': 'http://localhost',
|
||||
'NODE_ENV': 'development'
|
||||
});
|
||||
|
||||
// Override normal ENV values with nconf ENV values (ENV values are used the same way without nconf)
|
||||
process.env.IP = conf.get("IP");
|
||||
process.env.PORT = conf.get("PORT");
|
||||
process.env.BASE_URL = conf.get("BASE_URL");
|
||||
process.env.FACEBOOK_KEY = conf.get("FACEBOOK_KEY");
|
||||
process.env.FACEBOOK_SECRET = conf.get("FACEBOOK_SECRET");
|
||||
process.env.NODE_DB_URI = conf.get("NODE_DB_URI");
|
||||
process.env.NODE_ENV = conf.get("NODE_ENV");
|
||||
process.env.SESSION_SECRET = conf.get("SESSION_SECRET");
|
||||
process.env.SMTP_USER = conf.get("SMTP_USER");
|
||||
process.env.SMTP_PASS = conf.get("SMTP_PASS");
|
||||
process.env.SMTP_SERVICE = conf.get("SMTP_SERVICE");
|
||||
process.env.STRIPE_API_KEY = conf.get("STRIPE_API_KEY");
|
||||
process.env.STRIPE_PUB_KEY = conf.get("STRIPE_PUB_KEY");
|
||||
|
||||
/*var agent;
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
// Follow these instructions for profiling / debugging leaks
|
||||
// * https://developers.google.com/chrome-developer-tools/docs/heap-profiling
|
||||
// * https://developers.google.com/chrome-developer-tools/docs/memory-analysis-101
|
||||
agent = require('webkit-devtools-agent');
|
||||
console.log("To debug memory leaks:" +
|
||||
"\n\t(1) Run `kill -SIGUSR2 " + process.pid + "`" +
|
||||
"\n\t(2) open http://c4milo.github.com/node-webkit-agent/21.0.1180.57/inspector.html?host=localhost:1337&page=0");
|
||||
}*/
|
||||
|
||||
if (process.env.NODE_ENV === 'development') Error.stackTraceLimit = Infinity;
|
||||
|
||||
process.on('uncaughtException', function (error) {
|
||||
|
||||
function sendEmail(mailData) {
|
||||
var nodemailer = require("derby-auth/node_modules/nodemailer");
|
||||
|
||||
// create reusable transport method (opens pool of SMTP connections)
|
||||
// TODO derby-auth isn't currently configurable here, if you need customizations please send pull request
|
||||
var smtpTransport = nodemailer.createTransport("SMTP",{
|
||||
service: process.env.SMTP_SERVICE,
|
||||
auth: {
|
||||
user: process.env.SMTP_USER,
|
||||
pass: process.env.SMTP_PASS
|
||||
}
|
||||
});
|
||||
|
||||
// send mail with defined transport object
|
||||
smtpTransport.sendMail(mailData, function(error, response){
|
||||
if(error){
|
||||
console.log(error);
|
||||
}else{
|
||||
console.log("Message sent: " + response.message);
|
||||
}
|
||||
|
||||
smtpTransport.close(); // shut down the connection pool, no more messages
|
||||
});
|
||||
}
|
||||
|
||||
sendEmail({
|
||||
from: "HabitRPG <admin@habitrpg.com>",
|
||||
to: "tylerrenelle@gmail.com",
|
||||
subject: "HabitRPG Error",
|
||||
text: error.stack
|
||||
});
|
||||
console.log(error.stack);
|
||||
});
|
||||
|
||||
require('coffee-script') // remove intermediate compilation requirement
|
||||
require('./src/server').listen(process.env.PORT || 3000, process.env.IP || '0.0.0.0');
|
||||
|
||||
// Note: removed "up" module, which is default for development (but interferes with and production + PaaS)
|
||||
// Restore to 5310bb0 if I want it back (see https://github.com/codeparty/derby/issues/165#issuecomment-10405693)
|
||||
20
src/config.coffee
Normal file
20
src/config.coffee
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
# Load nconf and define default configuration values if config.json or ENV vars are not found
|
||||
conf = require("nconf")
|
||||
path = require("path")
|
||||
conf
|
||||
.argv()
|
||||
.env()
|
||||
.file('defaults', path.join(path.resolve __dirname, '../config.json.example'))
|
||||
.file('user', path.join(path.resolve __dirname, '../config.json'))
|
||||
|
||||
#var agent;
|
||||
#if (process.env.NODE_ENV === 'development') {
|
||||
# // Follow these instructions for profiling / debugging leaks
|
||||
# // * https://developers.google.com/chrome-developer-tools/docs/heap-profiling
|
||||
# // * https://developers.google.com/chrome-developer-tools/docs/memory-analysis-101
|
||||
# agent = require('webkit-devtools-agent');
|
||||
# console.log("To debug memory leaks:" +
|
||||
# "\n\t(1) Run `kill -SIGUSR2 " + process.pid + "`" +
|
||||
# "\n\t(2) open http://c4milo.github.com/node-webkit-agent/21.0.1180.57/inspector.html?host=localhost:1337&page=0");
|
||||
#}
|
||||
Error.stackTraceLimit = Infinity if conf.get('NODE_ENV') is "development"
|
||||
|
|
@ -9,9 +9,8 @@ validator = require 'derby-auth/node_modules/validator'
|
|||
check = validator.check
|
||||
sanitize = validator.sanitize
|
||||
utils = require 'derby-auth/utils'
|
||||
misc = require '../app/misc'
|
||||
derbyAuthUtil = require('derby-auth/utils')
|
||||
User = require('./models/user').model
|
||||
User = require('./../models/user').model
|
||||
|
||||
api = module.exports
|
||||
|
||||
30
src/errors.coffee
Normal file
30
src/errors.coffee
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
nconf = require('nconf')
|
||||
|
||||
process.on "uncaughtException", (error) ->
|
||||
sendEmail = (mailData) ->
|
||||
nodemailer = require("derby-auth/node_modules/nodemailer")
|
||||
|
||||
# create reusable transport method (opens pool of SMTP connections)
|
||||
# TODO derby-auth isn't currently configurable here, if you need customizations please send pull request
|
||||
smtpTransport = nodemailer.createTransport("SMTP",
|
||||
service: nconf.get('SMTP_SERVICE')
|
||||
auth:
|
||||
user: nconf.get('SMTP_USER')
|
||||
pass: nconf.get('SMTP_PASS')
|
||||
)
|
||||
|
||||
# send mail with defined transport object
|
||||
smtpTransport.sendMail mailData, (error, response) ->
|
||||
if error
|
||||
console.log error
|
||||
else
|
||||
console.log "Message sent: " + response.message
|
||||
smtpTransport.close() # shut down the connection pool, no more messages
|
||||
|
||||
sendEmail
|
||||
from: "HabitRPG <admin@habitrpg.com>"
|
||||
to: "tylerrenelle@gmail.com"
|
||||
subject: "HabitRPG Error"
|
||||
text: error.stack
|
||||
|
||||
console.log error.stack
|
||||
|
|
@ -32,8 +32,4 @@ translate = (req, res, next) ->
|
|||
|
||||
next()
|
||||
|
||||
apiv1Middleware = (req, res, next) ->
|
||||
req.habit ?= {}
|
||||
next()
|
||||
|
||||
module.exports = { splash, view, allowCrossDomain, translate, apiv1Middleware}
|
||||
module.exports = { splash, view, allowCrossDomain, translate}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
express = require 'express'
|
||||
router = new express.Router()
|
||||
api = require './api'
|
||||
api = require './controllers/api'
|
||||
|
||||
###
|
||||
---------- /api/v1 API ------------
|
||||
96
src/server.coffee
Normal file
96
src/server.coffee
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
express = require("express")
|
||||
http = require("http")
|
||||
path = require("path")
|
||||
app = express()
|
||||
nconf = require('nconf')
|
||||
middleware = require("./middleware")
|
||||
require('./config') # Setup configurations
|
||||
require('./errors')
|
||||
|
||||
###
|
||||
MongoDB Configuration
|
||||
###
|
||||
|
||||
mongoose = require('mongoose')
|
||||
require('./models/user') # load up the user schema - TODO is this necessary?
|
||||
module.exports = server
|
||||
|
||||
# Connect using Mongoose too for API purposes, we'll eventually phase out Derby and only use mongoose
|
||||
mongoose.connect nconf.get('NODE_DB_URI'), (err) ->
|
||||
throw err if (err)
|
||||
console.info('Connected with Mongoose')
|
||||
|
||||
###
|
||||
Server Configuration
|
||||
###
|
||||
|
||||
# all environments
|
||||
app.set "port", nconf.get('PORT')
|
||||
app.set "views", __dirname + "/../views"
|
||||
app.set "view engine", "jade"
|
||||
app.use express.favicon()
|
||||
app.use express.logger("dev")
|
||||
app.use express.bodyParser()
|
||||
app.use require('connect-assets')()
|
||||
app.use express.methodOverride()
|
||||
app.use app.router
|
||||
app.use express['static'](path.join(__dirname, "/../public"))
|
||||
|
||||
# development only
|
||||
app.use express.errorHandler() if "development" is app.get("env")
|
||||
|
||||
# Custom Directives
|
||||
app.get '/', (req, res) ->
|
||||
res.render 'index', {'HabitRPG | Your Life, The Role Playing Game'}
|
||||
app.use('/api/v1', require('./routes').middleware)
|
||||
app.use(require('./controllers/deprecated').middleware)
|
||||
|
||||
server = http.createServer(app).listen app.get("port"), ->
|
||||
console.log "Express server listening on port " + app.get("port")
|
||||
module.exports = server
|
||||
|
||||
|
||||
|
||||
#ONE_YEAR = 1000 * 60 * 60 * 24 * 365
|
||||
#TWO_WEEKS = 1000 * 60 * 60 * 24 * 14
|
||||
#root = path.dirname path.dirname __dirname
|
||||
#publicPath = path.join root, 'public'
|
||||
#
|
||||
#
|
||||
#expressApp
|
||||
# .use(middleware.allowCrossDomain)
|
||||
# .use(express.favicon("#{publicPath}/favicon.ico"))
|
||||
# # Gzip static files and serve from memory
|
||||
# .use(gzippo.staticGzip(publicPath, maxAge: ONE_YEAR))
|
||||
# # Gzip dynamically rendered content
|
||||
# .use(express.compress())
|
||||
# .use(express.bodyParser())
|
||||
# .use(express.methodOverride())
|
||||
# # Uncomment and supply secret to add Derby session handling
|
||||
# # Derby session middleware creates req.session and socket.io sessions
|
||||
# .use(express.cookieParser())
|
||||
# .use(store.sessionMiddleware
|
||||
# secret: process.env.SESSION_SECRET || 'YOUR SECRET HERE'
|
||||
# cookie: { maxAge: TWO_WEEKS } # defaults to 2 weeks? aka, can delete this line?
|
||||
# store: mongo_store
|
||||
# )
|
||||
# # Adds req.getModel method
|
||||
# .use(store.modelMiddleware())
|
||||
# .use(middleware.translate)
|
||||
# # API should be hit before all other routes
|
||||
|
||||
# # Show splash page for newcomers
|
||||
# .use(middleware.splash)
|
||||
# .use(priv.middleware)
|
||||
# .use(middleware.view)
|
||||
# .use(auth.middleware(strategies, options))
|
||||
# # Creates an express middleware from the app's routes
|
||||
# .use(app.router())
|
||||
# .use(require('./static').middleware)
|
||||
# .use(expressApp.router)
|
||||
# .use(serverError(root))
|
||||
#
|
||||
#
|
||||
## Errors
|
||||
#expressApp.all '*', (req) ->
|
||||
# throw "404: #{req.url}"
|
||||
|
|
@ -1,105 +0,0 @@
|
|||
http = require 'http'
|
||||
path = require 'path'
|
||||
express = require 'express'
|
||||
gzippo = require 'gzippo'
|
||||
derby = require 'derby'
|
||||
racer = require 'racer'
|
||||
auth = require 'derby-auth'
|
||||
app = require '../app'
|
||||
serverError = require './serverError'
|
||||
MongoStore = require('connect-mongo')(express)
|
||||
priv = require './private'
|
||||
habitrpgStore = require './store'
|
||||
middleware = require './middleware'
|
||||
helpers = require("habitrpg-shared/script/helpers")
|
||||
|
||||
# The first-fruits of our derby-expulsion, API-only for now
|
||||
mongoose = require('mongoose')
|
||||
require('./models/user') # load up the user schema - TODO is this necessary?
|
||||
|
||||
## RACER CONFIGURATION ##
|
||||
|
||||
#racer.io.set('transports', ['xhr-polling'])
|
||||
racer.ioClient.set('reconnection limit', 300000) # max reconect timeout to 5 minutes
|
||||
racer.set('bundleTimeout', 40000)
|
||||
#unless process.env.NODE_ENV == 'production'
|
||||
# racer.use(racer.logPlugin)
|
||||
# derby.use(derby.logPlugin)
|
||||
|
||||
## SERVER CONFIGURATION ##
|
||||
|
||||
expressApp = express()
|
||||
server = http.createServer expressApp
|
||||
module.exports = server
|
||||
|
||||
derby.use require('racer-db-mongo')
|
||||
module.exports.habitStore = store = derby.createStore
|
||||
db: {type: 'Mongo', uri: process.env.NODE_DB_URI, safe:true, autoreconnect: true}
|
||||
listen: server
|
||||
|
||||
# Connect using Mongoose too for API purposes, we'll eventually phase out Derby and only use mongoose
|
||||
mongoose.connect process.env.NODE_DB_URI, (err) ->
|
||||
throw err if (err)
|
||||
console.info('Connected with Mongoose')
|
||||
|
||||
ONE_YEAR = 1000 * 60 * 60 * 24 * 365
|
||||
TWO_WEEKS = 1000 * 60 * 60 * 24 * 14
|
||||
root = path.dirname path.dirname __dirname
|
||||
publicPath = path.join root, 'public'
|
||||
|
||||
# Authentication setup
|
||||
strategies =
|
||||
facebook:
|
||||
strategy: require("passport-facebook").Strategy
|
||||
conf:
|
||||
clientID: process.env.FACEBOOK_KEY
|
||||
clientSecret: process.env.FACEBOOK_SECRET
|
||||
options =
|
||||
domain: process.env.BASE_URL || 'http://localhost:3000'
|
||||
allowPurl: true
|
||||
schema: helpers.newUser(true)
|
||||
|
||||
# This has to happen before our middleware stuff
|
||||
auth.store(store, habitrpgStore.customAccessControl)
|
||||
|
||||
mongo_store = new MongoStore {url: process.env.NODE_DB_URI}, ->
|
||||
expressApp
|
||||
.use(middleware.allowCrossDomain)
|
||||
.use(express.favicon("#{publicPath}/favicon.ico"))
|
||||
# Gzip static files and serve from memory
|
||||
.use(gzippo.staticGzip(publicPath, maxAge: ONE_YEAR))
|
||||
# Gzip dynamically rendered content
|
||||
.use(express.compress())
|
||||
.use(express.bodyParser())
|
||||
.use(express.methodOverride())
|
||||
# Uncomment and supply secret to add Derby session handling
|
||||
# Derby session middleware creates req.session and socket.io sessions
|
||||
.use(express.cookieParser())
|
||||
.use(store.sessionMiddleware
|
||||
secret: process.env.SESSION_SECRET || 'YOUR SECRET HERE'
|
||||
cookie: { maxAge: TWO_WEEKS } # defaults to 2 weeks? aka, can delete this line?
|
||||
store: mongo_store
|
||||
)
|
||||
# Adds req.getModel method
|
||||
.use(store.modelMiddleware())
|
||||
.use(middleware.translate)
|
||||
# API should be hit before all other routes
|
||||
.use(middleware.apiv1Middleware)
|
||||
.use('/api/v1', require('./routes').middleware)
|
||||
.use(require('./deprecated').middleware)
|
||||
# Show splash page for newcomers
|
||||
.use(middleware.splash)
|
||||
.use(priv.middleware)
|
||||
.use(middleware.view)
|
||||
.use(auth.middleware(strategies, options))
|
||||
# Creates an express middleware from the app's routes
|
||||
.use(app.router())
|
||||
.use(require('./static').middleware)
|
||||
.use(expressApp.router)
|
||||
.use(serverError(root))
|
||||
|
||||
priv.routes(expressApp)
|
||||
|
||||
# Errors
|
||||
expressApp.all '*', (req) ->
|
||||
throw "404: #{req.url}"
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
derby = require 'derby'
|
||||
{isProduction} = derby.util
|
||||
|
||||
module.exports = (root) ->
|
||||
staticPages = derby.createStatic root
|
||||
|
||||
return (err, req, res, next) ->
|
||||
return next() unless err?
|
||||
|
||||
console.log(if err.stack then err.stack else err)
|
||||
|
||||
## Customize error handling here ##
|
||||
message = err.message || err.toString()
|
||||
status = parseInt message
|
||||
if status is 404
|
||||
staticPages.render '404', res, {url: req.url}, 404
|
||||
else if status >= 400 and status < 600
|
||||
res.send status
|
||||
else
|
||||
staticPages.render 'error', res, {message, status}, status
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue