Publish Vulpes Preview 15 sources for desktop, Android and Tundra
Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
This commit is contained in:
parent
93e3a48004
commit
b38dea0597
25901 changed files with 9982925 additions and 369 deletions
413
gaia/apps/calendar/js/views/modify_account.js
Executable file
413
gaia/apps/calendar/js/views/modify_account.js
Executable file
|
|
@ -0,0 +1,413 @@
|
|||
define(function(require, exports, module) {
|
||||
'use strict';
|
||||
|
||||
var Account = require('models/account');
|
||||
var OAuthWindow = require('oauth_window');
|
||||
var Presets = require('common/presets');
|
||||
var URI = require('utils/uri');
|
||||
var View = require('view');
|
||||
var co = require('ext/co');
|
||||
var core = require('core');
|
||||
var isOffline = require('common/is_offline');
|
||||
var router = require('router');
|
||||
|
||||
require('dom!modify-account-view');
|
||||
|
||||
var DEFAULT_AUTH_TYPE = 'basic';
|
||||
var OAUTH_AUTH_CREDENTIALS = [
|
||||
'client_id',
|
||||
'scope',
|
||||
'redirect_uri',
|
||||
'state'
|
||||
];
|
||||
|
||||
function ModifyAccount(options) {
|
||||
View.apply(this, arguments);
|
||||
|
||||
this.deleteRecord = this.deleteRecord.bind(this);
|
||||
this.cancel = this.cancel.bind(this);
|
||||
this.displayOAuth2 = this.displayOAuth2.bind(this);
|
||||
this.hideHeaderAndForm = this.hideHeaderAndForm.bind(this);
|
||||
this.cancelDelete = this.cancelDelete.bind(this);
|
||||
|
||||
// bound so we can add remove listeners
|
||||
this._boundSaveUpdateModel = this.save.bind(this, { updateModel: true });
|
||||
}
|
||||
module.exports = ModifyAccount;
|
||||
|
||||
ModifyAccount.prototype = {
|
||||
__proto__: View.prototype,
|
||||
|
||||
_changeToken: 0,
|
||||
|
||||
selectors: {
|
||||
element: '#modify-account-view',
|
||||
form: '.modify-account-form',
|
||||
fields: '*[name]',
|
||||
saveButton: '#modify-account-view .save',
|
||||
deleteButton: '#modify-account-view .delete-confirm',
|
||||
deleteRecordButton: '.delete-record',
|
||||
cancelDeleteButton: '#modify-account-view .delete-cancel',
|
||||
header: '#modify-account-header',
|
||||
status: '#modify-account-view section[role="status"]',
|
||||
errors: '#modify-account-view .errors',
|
||||
oauth2Window: '#oauth2',
|
||||
oauth2SignIn: '#modify-account-view .force-oauth2'
|
||||
},
|
||||
|
||||
progressClass: 'in-progress',
|
||||
removeDialogClass: 'remove-dialog',
|
||||
|
||||
get authenticationType() {
|
||||
if (this.preset && this.preset.authenticationType) {
|
||||
return this.preset.authenticationType;
|
||||
}
|
||||
|
||||
return DEFAULT_AUTH_TYPE;
|
||||
},
|
||||
|
||||
get oauth2Window() {
|
||||
return this._findElement('oauth2Window');
|
||||
},
|
||||
|
||||
get oauth2SignIn() {
|
||||
return this._findElement('oauth2SignIn');
|
||||
},
|
||||
|
||||
get deleteRecordButton() {
|
||||
return this._findElement('deleteRecordButton');
|
||||
},
|
||||
|
||||
get deleteButton() {
|
||||
return this._findElement('deleteButton');
|
||||
},
|
||||
|
||||
get cancelDeleteButton() {
|
||||
return this._findElement('cancelDeleteButton');
|
||||
},
|
||||
|
||||
get header() {
|
||||
return this._findElement('header');
|
||||
},
|
||||
|
||||
get saveButton() {
|
||||
return this._findElement('saveButton');
|
||||
},
|
||||
|
||||
get form() {
|
||||
return this._findElement('form');
|
||||
},
|
||||
|
||||
get fields() {
|
||||
if (!this._fields) {
|
||||
var result = this._fields = {};
|
||||
var elements = this.element.querySelectorAll(
|
||||
this.selectors.fields
|
||||
);
|
||||
|
||||
var i = 0;
|
||||
var len = elements.length;
|
||||
|
||||
for (i; i < len; i++) {
|
||||
var el = elements[i];
|
||||
result[el.getAttribute('name')] = el;
|
||||
}
|
||||
}
|
||||
|
||||
return this._fields;
|
||||
},
|
||||
|
||||
updateForm: function() {
|
||||
var update = ['user', 'fullUrl'];
|
||||
|
||||
update.forEach(function(name) {
|
||||
var field = this.fields[name];
|
||||
field.value = this.model[name];
|
||||
}, this);
|
||||
},
|
||||
|
||||
updateModel: function() {
|
||||
var update = ['user', 'password', 'fullUrl'];
|
||||
|
||||
update.forEach(function(name) {
|
||||
var field = this.fields[name];
|
||||
var value = field.value;
|
||||
if (name === 'fullUrl') {
|
||||
// Prepend a scheme if url has neither port nor scheme
|
||||
var port = URI.getPort(value);
|
||||
var scheme = URI.getScheme(value);
|
||||
if (!port && !scheme) {
|
||||
value = 'https://' + value;
|
||||
}
|
||||
}
|
||||
|
||||
this.model[name] = value;
|
||||
}, this);
|
||||
},
|
||||
|
||||
deleteRecord: function(e) {
|
||||
if (e) {
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
// begin the removal (which will emit the preRemove event) but don't wait
|
||||
// for it to complete...
|
||||
core.bridge.deleteAccount(this.model._id);
|
||||
|
||||
// semi-hack clear the :target - harmless in tests
|
||||
// but important in the current UI because css :target
|
||||
// does not get cleared (for some reason)
|
||||
window.location.replace('#');
|
||||
|
||||
// TODO: in the future we may want to store the entry
|
||||
// url of this view and use that instead of this
|
||||
// hard coded value...
|
||||
router.show('/advanced-settings/');
|
||||
},
|
||||
|
||||
cancel: function(event) {
|
||||
if (event) {
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
window.history.back();
|
||||
},
|
||||
|
||||
cancelDelete: function(event) {
|
||||
this.element.classList.remove(this.removeDialogClass);
|
||||
this.cancel(event);
|
||||
},
|
||||
|
||||
isOffline: isOffline,
|
||||
|
||||
save: co.wrap(function *(options, e) {
|
||||
|
||||
if (e) {
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
var list = this.element.classList;
|
||||
|
||||
if (this.isOffline()) {
|
||||
this.showErrors([{name: 'offline'}]);
|
||||
return;
|
||||
}
|
||||
|
||||
list.add(this.progressClass);
|
||||
|
||||
this.errors.textContent = '';
|
||||
|
||||
if (options && options.updateModel) {
|
||||
this.updateModel();
|
||||
}
|
||||
|
||||
try {
|
||||
yield core.bridge.createAccount(this.model);
|
||||
list.remove(this.progressClass);
|
||||
router.go(this.completeUrl);
|
||||
} catch(err) {
|
||||
list.remove(this.progressClass);
|
||||
this.showErrors(err);
|
||||
}
|
||||
}),
|
||||
|
||||
hideHeaderAndForm: function() {
|
||||
this.element.classList.add(this.removeDialogClass);
|
||||
},
|
||||
|
||||
displayOAuth2: function(event) {
|
||||
if (event) {
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
var self = this;
|
||||
this.oauth2Window.classList.add(View.ACTIVE);
|
||||
|
||||
navigator.mozApps.getSelf().onsuccess = function(e) {
|
||||
var app = e.target.result;
|
||||
app.clearBrowserData().onsuccess = function() {
|
||||
self._redirectToOAuthFlow();
|
||||
};
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {String} preset name of value in Calendar.Presets.
|
||||
*/
|
||||
_createModel: function(preset, callback) {
|
||||
var settings = Presets[preset];
|
||||
var model = new Account(settings.options);
|
||||
model.preset = preset;
|
||||
return model;
|
||||
},
|
||||
|
||||
_redirectToOAuthFlow: function() {
|
||||
|
||||
var apiCredentials = this.preset.apiCredentials;
|
||||
var params = {
|
||||
/*
|
||||
* code response type for now might change when we can use window.open
|
||||
*/
|
||||
response_type: 'code',
|
||||
/* offline so we get refresh_token[s] */
|
||||
access_type: 'offline',
|
||||
/* we us force so we always get a refresh_token */
|
||||
approval_prompt: 'force'
|
||||
};
|
||||
|
||||
OAUTH_AUTH_CREDENTIALS.forEach(function(key) {
|
||||
if (key in apiCredentials) {
|
||||
params[key] = apiCredentials[key];
|
||||
}
|
||||
});
|
||||
|
||||
var oauth = this._oauthDialog = new OAuthWindow(
|
||||
this.oauth2Window,
|
||||
apiCredentials.authorizationUrl,
|
||||
params
|
||||
);
|
||||
|
||||
var self = this;
|
||||
|
||||
oauth.open();
|
||||
oauth.onabort = function() {
|
||||
self.cancel();
|
||||
};
|
||||
|
||||
oauth.oncomplete = function(params) {
|
||||
if ('error' in params) {
|
||||
// Ruh roh
|
||||
return self.cancel();
|
||||
}
|
||||
|
||||
if (!params.code) {
|
||||
return console.error('authentication error');
|
||||
}
|
||||
|
||||
// Fistpump!
|
||||
self.model.oauth = { code: params.code };
|
||||
self.save();
|
||||
};
|
||||
},
|
||||
|
||||
render: function() {
|
||||
if (!this.model) {
|
||||
throw new Error('must provider model to ModifyAccount');
|
||||
}
|
||||
|
||||
this.form.addEventListener('submit', this._boundSaveUpdateModel);
|
||||
this.saveButton.addEventListener('click', this._boundSaveUpdateModel);
|
||||
this.header.addEventListener('action', this.cancel);
|
||||
this.deleteRecordButton.addEventListener('click', this.hideHeaderAndForm);
|
||||
|
||||
if (this.model._id) {
|
||||
this.type = 'update';
|
||||
this.deleteButton.addEventListener('click', this.deleteRecord);
|
||||
this.cancelDeleteButton.addEventListener('click', this.cancelDelete);
|
||||
} else {
|
||||
this.type = 'create';
|
||||
}
|
||||
|
||||
var list = this.element.classList;
|
||||
list.add(this.type);
|
||||
list.add('preset-' + this.model.preset);
|
||||
list.add('provider-' + this.model.providerType);
|
||||
list.add('auth-' + this.authenticationType);
|
||||
|
||||
if (this.model.error) {
|
||||
list.add('error');
|
||||
}
|
||||
|
||||
if (this.authenticationType === 'oauth2') {
|
||||
this.oauth2SignIn.addEventListener('click', this.displayOAuth2);
|
||||
|
||||
if (this.type === 'create') {
|
||||
this.displayOAuth2();
|
||||
}
|
||||
|
||||
this.fields.user.disabled = true;
|
||||
this.saveButton.disabled = true;
|
||||
}
|
||||
|
||||
this.form.reset();
|
||||
this.updateForm();
|
||||
|
||||
var usernameType = this.model.usernameType;
|
||||
this.fields.user.type = (usernameType === undefined) ?
|
||||
'text' : usernameType;
|
||||
|
||||
this.header.runFontFitSoon();
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
var list = this.element.classList;
|
||||
|
||||
list.remove(this.type);
|
||||
|
||||
list.remove('preset-' + this.model.preset);
|
||||
list.remove('provider-' + this.model.providerType);
|
||||
list.remove('auth-' + this.authenticationType);
|
||||
list.remove('error');
|
||||
list.remove(this.removeDialogClass);
|
||||
|
||||
this.fields.user.disabled = false;
|
||||
this.saveButton.disabled = false;
|
||||
|
||||
this._fields = null;
|
||||
this.form.reset();
|
||||
|
||||
this.deleteRecordButton.removeEventListener('click',
|
||||
this.hideHeaderAndForm);
|
||||
this.oauth2SignIn.removeEventListener('click', this.displayOAuth2);
|
||||
this.saveButton.removeEventListener('click', this._boundSaveUpdateModel);
|
||||
this.deleteButton.removeEventListener('click', this.deleteRecord);
|
||||
this.cancelDeleteButton.removeEventListener('click', this.cancelDelete);
|
||||
this.header.removeEventListener('action',
|
||||
this.cancel);
|
||||
this.form.removeEventListener('submit', this._boundSaveUpdateModel);
|
||||
},
|
||||
|
||||
dispatch: co.wrap(function *(data) {
|
||||
if (this.model) {
|
||||
this.destroy();
|
||||
}
|
||||
|
||||
var params = data.params;
|
||||
var changeToken = ++this._changeToken;
|
||||
|
||||
this.completeUrl = '/settings/';
|
||||
|
||||
try {
|
||||
var model;
|
||||
if (params.id) {
|
||||
model = yield core.bridge.getAccount(params.id);
|
||||
} else if (params.preset) {
|
||||
model = this._createModel(params.preset);
|
||||
}
|
||||
|
||||
this.preset = Presets[model.preset];
|
||||
|
||||
// race condition another dispatch has queued
|
||||
// while we where waiting for an async event.
|
||||
if (this._changeToken !== changeToken) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.model = model;
|
||||
this.render();
|
||||
} catch (err) {
|
||||
console.error('Error displaying model in ModifyAccount', data, err);
|
||||
}
|
||||
}),
|
||||
|
||||
oninactive: function() {
|
||||
View.prototype.oninactive.apply(this, arguments);
|
||||
|
||||
if (this._oauthDialog) {
|
||||
this._oauthDialog.close();
|
||||
this._oauthDialog = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
});
|
||||
Loading…
Reference in a new issue