2014-11-28 20:49:41 -05:00
|
|
|
CocoView = require 'views/core/CocoView'
|
2014-11-25 13:19:38 -05:00
|
|
|
template = require 'templates/account/account-settings-view'
|
2014-11-28 20:49:41 -05:00
|
|
|
{me} = require 'core/auth'
|
|
|
|
forms = require 'core/forms'
|
2014-06-30 22:16:26 -04:00
|
|
|
User = require 'models/User'
|
2014-11-29 11:54:08 -05:00
|
|
|
AuthModal = require 'views/core/AuthModal'
|
2015-02-19 16:14:34 -05:00
|
|
|
ConfirmModal = require 'views/editor/modal/ConfirmModal'
|
|
|
|
{logoutUser, me} = require('core/auth')
|
2014-01-03 13:32:13 -05:00
|
|
|
|
2014-11-25 15:43:17 -05:00
|
|
|
module.exports = class AccountSettingsView extends CocoView
|
2014-01-03 17:28:00 -05:00
|
|
|
id: 'account-settings-view'
|
2014-01-03 13:32:13 -05:00
|
|
|
template: template
|
2014-11-25 15:43:17 -05:00
|
|
|
className: 'countainer-fluid'
|
2014-01-03 13:32:13 -05:00
|
|
|
|
|
|
|
events:
|
2015-10-21 17:02:04 -04:00
|
|
|
'change .panel input': 'onChangePanelInput'
|
|
|
|
'change #name-input': 'onChangeNameInput'
|
|
|
|
'click #toggle-all-btn': 'onClickToggleAllButton'
|
|
|
|
'click #profile-photo-panel-body': 'onClickProfilePhotoPanelBody'
|
|
|
|
'click #delete-account-btn': 'onClickDeleteAccountButton'
|
2015-02-27 19:07:41 -05:00
|
|
|
|
2014-01-03 13:32:13 -05:00
|
|
|
constructor: (options) ->
|
|
|
|
super options
|
2014-11-28 20:49:41 -05:00
|
|
|
require('core/services/filepicker')() unless window.application.isIPadApp # Initialize if needed
|
2014-11-25 13:19:38 -05:00
|
|
|
@uploadFilePath = "db/user/#{me.id}"
|
2014-07-10 14:50:16 -04:00
|
|
|
|
2014-11-25 13:19:38 -05:00
|
|
|
afterInsert: ->
|
|
|
|
super()
|
|
|
|
@openModalView new AuthModal() if me.get('anonymous')
|
2014-07-10 14:50:16 -04:00
|
|
|
|
2015-10-21 20:09:49 -04:00
|
|
|
getEmailSubsDict: ->
|
|
|
|
subs = {}
|
|
|
|
return subs unless me
|
|
|
|
subs[sub] = 1 for sub in me.getEnabledEmails()
|
|
|
|
return subs
|
2015-02-27 19:07:41 -05:00
|
|
|
|
2014-11-25 13:19:38 -05:00
|
|
|
#- Form input callbacks
|
2015-10-21 17:02:04 -04:00
|
|
|
onChangePanelInput: (e) ->
|
2014-11-25 13:19:38 -05:00
|
|
|
$(e.target).addClass 'changed'
|
2015-10-16 18:02:33 -04:00
|
|
|
if (JSON.stringify(document.getElementById('email1').className)).indexOf("changed") > -1 or (JSON.stringify(document.getElementById('password1').className)).indexOf("changed") > -1
|
2015-02-19 16:14:34 -05:00
|
|
|
$(e.target).removeClass 'changed'
|
2015-02-27 19:07:41 -05:00
|
|
|
else
|
2015-02-19 16:14:34 -05:00
|
|
|
@trigger 'input-changed'
|
2014-07-10 14:50:16 -04:00
|
|
|
|
2015-10-21 17:02:04 -04:00
|
|
|
onClickToggleAllButton: ->
|
2014-11-25 13:19:38 -05:00
|
|
|
subs = @getSubscriptions()
|
|
|
|
$('#email-panel input[type="checkbox"]', @$el).prop('checked', not _.any(_.values(subs))).addClass('changed')
|
2015-02-24 06:55:18 -05:00
|
|
|
@trigger 'input-changed'
|
2014-07-10 14:50:16 -04:00
|
|
|
|
2015-10-21 17:02:04 -04:00
|
|
|
onChangeNameInput: ->
|
|
|
|
name = $('#name-input', @$el).val()
|
2014-07-10 14:50:16 -04:00
|
|
|
return if name is me.get 'name'
|
|
|
|
User.getUnconflictedName name, (newName) =>
|
|
|
|
forms.clearFormAlerts(@$el)
|
|
|
|
if name is newName
|
|
|
|
@suggestedName = undefined
|
|
|
|
else
|
|
|
|
@suggestedName = newName
|
|
|
|
forms.setErrorToProperty @$el, 'name', "That name is taken! How about #{newName}?", true
|
2014-01-03 13:32:13 -05:00
|
|
|
|
2014-11-25 13:19:38 -05:00
|
|
|
onPictureChanged: (e) =>
|
|
|
|
@trigger 'inputChanged', e
|
|
|
|
@$el.find('.gravatar-fallback').toggle not me.get 'photoURL'
|
2014-01-03 13:32:13 -05:00
|
|
|
|
2015-02-27 19:07:41 -05:00
|
|
|
|
2014-11-25 13:19:38 -05:00
|
|
|
#- Just copied from OptionsView, TODO refactor
|
2015-10-21 17:02:04 -04:00
|
|
|
onClickDeleteAccountButton: ->
|
2015-02-19 16:14:34 -05:00
|
|
|
forms.clearFormAlerts(@$el)
|
2015-10-16 18:02:33 -04:00
|
|
|
myEmail = me.get 'email'
|
2015-02-19 16:14:34 -05:00
|
|
|
email1 = document.getElementById('email1').value
|
2015-06-20 10:03:37 -04:00
|
|
|
password1 = document.getElementById('password1').value
|
2015-02-19 16:14:34 -05:00
|
|
|
if Boolean(email1) and email1 is myEmail
|
2015-06-20 10:03:37 -04:00
|
|
|
isPasswordCorrect = false
|
|
|
|
toBeDelayed = true
|
|
|
|
$.ajax
|
|
|
|
url: '/auth/login'
|
|
|
|
type: 'POST'
|
|
|
|
data:
|
|
|
|
{
|
|
|
|
username: email1,
|
|
|
|
password: password1
|
|
|
|
}
|
|
|
|
parse: true
|
|
|
|
error: (error) ->
|
|
|
|
toBeDelayed = false
|
|
|
|
'Bad Error. Can\'t connect to server or something. ' + error
|
|
|
|
success: (response, textStatus, jqXHR) ->
|
|
|
|
toBeDelayed = false
|
|
|
|
unless jqXHR.status is 200
|
|
|
|
return
|
|
|
|
isPasswordCorrect = true
|
2015-06-20 13:09:44 -04:00
|
|
|
callback = =>
|
2015-06-20 10:03:37 -04:00
|
|
|
if toBeDelayed
|
2015-06-20 13:09:44 -04:00
|
|
|
setTimeout callback, 100
|
2015-06-20 10:03:37 -04:00
|
|
|
else
|
|
|
|
if isPasswordCorrect
|
|
|
|
renderData =
|
|
|
|
'confirmTitle': 'Are you really sure?'
|
|
|
|
'confirmBody': 'This will completely delete your account. This action CANNOT be undone. Are you entirely sure?'
|
|
|
|
'confirmDecline': 'Not really'
|
|
|
|
'confirmConfirm': 'Definitely'
|
|
|
|
confirmModal = new ConfirmModal renderData
|
2015-06-20 13:09:44 -04:00
|
|
|
confirmModal.on 'confirm', @deleteAccount
|
|
|
|
@openModalView confirmModal
|
2015-06-20 10:03:37 -04:00
|
|
|
else
|
|
|
|
message = $.i18n.t('account_settings.wrong_password', defaultValue: 'Wrong Password.')
|
|
|
|
err = [message: message, property: 'password1', formatted: true]
|
2015-06-20 13:09:44 -04:00
|
|
|
forms.applyErrorsToForm(@$el, err)
|
2015-10-16 18:02:33 -04:00
|
|
|
$('.nano').nanoScroller({scrollTo: @$el.find('.has-error')})
|
2015-06-20 13:09:44 -04:00
|
|
|
setTimeout callback, 100
|
2015-02-19 16:14:34 -05:00
|
|
|
else
|
|
|
|
message = $.i18n.t('account_settings.wrong_email', defaultValue: 'Wrong Email.')
|
|
|
|
err = [message: message, property: 'email1', formatted: true]
|
|
|
|
forms.applyErrorsToForm(@$el, err)
|
|
|
|
$('.nano').nanoScroller({scrollTo: @$el.find('.has-error')})
|
|
|
|
|
2015-06-20 10:03:37 -04:00
|
|
|
|
2015-02-19 16:14:34 -05:00
|
|
|
deleteAccount: ->
|
|
|
|
myID = me.id
|
|
|
|
$.ajax
|
|
|
|
type: 'DELETE'
|
|
|
|
success: ->
|
|
|
|
noty
|
|
|
|
timeout: 5000
|
|
|
|
text: 'Your account is gone.'
|
|
|
|
type: 'success'
|
|
|
|
layout: 'topCenter'
|
|
|
|
_.delay ->
|
2015-10-16 18:02:33 -04:00
|
|
|
window?.webkit?.messageHandlers?.notification?.postMessage(name: "signOut") if window.application.isIPadApp
|
2015-02-19 16:14:34 -05:00
|
|
|
Backbone.Mediator.publish("auth:logging-out", {})
|
2015-02-27 19:07:41 -05:00
|
|
|
window.tracker?.trackEvent 'Log Out', category:'Homepage' if @id is 'home-view'
|
2015-02-19 16:14:34 -05:00
|
|
|
logoutUser($('#login-email').val())
|
|
|
|
, 500
|
|
|
|
error: (jqXHR, status, error) ->
|
|
|
|
console.error jqXHR
|
|
|
|
timeout: 5000
|
|
|
|
text: "Deleting account failed with error code #{jqXHR.status}"
|
|
|
|
type: 'error'
|
|
|
|
layout: 'topCenter'
|
|
|
|
url: "/db/user/#{myID}"
|
|
|
|
|
2015-10-21 17:02:04 -04:00
|
|
|
onClickProfilePhotoPanelBody: (e) ->
|
2014-11-25 13:19:38 -05:00
|
|
|
return if window.application.isIPadApp # TODO: have an iPad-native way of uploading a photo, since we don't want to load FilePicker on iPad (memory)
|
|
|
|
photoContainer = @$el.find('.profile-photo')
|
|
|
|
onSaving = =>
|
|
|
|
photoContainer.addClass('saving')
|
|
|
|
onSaved = (uploadingPath) =>
|
|
|
|
@$el.find('#photoURL').val(uploadingPath)
|
2015-02-05 11:56:51 -05:00
|
|
|
@$el.find('#photoURL').trigger('change') # cause for some reason editing the value doesn't trigger the jquery event
|
2014-11-25 13:19:38 -05:00
|
|
|
me.set('photoURL', uploadingPath)
|
|
|
|
photoContainer.removeClass('saving').attr('src', me.getPhotoURL(photoContainer.width()))
|
|
|
|
filepicker.pick {mimetypes: 'image/*'}, @onImageChosen(onSaving, onSaved)
|
|
|
|
|
|
|
|
formatImagePostData: (inkBlob) ->
|
|
|
|
url: inkBlob.url, filename: inkBlob.filename, mimetype: inkBlob.mimetype, path: @uploadFilePath, force: true
|
|
|
|
|
|
|
|
onImageChosen: (onSaving, onSaved) ->
|
|
|
|
(inkBlob) =>
|
|
|
|
onSaving()
|
|
|
|
uploadingPath = [@uploadFilePath, inkBlob.filename].join('/')
|
|
|
|
data = @formatImagePostData(inkBlob)
|
|
|
|
success = @onImageUploaded(onSaved, uploadingPath)
|
|
|
|
$.ajax '/file', type: 'POST', data: data, success: success
|
|
|
|
|
|
|
|
onImageUploaded: (onSaved, uploadingPath) ->
|
|
|
|
(e) =>
|
|
|
|
onSaved uploadingPath
|
2015-02-27 19:07:41 -05:00
|
|
|
|
|
|
|
|
2014-11-25 13:19:38 -05:00
|
|
|
#- Misc
|
2014-01-03 13:32:13 -05:00
|
|
|
|
|
|
|
getSubscriptions: ->
|
2014-11-25 13:19:38 -05:00
|
|
|
inputs = ($(i) for i in $('#email-panel input[type="checkbox"].changed', @$el))
|
2014-04-21 19:15:23 -04:00
|
|
|
emailNames = (i.attr('name').replace('email_', '') for i in inputs)
|
|
|
|
enableds = (i.prop('checked') for i in inputs)
|
|
|
|
_.zipObject emailNames, enableds
|
2014-01-03 13:32:13 -05:00
|
|
|
|
2015-02-27 19:07:41 -05:00
|
|
|
|
2014-11-25 13:19:38 -05:00
|
|
|
#- Saving changes
|
2015-02-27 19:07:41 -05:00
|
|
|
|
2014-11-25 15:43:17 -05:00
|
|
|
save: ->
|
2014-07-16 08:39:48 -04:00
|
|
|
$('#settings-tabs input').removeClass 'changed'
|
2014-01-03 13:32:13 -05:00
|
|
|
forms.clearFormAlerts(@$el)
|
|
|
|
@grabData()
|
|
|
|
res = me.validate()
|
|
|
|
if res?
|
2014-06-30 22:16:26 -04:00
|
|
|
console.error 'Couldn\'t save because of validation errors:', res
|
2014-01-03 13:32:13 -05:00
|
|
|
forms.applyErrorsToForm(@$el, res)
|
2014-11-25 13:19:38 -05:00
|
|
|
$('.nano').nanoScroller({scrollTo: @$el.find('.has-error')})
|
2014-01-03 13:32:13 -05:00
|
|
|
return
|
2014-03-10 16:20:00 -04:00
|
|
|
|
2014-02-27 15:02:08 -05:00
|
|
|
return unless me.hasLocalChanges()
|
2014-01-03 13:32:13 -05:00
|
|
|
|
2014-06-10 23:43:25 -04:00
|
|
|
res = me.patch()
|
2014-01-03 13:32:13 -05:00
|
|
|
return unless res
|
|
|
|
|
2014-11-25 15:43:17 -05:00
|
|
|
res.error =>
|
2014-01-03 13:32:13 -05:00
|
|
|
errors = JSON.parse(res.responseText)
|
|
|
|
forms.applyErrorsToForm(@$el, errors)
|
2014-11-25 13:19:38 -05:00
|
|
|
$('.nano').nanoScroller({scrollTo: @$el.find('.has-error')})
|
2014-11-25 15:43:17 -05:00
|
|
|
@trigger 'save-user-error'
|
2014-07-10 14:50:16 -04:00
|
|
|
res.success (model, response, options) =>
|
2014-11-25 15:43:17 -05:00
|
|
|
@trigger 'save-user-success'
|
|
|
|
|
|
|
|
@trigger 'save-user-began'
|
2014-01-03 13:32:13 -05:00
|
|
|
|
|
|
|
grabData: ->
|
|
|
|
@grabPasswordData()
|
|
|
|
@grabOtherData()
|
|
|
|
|
|
|
|
grabPasswordData: ->
|
|
|
|
password1 = $('#password', @$el).val()
|
|
|
|
password2 = $('#password2', @$el).val()
|
|
|
|
bothThere = Boolean(password1) and Boolean(password2)
|
|
|
|
if bothThere and password1 isnt password2
|
|
|
|
message = $.i18n.t('account_settings.password_mismatch', defaultValue: 'Password does not match.')
|
2014-06-30 22:16:26 -04:00
|
|
|
err = [message: message, property: 'password2', formatted: true]
|
2014-01-03 13:32:13 -05:00
|
|
|
forms.applyErrorsToForm(@$el, err)
|
2014-11-25 13:19:38 -05:00
|
|
|
$('.nano').nanoScroller({scrollTo: @$el.find('.has-error')})
|
2014-01-03 13:32:13 -05:00
|
|
|
return
|
|
|
|
if bothThere
|
|
|
|
me.set('password', password1)
|
2014-07-16 08:39:48 -04:00
|
|
|
else if password1
|
|
|
|
message = $.i18n.t('account_settings.password_repeat', defaultValue: 'Please repeat your password.')
|
|
|
|
err = [message: message, property: 'password2', formatted: true]
|
|
|
|
forms.applyErrorsToForm(@$el, err)
|
2014-11-25 13:19:38 -05:00
|
|
|
$('.nano').nanoScroller({scrollTo: @$el.find('.has-error')})
|
2014-01-03 13:32:13 -05:00
|
|
|
|
|
|
|
grabOtherData: ->
|
2015-10-21 17:02:04 -04:00
|
|
|
@$el.find('#name-input').val @suggestedName if @suggestedName
|
|
|
|
me.set 'name', @$el.find('#name-input').val()
|
2014-11-25 13:19:38 -05:00
|
|
|
me.set 'email', @$el.find('#email').val()
|
2014-04-21 19:15:23 -04:00
|
|
|
for emailName, enabled of @getSubscriptions()
|
2014-05-31 01:12:44 -04:00
|
|
|
me.setEmailSubscription emailName, enabled
|
2014-11-25 13:19:38 -05:00
|
|
|
|
|
|
|
me.set('photoURL', @$el.find('#photoURL').val())
|
2014-01-03 17:28:00 -05:00
|
|
|
|
2015-02-12 14:42:05 -05:00
|
|
|
permissions = []
|
|
|
|
|
2014-01-03 17:28:00 -05:00
|
|
|
adminCheckbox = @$el.find('#admin')
|
|
|
|
if adminCheckbox.length
|
|
|
|
permissions.push 'admin' if adminCheckbox.prop('checked')
|
2015-02-12 14:42:05 -05:00
|
|
|
|
|
|
|
godmodeCheckbox = @$el.find('#godmode')
|
|
|
|
if godmodeCheckbox.length
|
|
|
|
permissions.push 'godmode' if godmodeCheckbox.prop('checked')
|
|
|
|
|
|
|
|
me.set('permissions', permissions)
|