2012-09-24 20:45:37 +00:00
|
|
|
derby = require 'derby'
|
2012-12-31 21:09:36 +00:00
|
|
|
{get, view, ready} = derby.createApp module
|
2012-09-24 20:45:37 +00:00
|
|
|
derby.use require 'derby-ui-boot'
|
|
|
|
|
derby.use require('../../ui')
|
2012-12-04 23:18:59 +00:00
|
|
|
derby.use require('derby-auth/components');
|
2012-07-27 23:38:28 +00:00
|
|
|
|
2012-07-28 21:02:09 +00:00
|
|
|
# Custom requires
|
2012-10-11 16:52:40 +00:00
|
|
|
moment = require('moment')
|
2012-09-24 20:45:37 +00:00
|
|
|
content = require './content'
|
|
|
|
|
scoring = require './scoring'
|
|
|
|
|
schema = require './schema'
|
|
|
|
|
helpers = require './helpers'
|
|
|
|
|
helpers.viewHelpers view
|
2013-01-20 22:55:45 +00:00
|
|
|
browser = require './browser'
|
2013-01-21 00:35:31 +00:00
|
|
|
_ = require('underscore')
|
2012-06-20 21:30:10 +00:00
|
|
|
|
2013-01-21 17:15:14 +00:00
|
|
|
setupListReferences = (model) ->
|
2013-01-26 10:33:51 +00:00
|
|
|
taskTypes = ['habit', 'daily', 'todo', 'reward']
|
2013-01-21 17:15:14 +00:00
|
|
|
_.each taskTypes, (type) -> model.refList "_#{type}List", "_user.tasks", "_user.#{type}Ids"
|
|
|
|
|
|
2013-01-30 18:03:10 +00:00
|
|
|
setupModelFns = (model) ->
|
|
|
|
|
model.fn '_user._tnl', '_user.stats.lvl', (lvl) ->
|
|
|
|
|
# see https://github.com/lefnire/habitrpg/issues/4
|
|
|
|
|
# also update in scoring.coffee. TODO create a function accessible in both locations
|
|
|
|
|
(lvl*100)/5
|
|
|
|
|
|
2013-01-30 22:14:55 +00:00
|
|
|
# model.fn '_user._friends', '_user.friends', (friendIds) ->
|
|
|
|
|
# model.fetch model.query('users').friends(friendIds), (err, friends) ->
|
|
|
|
|
# model.set '_view.friends', friends
|
2013-01-30 21:52:31 +00:00
|
|
|
|
2012-07-28 01:11:53 +00:00
|
|
|
# ========== ROUTES ==========
|
2012-07-08 20:59:07 +00:00
|
|
|
|
2013-01-18 22:11:45 +00:00
|
|
|
get '/', (page, model, next) ->
|
|
|
|
|
# temporary view variables, so we don't call model.set() too fast
|
|
|
|
|
_view = model.get '_view' || {}
|
2012-11-15 15:26:35 +00:00
|
|
|
|
2013-01-17 21:30:09 +00:00
|
|
|
# Force SSL # NOTE handled by ngix now
|
|
|
|
|
#req = page._res.req
|
|
|
|
|
#if req.headers['x-forwarded-proto']!='https' and process.env.NODE_ENV=='production'
|
|
|
|
|
# return page.redirect 'https://' + req.headers.host + req.url
|
2012-09-15 19:06:51 +00:00
|
|
|
|
2013-01-23 17:51:12 +00:00
|
|
|
#FIXME subscribing to this query causes "Fatal Error: Unauuthorized" after conncetion for a time (racer/lib/accessControl/accessControl.Store.js)
|
|
|
|
|
#q = model.query('users').withId(model.session.userId)
|
|
|
|
|
q = "users.#{model.session.userId}"
|
|
|
|
|
model.subscribe q, (err, user) ->
|
|
|
|
|
#user = result.at(0)
|
2013-01-21 19:36:26 +00:00
|
|
|
model.ref '_user', user
|
2013-01-18 22:29:28 +00:00
|
|
|
userObj = user.get()
|
2013-01-22 16:49:53 +00:00
|
|
|
|
2013-01-19 19:16:59 +00:00
|
|
|
return page.redirect '/500.html' unless userObj? #this should never happen, but it is. Looking into it
|
2012-09-24 16:52:44 +00:00
|
|
|
|
2012-11-15 18:10:59 +00:00
|
|
|
# support legacy Everyauth schema (now using derby-auth, Passport)
|
2013-01-18 22:11:45 +00:00
|
|
|
if username = userObj.auth?.local?.username
|
|
|
|
|
_view.loginName = username
|
2013-01-18 22:36:14 +00:00
|
|
|
else if fb = userObj.auth?.facebook
|
2013-01-18 22:11:45 +00:00
|
|
|
_view.loginName = if fb._raw then "#{fb.name.givenName} #{fb.name.familyName}" else fb.name
|
2013-01-02 01:29:39 +00:00
|
|
|
|
2012-09-24 16:52:44 +00:00
|
|
|
# Setup Item Store
|
2013-01-22 16:49:53 +00:00
|
|
|
items = userObj.items
|
2013-01-18 22:11:45 +00:00
|
|
|
_view.items =
|
2013-01-22 16:49:53 +00:00
|
|
|
armor: content.items.armor[parseInt(items?.armor || 0) + 1]
|
|
|
|
|
weapon: content.items.weapon[parseInt(items?.weapon || 0) + 1]
|
2012-07-09 01:20:30 +00:00
|
|
|
potion: content.items.potion
|
|
|
|
|
reroll: content.items.reroll
|
2012-11-16 04:14:59 +00:00
|
|
|
|
2013-01-18 22:11:45 +00:00
|
|
|
model.set '_view', _view
|
2013-01-18 22:29:28 +00:00
|
|
|
|
2013-01-30 20:50:54 +00:00
|
|
|
schema.updateUser(user, userObj)
|
2013-01-21 17:15:14 +00:00
|
|
|
setupListReferences(model)
|
2013-01-30 18:03:10 +00:00
|
|
|
setupModelFns(model)
|
2013-01-18 22:29:28 +00:00
|
|
|
|
2013-01-30 22:14:55 +00:00
|
|
|
if !_.isEmpty(userObj.friends)
|
|
|
|
|
model.subscribe model.query('users').friends(userObj.friends), (err, friends) ->
|
|
|
|
|
model.ref '_friends', friends
|
|
|
|
|
|
2013-01-18 22:29:28 +00:00
|
|
|
page.render()
|
2012-04-27 02:19:31 +00:00
|
|
|
|
2012-07-28 01:11:53 +00:00
|
|
|
# ========== CONTROLLER FUNCTIONS ==========
|
2012-04-27 02:19:31 +00:00
|
|
|
|
2013-01-21 21:42:23 +00:00
|
|
|
resetDom = (model) ->
|
|
|
|
|
window.DERBY.app.dom.clear()
|
|
|
|
|
view.render(model)
|
2013-01-30 18:03:10 +00:00
|
|
|
setupModelFns(model)
|
2013-01-21 19:36:26 +00:00
|
|
|
|
2012-04-27 02:19:31 +00:00
|
|
|
ready (model) ->
|
2013-01-21 17:06:12 +00:00
|
|
|
user = model.at('_user')
|
2013-01-29 05:02:30 +00:00
|
|
|
|
|
|
|
|
#set cron immediately
|
|
|
|
|
lastCron = user.get('lastCron')
|
|
|
|
|
user.set('lastCron', +new Date) if (!lastCron or lastCron == 'new')
|
2013-01-21 17:06:12 +00:00
|
|
|
|
2013-01-21 19:36:26 +00:00
|
|
|
# Setup model in scoring functions
|
|
|
|
|
scoring.setModel(model)
|
2013-01-30 18:33:36 +00:00
|
|
|
scoring.cron(resetDom)
|
2013-01-21 19:36:26 +00:00
|
|
|
|
2013-01-21 17:06:12 +00:00
|
|
|
# Load all the jQuery, Growl, Tour, etc
|
2013-01-20 22:55:45 +00:00
|
|
|
browser.loadJavaScripts(model)
|
2013-01-20 23:06:34 +00:00
|
|
|
browser.setupSortable(model)
|
|
|
|
|
browser.setupTooltips(model)
|
|
|
|
|
browser.setupTour(model)
|
2013-01-21 04:21:50 +00:00
|
|
|
browser.setupGrowlNotifications(model) unless model.get('_view.mobileDevice')
|
2012-12-05 16:09:27 +00:00
|
|
|
|
2013-01-15 19:35:10 +00:00
|
|
|
require('../server/private').app(exports, model)
|
|
|
|
|
|
2013-01-21 17:06:12 +00:00
|
|
|
user.on 'set', 'tasks.*.completed', (i, completed, previous, isLocal, passed) ->
|
2012-08-06 14:15:58 +00:00
|
|
|
return if passed? && passed.cron # Don't do this stuff on cron
|
2012-07-28 00:47:59 +00:00
|
|
|
direction = () ->
|
|
|
|
|
return 'up' if completed==true and previous == false
|
|
|
|
|
return 'down' if completed==false and previous == true
|
2012-07-28 01:56:21 +00:00
|
|
|
throw new Error("Direction neither 'up' nor 'down' on checkbox set.")
|
2012-07-28 00:47:59 +00:00
|
|
|
|
|
|
|
|
# Score the user based on todo task
|
2013-01-21 17:06:12 +00:00
|
|
|
task = user.at("tasks.#{i}")
|
2012-09-24 16:52:44 +00:00
|
|
|
scoring.score(i, direction())
|
2012-07-28 00:47:59 +00:00
|
|
|
|
2012-06-09 18:25:10 +00:00
|
|
|
exports.addTask = (e, el, next) ->
|
|
|
|
|
type = $(el).attr('data-task-type')
|
|
|
|
|
list = model.at "_#{type}List"
|
|
|
|
|
newModel = model.at('_new' + type.charAt(0).toUpperCase() + type.slice(1))
|
2013-01-28 02:36:34 +00:00
|
|
|
text = newModel.get()
|
2012-04-27 17:04:44 +00:00
|
|
|
# Don't add a blank todo
|
2013-01-28 02:36:34 +00:00
|
|
|
return if /^(\s)*$/.test(text)
|
|
|
|
|
|
2012-06-09 18:25:10 +00:00
|
|
|
newModel.set ''
|
|
|
|
|
switch type
|
2012-06-20 21:43:23 +00:00
|
|
|
|
2012-06-09 18:25:10 +00:00
|
|
|
when 'habit'
|
2012-06-26 15:02:29 +00:00
|
|
|
list.push {type: type, text: text, notes: '', value: 0, up: true, down: true}
|
2012-06-20 21:43:23 +00:00
|
|
|
|
2012-06-09 18:25:10 +00:00
|
|
|
when 'reward'
|
2012-06-26 15:02:29 +00:00
|
|
|
list.push {type: type, text: text, notes: '', value: 20 }
|
2012-06-20 21:43:23 +00:00
|
|
|
|
2012-09-05 02:09:52 +00:00
|
|
|
when 'daily'
|
|
|
|
|
list.push {type: type, text: text, notes: '', value: 0, repeat:{su:true,m:true,t:true,w:true,th:true,f:true,s:true}, completed: false }
|
|
|
|
|
|
|
|
|
|
when 'todo'
|
2012-06-26 15:02:29 +00:00
|
|
|
list.push {type: type, text: text, notes: '', value: 0, completed: false }
|
2012-06-25 22:26:12 +00:00
|
|
|
|
|
|
|
|
# list.on 'set', '*.completed', (i, completed, previous, isLocal) ->
|
|
|
|
|
# # Move the item to the bottom if it was checked off
|
|
|
|
|
# list.move i, -1 if completed && isLocal
|
2012-04-27 17:04:44 +00:00
|
|
|
|
2012-07-07 02:09:51 +00:00
|
|
|
exports.del = (e, el) ->
|
2012-04-27 17:04:44 +00:00
|
|
|
# Derby extends model.at to support creation from DOM nodes
|
2013-01-29 19:09:04 +00:00
|
|
|
#task = model.at(e.target)
|
|
|
|
|
# FIXME normally that would work, and we'd later simply call `user.del task` (instead of that 4-liner down there)
|
|
|
|
|
# however, see https://github.com/lefnire/habitrpg/pull/226#discussion_r2810391
|
|
|
|
|
|
|
|
|
|
id = $(e.target).parents('li.task').attr('data-id')
|
|
|
|
|
return unless id?
|
|
|
|
|
|
|
|
|
|
task = user.at "tasks.#{id}"
|
|
|
|
|
type = task.get('type')
|
|
|
|
|
|
2012-09-01 23:10:51 +00:00
|
|
|
history = task.get('history')
|
2012-09-04 21:10:36 +00:00
|
|
|
if history and history.length>2
|
|
|
|
|
# prevent delete-and-recreate hack on red tasks
|
|
|
|
|
if task.get('value') < 0
|
|
|
|
|
result = confirm("Are you sure? Deleting this task will hurt you (to prevent deleting, then re-creating red tasks).")
|
|
|
|
|
if result != true
|
|
|
|
|
return # Cancel. Don't delete, don't hurt user
|
|
|
|
|
else
|
|
|
|
|
task.set('type','habit') # hack to make sure it hits HP, instead of performing "undo checkbox"
|
2013-01-29 19:09:04 +00:00
|
|
|
scoring.score(id, direction:'down')
|
2012-09-04 21:10:36 +00:00
|
|
|
|
|
|
|
|
# prevent accidently deleting long-standing tasks
|
2012-09-01 23:10:51 +00:00
|
|
|
else
|
2012-09-04 21:10:36 +00:00
|
|
|
result = confirm("Are you sure you want to delete this task?")
|
|
|
|
|
return if result != true
|
2012-09-01 23:10:51 +00:00
|
|
|
|
2012-07-07 02:09:51 +00:00
|
|
|
#TODO bug where I have to delete from _users.tasks AND _{type}List,
|
|
|
|
|
# fix when query subscriptions implemented properly
|
2012-09-04 21:10:36 +00:00
|
|
|
$('[rel=tooltip]').tooltip('hide')
|
2013-01-29 19:09:04 +00:00
|
|
|
|
|
|
|
|
ids = user.get("#{type}Ids")
|
|
|
|
|
ids.splice(ids.indexOf(id),1)
|
|
|
|
|
user.del('tasks.'+id)
|
|
|
|
|
user.set("#{type}Ids", ids)
|
|
|
|
|
|
2012-06-25 01:51:13 +00:00
|
|
|
|
2012-07-28 04:01:58 +00:00
|
|
|
exports.clearCompleted = (e, el) ->
|
2013-01-26 10:33:51 +00:00
|
|
|
todoIds = user.get('todoIds')
|
|
|
|
|
removed = false
|
|
|
|
|
_.each model.get('_todoList'), (task) ->
|
|
|
|
|
if task.completed
|
|
|
|
|
removed = true
|
|
|
|
|
user.del('tasks.'+task.id)
|
|
|
|
|
todoIds.splice(todoIds.indexOf(task.id), 1)
|
|
|
|
|
if removed
|
|
|
|
|
user.set('todoIds', todoIds)
|
2012-09-05 02:09:52 +00:00
|
|
|
|
|
|
|
|
exports.toggleDay = (e, el) ->
|
|
|
|
|
task = model.at(e.target)
|
|
|
|
|
if /active/.test($(el).attr('class')) # previous state, not current
|
|
|
|
|
task.set('repeat.' + $(el).attr('data-day'), false)
|
|
|
|
|
else
|
|
|
|
|
task.set('repeat.' + $(el).attr('data-day'), true)
|
2012-07-28 04:01:58 +00:00
|
|
|
|
2012-06-29 13:45:50 +00:00
|
|
|
exports.toggleTaskEdit = (e, el) ->
|
2012-07-17 20:35:26 +00:00
|
|
|
hideId = $(el).attr('data-hide-id')
|
|
|
|
|
toggleId = $(el).attr('data-toggle-id')
|
|
|
|
|
$(document.getElementById(hideId)).hide()
|
|
|
|
|
$(document.getElementById(toggleId)).toggle()
|
2012-06-29 08:33:09 +00:00
|
|
|
|
2012-07-07 02:46:22 +00:00
|
|
|
exports.toggleChart = (e, el) ->
|
2012-07-17 20:35:26 +00:00
|
|
|
hideSelector = $(el).attr('data-hide-id')
|
|
|
|
|
chartSelector = $(el).attr('data-toggle-id')
|
2012-07-07 02:46:22 +00:00
|
|
|
historyPath = $(el).attr('data-history-path')
|
|
|
|
|
$(document.getElementById(hideSelector)).hide()
|
|
|
|
|
$(document.getElementById(chartSelector)).toggle()
|
2012-06-29 08:33:09 +00:00
|
|
|
|
|
|
|
|
matrix = [['Date', 'Score']]
|
2012-07-07 02:46:22 +00:00
|
|
|
for obj in model.get(historyPath)
|
2013-01-29 02:28:45 +00:00
|
|
|
date = +new Date(obj.date)
|
2012-10-11 16:52:40 +00:00
|
|
|
readableDate = moment(date).format('MM/DD')
|
2012-06-29 08:51:50 +00:00
|
|
|
matrix.push [ readableDate, obj.value ]
|
2012-06-29 08:33:09 +00:00
|
|
|
data = google.visualization.arrayToDataTable matrix
|
2012-06-29 08:44:52 +00:00
|
|
|
|
2012-06-29 08:33:09 +00:00
|
|
|
options = {
|
|
|
|
|
title: 'History'
|
2012-06-29 08:44:52 +00:00
|
|
|
#TODO use current background color: $(el).css('background-color), but convert to hex (see http://goo.gl/ql5pR)
|
|
|
|
|
backgroundColor: 'whiteSmoke'
|
2012-06-29 08:33:09 +00:00
|
|
|
}
|
|
|
|
|
|
2012-07-07 02:46:22 +00:00
|
|
|
chart = new google.visualization.LineChart(document.getElementById( chartSelector ))
|
2012-06-29 08:33:09 +00:00
|
|
|
chart.draw(data, options)
|
2012-06-29 13:45:50 +00:00
|
|
|
|
2012-07-08 22:58:11 +00:00
|
|
|
exports.buyItem = (e, el, next) ->
|
|
|
|
|
user = model.at '_user'
|
2012-07-09 01:20:30 +00:00
|
|
|
#TODO: this should be working but it's not. so instead, i'm passing all needed values as data-attrs
|
|
|
|
|
# item = model.at(e.target)
|
|
|
|
|
|
2012-07-08 22:58:11 +00:00
|
|
|
money = user.get 'stats.money'
|
2012-07-09 01:20:30 +00:00
|
|
|
[type, value, index] = [ $(el).attr('data-type'), $(el).attr('data-value'), $(el).attr('data-index') ]
|
2012-07-08 22:58:11 +00:00
|
|
|
|
2012-07-09 01:20:30 +00:00
|
|
|
return if money < value
|
2012-07-08 22:58:11 +00:00
|
|
|
user.set 'stats.money', money - value
|
|
|
|
|
if type == 'armor'
|
2012-07-09 01:20:30 +00:00
|
|
|
user.set 'items.armor', index
|
2013-01-30 18:03:10 +00:00
|
|
|
model.set '_view.items.armor', content.items.armor[parseInt(index) + 1]
|
2012-07-08 22:58:11 +00:00
|
|
|
else if type == 'weapon'
|
2012-07-09 01:20:30 +00:00
|
|
|
user.set 'items.weapon', index
|
2013-01-30 18:03:10 +00:00
|
|
|
model.set '_view.items.weapon', content.items.weapon[parseInt(index) + 1]
|
2012-07-08 22:58:11 +00:00
|
|
|
else if type == 'potion'
|
|
|
|
|
hp = user.get 'stats.hp'
|
|
|
|
|
hp += 15
|
|
|
|
|
hp = 50 if hp > 50
|
|
|
|
|
user.set 'stats.hp', hp
|
2012-09-06 19:33:06 +00:00
|
|
|
|
2012-09-24 02:01:41 +00:00
|
|
|
exports.score = (e, el, next) ->
|
2012-06-10 00:41:21 +00:00
|
|
|
direction = $(el).attr('data-direction')
|
2012-06-26 14:55:24 +00:00
|
|
|
direction = 'up' if direction == 'true/'
|
|
|
|
|
direction = 'down' if direction == 'false/'
|
2012-06-20 20:40:59 +00:00
|
|
|
task = model.at $(el).parents('li')[0]
|
2013-01-21 17:06:12 +00:00
|
|
|
scoring.score(task.get('id'), direction)
|
2013-01-21 16:48:18 +00:00
|
|
|
|
2013-01-21 21:42:23 +00:00
|
|
|
revive = (userObj, animateHp = false) ->
|
2013-01-21 16:48:18 +00:00
|
|
|
# Reset stats
|
2013-01-21 21:42:23 +00:00
|
|
|
userObj.stats.hp = 50 unless animateHp # if we're animating hp-reset, we'll set to 50 ourselves later in our functions
|
|
|
|
|
userObj.stats.lvl = 1; userObj.stats.money = 0; userObj.stats.exp = 0
|
2013-01-21 16:48:18 +00:00
|
|
|
|
|
|
|
|
# Reset items
|
|
|
|
|
userObj.items.armor = 0; userObj.items.weapon = 0
|
|
|
|
|
|
|
|
|
|
# Reset item store
|
|
|
|
|
model.set '_view.items.armor', content.items.armor[1]
|
|
|
|
|
model.set '_view.items.weapon', content.items.weapon[1]
|
2013-01-21 17:06:12 +00:00
|
|
|
|
|
|
|
|
exports.revive = (e, el) ->
|
|
|
|
|
userObj = user.get()
|
2013-01-21 21:42:23 +00:00
|
|
|
revive(userObj, true)
|
|
|
|
|
|
|
|
|
|
user.set 'stats', userObj.stats
|
|
|
|
|
user.set 'items', userObj.items
|
|
|
|
|
# Re-render (since we replaced objects en-masse, see https://github.com/lefnire/habitrpg/issues/80)
|
|
|
|
|
resetDom(model)
|
|
|
|
|
setTimeout (-> user.set 'stats.hp', 50), 0 # animate hp loss
|
2012-10-25 01:22:32 +00:00
|
|
|
|
|
|
|
|
exports.reset = (e, el) ->
|
2013-01-21 17:06:12 +00:00
|
|
|
userObj = user.get()
|
2013-01-26 10:33:51 +00:00
|
|
|
taskTypes = ['habit', 'daily', 'todo', 'reward']
|
2013-01-21 17:06:12 +00:00
|
|
|
userObj.tasks = {}
|
|
|
|
|
_.each taskTypes, (type) -> userObj["#{type}Ids"] = []
|
|
|
|
|
userObj.balance = 2 if userObj.balance < 2 #only if they haven't manually bought tokens
|
2013-01-21 21:42:23 +00:00
|
|
|
revive(userObj, true)
|
2013-01-21 17:06:12 +00:00
|
|
|
|
|
|
|
|
# Set new user
|
2013-01-21 21:42:23 +00:00
|
|
|
model.set "users.#{userObj.id}", userObj
|
|
|
|
|
resetDom(model)
|
|
|
|
|
setTimeout (-> user.set 'stats.hp', 50), 0 # animate hp loss
|
2012-10-25 01:22:32 +00:00
|
|
|
|
2013-01-11 03:06:53 +00:00
|
|
|
exports.closeKickstarterNofitication = (e, el) ->
|
2013-01-30 18:25:10 +00:00
|
|
|
user.set('notifications.kickstarter', 'hide')
|
|
|
|
|
|
|
|
|
|
exports.setMale = -> user.set('preferences.gender', 'm')
|
2013-01-30 18:29:59 +00:00
|
|
|
exports.setFemale = -> user.set('preferences.gender', 'f')
|
|
|
|
|
exports.setArmorsetV1 = -> user.set('preferences.armorSet', 'v1')
|
2013-01-30 21:52:31 +00:00
|
|
|
exports.setArmorsetV2 = -> user.set('preferences.armorSet', 'v2')
|
|
|
|
|
|
|
|
|
|
exports.addFriend = ->
|
2013-01-30 22:29:35 +00:00
|
|
|
friendId = model.get('_newFriend').replace(/[\s"]/g, '')
|
|
|
|
|
return if _.isEmpty(friendId)
|
2013-01-30 23:04:02 +00:00
|
|
|
if user.get('friends').indexOf(friendId) != -1
|
|
|
|
|
model.set "_view.addFriendError", "#{friendId} already in party."
|
|
|
|
|
return
|
2013-01-30 21:52:31 +00:00
|
|
|
query = model.query('users').friends([friendId])
|
|
|
|
|
model.fetch query, (err, users) ->
|
|
|
|
|
friend = users.get(0)
|
2013-01-30 23:04:02 +00:00
|
|
|
if friend.id?
|
2013-01-30 22:29:35 +00:00
|
|
|
#TODO ensure unique
|
|
|
|
|
user.push('friends', friendId)
|
|
|
|
|
$('#add-friend-modal').modal('hide')
|
|
|
|
|
window.location.reload() #TODO break old subscript, setup new, then remove reload
|
|
|
|
|
model.set '_newFriend', ''
|
|
|
|
|
else
|
|
|
|
|
model.set "_view.addFriendError", "User with id #{friendId} not found."
|