password-manager-mirror/frontend/delta/js/Clipperz/PM/UI/MainController.js

2690 lines
95 KiB
JavaScript

/*
Copyright 2008-2015 Clipperz Srl
This file is part of Clipperz, the online password manager.
For further information about its features and functionalities please
refer to http://www.clipperz.com.
* Clipperz is free software: you can redistribute it and/or modify it
under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
* Clipperz is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU Affero General Public License for more details.
* You should have received a copy of the GNU Affero General Public
License along with Clipperz. If not, see http://www.gnu.org/licenses/.
*/
"use strict";
Clipperz.Base.module('Clipperz.PM.UI');
Clipperz.PM.UI.MainController = function() {
// this._proxy = null;
this._mediaQueryStyle = "narrow";
this._user = null;
this._filter = {'type':'ALL'};
this._shouldIncludeArchivedCards = false;
this._isSelectionPanelOpen = false;
this._isSettingsPanelOpen = false;
this._isAttachmentQueueBoxOpen = false;
this._isCertificateQueueBoxOpen = false;
this._pageStack = ['loadingPage'];
this._overlay = new Clipperz.PM.UI.Components.Overlay();
this._isTouchDevice = ('ontouchstart' in window || 'onmsgesturechange' in window);
this._isDesktop = window.screenX != 0 && !this._isTouchDevice;
this._hasKeyboard = this._isDesktop;
this._userPreferences = null;
this._recordsInfo = null;
this._selectedCards = null;
this._selectedCardInfo = null;
this._closeMaskAction = null;
this._lockListener = null;
this._lockTimeout = null;
this._pages = {};
this.renderPages([
'loginPage',
'registrationPage',
'unlockPage',
'mainPage',
'cardDetailPage',
'errorPage',
]);
this.registerForNotificationCenterEvents([
'doLogin', 'registerNewUser', 'showRegistrationForm', 'goBack',
'updateUserAccountInfo',
'logout',
'enableLock', 'disableLock', 'unlock',
'updatePIN', 'disablePIN', 'forcePassphraseLogin', 'forcePassphraseUnlock',
'changePassphrase', 'deleteAccount',
/*'updateUserPreferences',*/ 'setPreferences',
'updateOTPListAndDetails', 'createNewOTP', 'deleteOTPs', 'changeOTPLabel',
'importCards',
'downloadExport',
'updateProgress',
'toggleSelectionPanel', 'hideSelectionPanel', 'toggleSettingsPanel', 'toggleAttachmentQueueBox', 'toggleCertificateQueueBox',
'matchMediaQuery', 'unmatchMediaQuery',
'selectAllCards', 'selectRecentCards', 'selectCardsWithCertificate', 'selectCardsWithAttachments', 'selectUntaggedCards', 'tagSelected', 'search',
'refreshCardEditDetail',
'saveCardEdits', 'cancelCardEdits',
'selectCard',
'addCardClick',
'deleteCard', 'toggleArchiveCard', 'cloneCard', 'createCertificate', 'editCard',
'downloadCertificate', 'showCertificatePreview', 'hideCertificatePreview', 'closeCertificateNotification', 'showCertificateCard',
'addTag', 'removeTag',
'showArchivedCards', 'hideArchivedCards',
'goBackToMainPage',
'maskClick',
'closeHelp',
'downloadOfflineCopy',
'runDirectLogin', 'removeDirectLogin',
'exitSearch',
'updateAttachmentQueueInfo', 'addAttachment', 'removeAttachment', 'getAttachment', 'cancelAttachment', 'closeAttachmentNotification',
]);
this._attachmentController = new Clipperz.PM.UI.AttachmentController({
'uploadMessageCallback': MochiKit.Base.method(this, 'uploadMessageCallback'),
'downloadMessageCallback': MochiKit.Base.method(this, 'downloadMessageCallback'),
'reloadServerStatusCallback': MochiKit.Base.method(this, 'reloadAttachmentServerStatusCallback')
});
this._certificateQueueStatus = [];
document.addEventListener('dragover', MochiKit.Base.method(this, 'blockDragOver'), false);
Mousetrap.bind(['/'], MochiKit.Base.method(this, 'focusOnSearch'));
Mousetrap.bind(['left', 'h', 'esc'], MochiKit.Base.method(this, 'exitCurrentSelection'));
Mousetrap.bind(['right', 'l', 'enter'], MochiKit.Base.method(this, 'selectDetail'));
Mousetrap.bind(['up', 'k'], MochiKit.Base.method(this, 'selectPreviousCard'));
Mousetrap.bind(['down', 'j'], MochiKit.Base.method(this, 'selectNextCard'));
Mousetrap.bind(['*'], MochiKit.Base.method(this, 'selectAllCards_handler'));
Mousetrap.bind(['?'], MochiKit.Base.method(this, 'showHelp_handler'));
Mousetrap.bind(['l o c k'], MochiKit.Base.method(this, 'lockShortcut'));
// Mousetrap.bind(['t e s t'], MochiKit.Base.method(this, 'downloadExport_handler'));
return this;
}
MochiKit.Base.update(Clipperz.PM.UI.MainController.prototype, {
toString: function () {
return "Clipperz.PM.UI.MainController";
},
//=========================================================================
overlay: function () {
return this._overlay;
},
updateProgress_handler: function (aProgressPercentage) {
return Clipperz.Async.callbacks("MainController.updateProgress_handler", [
MochiKit.Base.method(this.overlay(), 'updateProgress', aProgressPercentage)
], {trace:false});
},
loginForm: function () {
return this._loginForm;
},
registrationWizard: function () {
return this._registrationWizard;
},
//=========================================================================
/*
proxy: function () {
return this._proxy;
},
setProxy: function (aValue) {
this._proxy = aValue;
},
*/
//=========================================================================
isOnline: function() {
return navigator.onLine;
// return false;
},
hasLocalData: function() {
// return false;
return (Clipperz.PM.DataModel.devicePreferences.accountData() != null);
},
loginMode: function () {
// PIN is set using this command:
// Clipperz.PM.PIN.setCredentialsWithPIN('1234', {'username':'joe', 'passphrase':'clipperz'});
return (Clipperz.PM.PIN.isLocalStorageSupported() && Clipperz.PM.PIN.isSet()) ? 'PIN' : 'CREDENTIALS';
},
//=========================================================================
pages: function () {
return this._pages;
},
pageStack: function () {
return this._pageStack;
},
//=========================================================================
showOfflineError: function () {
Clipperz.log("THE BROWSER IS OFFLINE");
},
selectInitialProxy: function () {
if (this.isOnline()) {
// this._proxy = Clipperz.PM.Proxy.defaultProxy;
} else {
if (this.hasLocalData()) {
// this._proxy = new Clipperz.PM.Proxy.Offline({dataStore: new Clipperz.PM.Proxy.Offline.LocalStorageDataStore(), shouldPayTolls:false});
Clipperz.PM.Proxy.defaultProxy = new Clipperz.PM.Proxy.Offline({dataStore: new Clipperz.PM.Proxy.Offline.LocalStorageDataStore(), shouldPayTolls:false});
} else {
this.showOfflineError();
}
}
},
// proxy: function () {
// return this._proxy;
// },
//=========================================================================
capitaliseFirstLetter: function (aValue) {
return aValue.charAt(0).toUpperCase() + aValue.slice(1);
},
renderPages: function (pages) {
var self = this;
MochiKit.Iter.forEach(pages, function (aPageName) {
self._pages[aPageName] = ReactDOM.render(
Clipperz.PM.UI.Components.Pages[self.capitaliseFirstLetter(aPageName)](self.pageProperties(aPageName)),
MochiKit.DOM.getElement(aPageName)
);
});
},
registerForNotificationCenterEvents: function (events) {
var self = this;
MochiKit.Iter.forEach(events, function (anEvent) {
// MochiKit.Signal.connect(Clipperz.Signal.NotificationCenter, anEvent, MochiKit.Base.method(self, anEvent + '_handler'));
MochiKit.Signal.connect(Clipperz.Signal.NotificationCenter, anEvent, MochiKit.Base.method(self, 'eventHandlerErrorCatcher', anEvent));
MochiKit.Signal.connect(Clipperz.Signal.NotificationCenter, anEvent, MochiKit.Base.method(self, 'resetLockTimeout'));
});
// MochiKit.Signal.connect(window, 'onpopstate', MochiKit.Base.method(this, 'historyGoBack'));
// MochiKit.Signal.connect(window, 'onbeforeunload', MochiKit.Base.method(this, 'shouldExitApp'));
},
eventHandlerErrorCatcher: function (anEvent, aValue) {
var deferredResult;
deferredResult = new Clipperz.Async.Deferred("MainController.eventHandlerErrorCatcher", {trace: false});
deferredResult.addMethod(this, anEvent + '_handler');
deferredResult.addErrback(MochiKit.Base.bind(function (anError) {
if (! anError instanceof MochiKit.Async.CancelledError) {
this.overlay().hide(true);
this.moveInPage(this.currentPage(), 'errorPage');
this.pages()['errorPage'].setProps({'error':anError});
console.log("CATCHED UNHANDLED ERROR");
}
return anError;
}, this));
deferredResult.callback(aValue);
return deferredResult;
},
//-------------------------------------------------------------------------
/*
selectionChange_handler: function (anEvent) {
var selection;
var selectionRange;
var selectionNode;
var valueElement;
// other hints: http://www.bearpanther.com/2013/05/27/easy-text-selection-in-mobile-safari/
// SELECTION: https://developer.mozilla.org/en-US/docs/Web/API/Selection
// RANGE: https://developer.mozilla.org/en-US/docs/Web/API/Range
// NODE TYPES: https://developer.mozilla.org/en-US/docs/Web/API/Node.nodeType
selection = MochiKit.DOM.currentWindow().getSelection();
//console.log("-- selection", selection);
selectionRange = selection.getRangeAt(0);
selectionNode = selectionRange.startContainer.childNodes[selectionRange.startOffset];
//console.log("-- selectionNode", selectionNode);
if (selectionNode != undefined) {
valueElement = MochiKit.DOM.getFirstElementByTagAndClassName('*', 'value', selectionNode);
//console.log("-- valueElement", valueElement);
}
if ((valueElement != null) && (valueElement != selectionNode)) {
var range;
range = MochiKit.DOM.currentDocument().createRange();
range.selectNodeContents(valueElement);
selection.removeAllRanges();
selection.addRange(range);
anEvent.preventDefault();
anEvent.stopPropagation();
//console.log("updated selection", MochiKit.DOM.currentWindow().getSelection());
}
//console.log("-----------");
},
*/
//-------------------------------------------------------------------------
run: function (parameters) {
var shouldShowRegistrationForm;
var canRegisterNewUsers;
canRegisterNewUsers = Clipperz.PM.Proxy.defaultProxy.canRegisterNewUsers();
this.selectInitialProxy();
shouldShowRegistrationForm = parameters['shouldShowRegistrationForm'] && canRegisterNewUsers;
this.showLoginForm();
if (shouldShowRegistrationForm) {
this.showRegistrationForm_handler();
}
// this.overlay().done("", 0.5);
this.overlay().hide();
},
//-------------------------------------------------------------------------
checkPassphrase: function( passphraseIn ) {
var deferredResult;
deferredResult = new Clipperz.Async.Deferred("MainController.checkPassphrase", {trace: false});
deferredResult.addMethod(this.user(), 'getPassphrase');
deferredResult.addCallback(function (candidatePassphrase, realPassphrase) { return candidatePassphrase == realPassphrase; }, passphraseIn );
deferredResult.callback();
return deferredResult;
},
//-------------------------------------------------------------------------
showLoginForm: function () {
var loginFormPage;
loginFormPage = this.pages()['loginPage'];
// loginFormPage.setProps({'mode':this.loginMode(), 'isNewUserRegistrationAvailable':Clipperz.PM.Proxy.defaultProxy.canRegisterNewUsers()});
loginFormPage.setProps({'mode':this.loginMode()});
this.moveInPage(this.currentPage(), 'loginPage');
MochiKit.Async.callLater(0.5, MochiKit.Base.method(loginFormPage, 'setInitialFocus'));
MochiKit.Async.callLater(0.5, MochiKit.Base.method(this, 'recursivelyPollLoginFormForChanges'));
},
recursivelyPollLoginFormForChanges: function () {
this.pages()['loginPage'].pollForChanges();
if (this.currentPage() == 'loginPage') {
MochiKit.Async.callLater(0.5, MochiKit.Base.method(this, 'recursivelyPollLoginFormForChanges'));
}
},
showRegistrationForm_handler: function () {
var currentPage;
var registrationPage;
currentPage = this.currentPage();
registrationPage = this.pages()['registrationPage'];
return Clipperz.Async.callbacks("MainController.showRegistrationForm_handler", [
MochiKit.Base.method(this, 'setCurrentPage', 'loginPage'),
MochiKit.Base.method(registrationPage, 'setProps', {}),
MochiKit.Base.method(this, 'moveInPage', currentPage, 'registrationPage'),
MochiKit.Base.partial(MochiKit.Async.callLater, 0.5, MochiKit.Base.method(registrationPage, 'setInitialFocus'))
], {trace:false});
},
forcePassphraseLogin_handler: function() {
return Clipperz.Async.callbacks("MainController.forcePassphraseLogin_handler", [
MochiKit.Base.method(this.pages()['loginPage'], 'setProps', {'forceCredentials': true}),
MochiKit.Base.partial(MochiKit.Async.callLater, 0.1, MochiKit.Base.method(this.pages()['loginPage'], 'setInitialFocus'))
], {trace:false});
},
forcePassphraseUnlock_handler: function() {
return Clipperz.Async.callbacks("MainController.forcePassphraseUnlock_handler", [
MochiKit.Base.method(this.pages()['unlockPage'], 'setProps', {'forceCredentials': true}),
MochiKit.Base.partial(MochiKit.Async.callLater, 0.1, MochiKit.Base.method(this.pages()['unlockPage'], 'setInitialFocus'))
], {trace:false});
},
//=========================================================================
doLogin_handler: function (event) {
return this.doLogin(event);
},
doLogin: function (someCredentials) {
var deferredResult;
var credentials;
var getPassphraseDelegate;
var user;
user = null;
this.overlay().show("logging in", false, false);
this.pages()['loginPage'].setProps({disabled:true});
if ('pin' in someCredentials) {
credentials = Clipperz.PM.PIN.credentialsWithPIN(someCredentials['pin']);
} else {
credentials = someCredentials;
}
getPassphraseDelegate = MochiKit.Base.partial(MochiKit.Async.succeed, credentials.passphrase);
user = new Clipperz.PM.DataModel.User({'username':credentials.username, 'getPassphraseFunction':getPassphraseDelegate});
deferredResult = new Clipperz.Async.Deferred('MainController.doLogin', {trace:false});
deferredResult.addCallback(MochiKit.Async.wait, 0.1);
deferredResult.addMethod(Clipperz.Crypto.PRNG.defaultRandomGenerator(), 'deferredEntropyCollection');
deferredResult.addMethod(user, 'login');
if (Clipperz.PM.PIN.isLocalStorageSupported()) {
deferredResult.addMethod(Clipperz.PM.PIN, 'resetFailedAttemptCount');
}
deferredResult.addMethod(this, 'setUser', user);
deferredResult.addMethod(this, 'updateUserPreferences');
deferredResult.addMethod(this, 'runApplication');
deferredResult.addMethod(this, 'updateCertificateQueueInfo');
deferredResult.addMethod(this.overlay(), 'done', "", 1);
deferredResult.addErrback(MochiKit.Base.method(this, 'genericErrorHandler', someCredentials, "login failed"));
deferredResult.addErrback(MochiKit.Base.bind(function (anEvent, anError) {
if (anError['isPermanent'] != true) {
this.pages()['loginPage'].setProps({disabled:false, 'mode':this.loginMode()});
this.pages()['loginPage'].setInitialFocus();
}
return anEvent; // anError;
}, this, someCredentials))
deferredResult.callback();
return deferredResult;
},
logout_handler: function () {
var deferredResult;
deferredResult = new Clipperz.Async.Deferred('MainController.logout', {trace:false});
deferredResult.addMethod(this.user(), 'logout');
deferredResult.addCallback(function () {
window.location.href = '/';
})
deferredResult.callback();
return deferredResult;
},
lockShortcut: function(anEvent) {
anEvent.preventDefault();
return this.lock();
},
lock: function () {
var deferredResult;
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'disableLock');
deferredResult = new Clipperz.Async.Deferred('MainController.lock_handler', {trace:false});
// force exit edit state OR skip lock if pending changes are present
deferredResult.addMethod(this, 'exitCurrentSelection');
deferredResult.addMethod(this, 'resetPanels');
deferredResult.addMethod(this, 'moveOutPage', this.currentPage(), 'unlockPage');
deferredResult.addMethod(this.user(), 'lock');
deferredResult.addMethod(this, 'deleteCleanTextData');
deferredResult.addMethod(this.pages()['unlockPage'], 'setProps', {'username': this.user().username()});
deferredResult.addCallback(MochiKit.Async.callLater, 0.1, MochiKit.Base.method(this.pages()['unlockPage'], 'resetUnlockForm'));
deferredResult.addMethod(this.pages()['unlockPage'], 'setInitialFocus');
deferredResult.addCallback(MochiKit.Async.callLater, 1, MochiKit.Base.method(this.pages()['mainPage'], 'replaceProps', {'locked': true}));
deferredResult.callback();
return deferredResult;
},
unlock_handler: function(someInfo) {
var deferredResult;
var credential = someInfo['credential'];
var credentialType = someInfo['credentialType'];
var user, passphrase, getPassphraseDelegate;
// var user = this.user();
var oldUser = this.user();
var unlockPage = this.pages()['unlockPage'];
var overlay = this.overlay();
overlay.show("validating…", false);
passphrase = (credentialType=='PIN') ? Clipperz.PM.PIN.credentialsWithPIN(credential)['passphrase'] : credential;
getPassphraseDelegate = MochiKit.Base.partial(MochiKit.Async.succeed, passphrase);
user = new Clipperz.PM.DataModel.User({'username':oldUser.username(), 'getPassphraseFunction':getPassphraseDelegate});
deferredResult = new Clipperz.Async.Deferred('MainController.unlock_handler', {trace:false});
deferredResult.addMethod(unlockPage, 'setProps', {'disabled': true});
deferredResult.addMethod(user, 'login');
deferredResult.addMethod(this, 'setUser', user);
// deferredResult.addMethod(user, 'unlock', MochiKit.Base.partial(MochiKit.Async.succeed, passphrase));
deferredResult.addErrback(MochiKit.Base.bind(function (aValue) {
var innerDeferredResult;
var errorMessage;
errorMessage = 'failed';
if (credentialType=='PIN') {
var attemptsLeft = Clipperz.PM.PIN.recordFailedAttempt();
if (attemptsLeft == -1) {
errorMessage = 'PIN resetted';
}
}
innerDeferredResult = new Clipperz.Async.Deferred('MainController.unlock_handler <incorrect passphrase>', {trace:false});
innerDeferredResult.addMethod(unlockPage, 'setProps', {
'disabled': false,
'mode': this.loginMode(),
});
innerDeferredResult.addMethod(unlockPage, 'setInitialFocus');
innerDeferredResult.addMethod(overlay, 'failed', errorMessage, 1);
innerDeferredResult.addCallback(MochiKit.Async.fail, aValue);
innerDeferredResult.callback();
return aValue;
}, this));
if (credentialType=='PIN') {
deferredResult.addMethod(Clipperz.PM.PIN, 'resetFailedAttemptCount');
}
deferredResult.addMethod(this, 'updateUserPreferences');
deferredResult.addMethod(this, 'moveInPage', this.currentPage(), 'mainPage');
deferredResult.addMethod(this, 'refreshUI');
deferredResult.addMethod(unlockPage, 'setProps', {
'disabled': false,
'forceCredentials': false,
});
// deferredResult.addMethod(unlockPage, 'resetUnlockForm');
deferredResult.addCallback(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'enableLock');
deferredResult.addMethod(this, 'updateCertificateQueueInfo');
deferredResult.addMethod(overlay, 'done', "", 0.5);
deferredResult.addErrback(MochiKit.Async.succeed, true);
deferredResult.callback();
return deferredResult;
// this.user().setPassphraseFunction(function(){return passphrase;});
// TODO: check if passphrase is correct by try/catch on decrypting something
// this.moveOutPage(this.currentPage(), 'mainPage');
// TODO: check why the unlock form keeps the value stored (doesn't happen with the login form...)
},
deleteCleanTextData: function() {
this._recordsInfo = null;
this._selectedCards = null;
this._selectedCardInfo = null;
this._userPreferences = null;
},
//-------------------------------------------------------------------------
registerNewUser_handler: function (credentials) {
var deferredResult;
this.overlay().show("creating user");
this.pages()['registrationPage'].setProps({disabled:true});
deferredResult = new Clipperz.Async.Deferred('MainController.registerNewUser', {trace:false});
deferredResult.addCallback(Clipperz.PM.DataModel.User.registerNewAccount,
credentials['username'],
MochiKit.Base.partial(MochiKit.Async.succeed, credentials['passphrase'])
);
deferredResult.addMethod(this, 'doLogin', credentials);
deferredResult.addMethod(this,'importCards', Clipperz.PM.DefaultCards);
deferredResult.addErrback(MochiKit.Base.method(this, 'genericErrorHandler', credentials, "registration failed"));
deferredResult.addErrback(MochiKit.Base.bind(function (anError) {
if (anError['isPermanent'] != true) {
this.pages()['registrationPage'].setProps({disabled:false});
this.pages()['registrationPage'].setInitialFocus();
}
return anError;
}, this));
deferredResult.callback();
return deferredResult;
},
//-------------------------------------------------------------------------
user: function () {
return this._user;
},
setUser: function (aUser) {
this._user = aUser;
return this._user;
},
//=========================================================================
filter: function () {
return this._filter;
},
setFilter: function (aType, aValue) {
this._filter = {'type':aType, 'value':aValue};
return this._filter;
},
shouldIncludeArchivedCards: function () {
return this._shouldIncludeArchivedCards;
},
setShouldIncludeArchivedCards: function (aValue) {
this._shouldIncludeArchivedCards = aValue;
},
//----------------------------------------------------------------------------
collectRecordInfo: function (aRecord) {
return Clipperz.Async.callbacks("MainController.updateOTPListAndDetails", [
Clipperz.Async.collectResults("MainController.updateOTPListAndDetails <inner results>", {
'recordInfo': MochiKit.Base.method(aRecord, 'collectRecordInfo'),
// 'certificateMetadata': MochiKit.Base.method(aRecord, 'certificateMetadata'),
'hasPendingChanges': MochiKit.Base.method(this.user(), 'hasPendingChanges'),
}, {trace:false}),
function (someData) {
var result;
result = someData['recordInfo'];
result['hasPendingChanges'] = someData['hasPendingChanges'];
return result;
},
], {trace:false});
return deferredResult;
},
//----------------------------------------------------------------------------
showCardDetailInNarrowView: function (aValue) {
return Clipperz.Async.callbacks("MainController.showCardDetailInNarrowView", [
MochiKit.Base.method(this, 'setPageProperties', 'cardDetailPage', 'features', this.features()),
MochiKit.Base.method(this, 'setPageProperties', 'cardDetailPage', 'selectedCard', aValue),
MochiKit.Base.method(this, 'moveInPage', this.currentPage(), 'cardDetailPage'),
function () { return aValue; },
], {trace:false});
},
updateSelectedCard: function (someInfo, shouldShowLoading, shouldShowCardDetail) {
var deferredResult;
var showLoading = typeof(shouldShowLoading) !== 'undefined' ? shouldShowLoading : true;
if (someInfo == null) {
this.setPageProperties('mainPage', 'selectedCard', {});
deferredResult = MochiKit.Async.succeed();
} else {
if (showLoading) {
// this.setPageProperties('mainPage', 'selectedCard', {'loading':true, 'label':someInfo['label'], '_reference':someInfo['reference']});
this.overlay().show('', true, false, true)
}
deferredResult = new Clipperz.Async.Deferred('MainController.updateSelectedCard', {trace:false});
deferredResult.addMethod(this.user(), 'getRecord', someInfo['reference']);
deferredResult.addMethod(this, 'collectRecordInfo');
deferredResult.addMethod(this, 'setPageProperties', 'mainPage', 'selectedCard');
if ((this.mediaQueryStyle() == 'narrow') && shouldShowCardDetail) {
deferredResult.addMethod(this, 'showCardDetailInNarrowView');
}
deferredResult.addMethod(this.overlay(), 'hide', true);
MochiKit.Async.callLater(0.1, MochiKit.Base.method(deferredResult, 'callback'));
}
return deferredResult;
},
//............................................................................
regExpFilterGenerator: function (aRegExp, aSearchField) {
var searchField = aSearchField ? aSearchField : Clipperz.PM.DataModel.Record.defaultSearchField;
return function (aCardInfo) {
aRegExp.lastIndex = 0;
return aRegExp.test(aCardInfo[searchField]);
}
},
selectedCardReference: function () {
return this.pages()['mainPage'].props &&
this.pages()['mainPage'].props['selectedCard'] &&
this.pages()['mainPage'].props['selectedCard']['_reference']
? this.pages()['mainPage'].props['selectedCard']['_reference']
: '';
},
isSelectedCardStillVisible: function (someCards) {
var result;
var reference;
reference = this.selectedCardReference();
result = MochiKit.Iter.some(someCards, function (aCardInfo) {
return aCardInfo['_reference'] == reference;
});
return result;
},
//----------------------------------------------------------------------------
recordsInfo: function () {
return this._recordsInfo;
},
setRecordsInfo: function (someRecordsInfo) {
//console.log("setRecordsInfo", someRecordsInfo);
this._recordsInfo = someRecordsInfo;
return this._recordsInfo;
},
resetRecordsInfo: function () {
this._recordsInfo = null;
this._selectedCards = null;
},
getRecordsInfo: function (cardInfo, shouldIncludeArchivedCards) {
var deferredResult;
if (this._recordsInfo == null) {
deferredResult = new Clipperz.Async.Deferred('MainController.getRecordsInfo', {trace:false});
deferredResult.addMethod(this.user(), 'getRecordsInfo', Clipperz.PM.DataModel.Record.defaultCardInfo /*, shouldIncludeArchivedCards*/);
deferredResult.addMethod(this, 'setRecordsInfo');
deferredResult.callback();
} else {
deferredResult = MochiKit.Async.succeed(this._recordsInfo);
}
return deferredResult;
},
//............................................................................
selectedCards: function () {
return this._selectedCards;
},
setSelectedCards: function (aValue) {
this._selectedCards = aValue;
return this._selectedCards;
},
//----------------------------------------------------------------------------
updateSelectedCards: function (shouldIncludeArchivedCards, aFilter) {
var deferredResult;
var filterCriteria;
var sortCriteria;
var rangeFilter;
var fullFilterCriteria;
var selectedCardReference = this._selectedCardInfo ? this._selectedCardInfo['reference'] : null;
if (aFilter['type'] == 'ALL') {
filterCriteria = MochiKit.Base.operator.truth;
sortCriteria = Clipperz.Base.caseInsensitiveKeyComparator('label');
rangeFilter = MochiKit.Base.operator.identity;
} else if (aFilter['type'] == 'RECENT') {
filterCriteria = MochiKit.Base.operator.truth;
sortCriteria = Clipperz.Base.reverseComparator(MochiKit.Base.keyComparator('_accessDate'));
rangeFilter = function (someCards) { return someCards.slice(0, 10)};
} else if (aFilter['type'] == 'WITH_CERTIFICATE') {
filterCriteria = function (aRecordInfo) { return aRecordInfo['hasBeenCertified']; };
sortCriteria = Clipperz.Base.caseInsensitiveKeyComparator('label');
rangeFilter = MochiKit.Base.operator.identity;
} else if (aFilter['type'] == 'WITH_ATTACHMENTS') {
filterCriteria = function (aRecordInfo) { return aRecordInfo.attachmentsCount > 0; };
sortCriteria = Clipperz.Base.caseInsensitiveKeyComparator('label');
rangeFilter = MochiKit.Base.operator.identity;
} else if (aFilter['type'] == 'SEARCH') {
filterCriteria = this.regExpFilterGenerator(Clipperz.PM.DataModel.Record.regExpForSearch(aFilter['value']));
sortCriteria = Clipperz.Base.caseInsensitiveKeyComparator('label');
rangeFilter = MochiKit.Base.operator.identity;
} else if (aFilter['type'] == 'TAG') {
filterCriteria = this.regExpFilterGenerator(Clipperz.PM.DataModel.Record.regExpForTag(aFilter['value']));
sortCriteria = Clipperz.Base.caseInsensitiveKeyComparator('label');
rangeFilter = MochiKit.Base.operator.identity;
} else if (aFilter['type'] == 'UNTAGGED') {
filterCriteria = this.regExpFilterGenerator(Clipperz.PM.DataModel.Record.regExpForNoTag());
sortCriteria = Clipperz.Base.caseInsensitiveKeyComparator('label');
rangeFilter = MochiKit.Base.operator.identity;
}
fullFilterCriteria = function (aRecordInfo) {
var result;
if (aRecordInfo['_reference'] == selectedCardReference) {
result = true;
} else {
if ((shouldIncludeArchivedCards == false) && (aRecordInfo['_isArchived'])) {
result = false;
} else {
result = filterCriteria(aRecordInfo);
}
}
return result;
}
deferredResult = new Clipperz.Async.Deferred('MainController.updateSelectedCards', {trace:false});
deferredResult.addMethod(this, 'getRecordsInfo', Clipperz.PM.DataModel.Record.defaultCardInfo, shouldIncludeArchivedCards);
deferredResult.addCallback(MochiKit.Base.filter, fullFilterCriteria);
deferredResult.addMethodcaller('sort', sortCriteria);
deferredResult.addCallback(rangeFilter);
deferredResult.addMethod(this, 'setPageProperties', 'mainPage', 'cards');
deferredResult.addCallback(MochiKit.Base.bind(function (someCards) {
this.setSelectedCards(someCards);
if (!this.isSelectedCardStillVisible(someCards)) {
this.updateSelectedCard(null);
};
}, this));
deferredResult.addMethod(this, 'setPageProperties', 'mainPage', 'filter', this.filter());
deferredResult.callback();
return deferredResult;
},
refreshSelectedCards: function () {
return this.updateSelectedCards(this.shouldIncludeArchivedCards(), this.filter());
},
refreshUI: function (selectedCardReference) {
var deferredResult;
deferredResult = new Clipperz.Async.Deferred('MainController.refreshUI', {trace:false});
deferredResult.addMethod(this, 'refreshSelectedCards');
deferredResult.addMethod(this, 'renderTags');
if (selectedCardReference != null) {
deferredResult.addMethod(this.user(), 'getRecord', selectedCardReference);
deferredResult.addMethod(this, 'collectRecordInfo');
deferredResult.addMethod(this, 'setPageProperties', this.currentPage(), 'selectedCard');
}
deferredResult.callback();
return deferredResult;
},
//----------------------------------------------------------------------------
enableLock_handler: function () {
return Clipperz.Async.callbacks("MainController.enableLock_handler", [
MochiKit.Base.partial(MochiKit.Signal.connect, Clipperz.Signal.NotificationCenter, 'lock', MochiKit.Base.method(this, 'lock'))
], {trace:false});
},
disableLock_handler: function () {
return Clipperz.Async.callbacks("MainController.disableLock_handler", [
MochiKit.Base.partial(MochiKit.Signal.disconnectAll, Clipperz.Signal.NotificationCenter, 'lock')
], {trace:false});
},
updatePIN_handler: function(aPIN) {
return Clipperz.Async.callbacks("MainController.updatePIN_handler", [
MochiKit.Base.method(this.overlay(), 'show', "updating …", true),
MochiKit.Base.method(Clipperz.PM.PIN, 'updatePin', this.user(), aPIN),
MochiKit.Base.method(this.overlay(), 'done', "", 1)
], {trace:false});
},
disablePIN_handler: function() {
return Clipperz.Async.callbacks("MainController.disablePIN_handler", [
MochiKit.Base.method(this.overlay(), 'show', "disabling …", true),
MochiKit.Base.method(Clipperz.PM.PIN, 'disablePin'),
MochiKit.Base.method(this.overlay(), 'done', "", 1)
], {trace:false});
},
resetLockTimeout: function () {
if (this.user()) {
return Clipperz.Async.callbacks("MainController.resetLockTimeout", [
MochiKit.Base.method(this.user(), 'getPreference', 'lock'),
MochiKit.Base.bind(function (someLockInfo) {
if (this._lockTimeout) {
clearTimeout(this._lockTimeout);
}
if (someLockInfo['enabled'] == true) {
var aDelay = someLockInfo['timeoutInMinutes'] * 60 * 1000;
this._lockTimeout = setTimeout(function() {
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'lock');
}, aDelay);
}
}, this)
], {trace:false});
}
},
//----------------------------------------------------------------------------
getAllCardsCount: function () {
var archivedCardsFilter = this.shouldIncludeArchivedCards()
? MochiKit.Async.succeed
: MochiKit.Base.partial(MochiKit.Base.filter, function (someRecordInfo) { return ! someRecordInfo['_isArchived']; });
return Clipperz.Async.callbacks("MainController.getAllCardsCount", [
MochiKit.Base.method(this.user(), 'getRecords'),
MochiKit.Base.partial(MochiKit.Base.map, Clipperz.Async.collectResults("collectResults", {'_fullLabel':MochiKit.Base.methodcaller('fullLabel'), '_isArchived':MochiKit.Base.methodcaller('isArchived')}, {trace:false})),
Clipperz.Async.collectAll,
archivedCardsFilter,
function (someCards) { return someCards.length; },
], {trace:false});
},
getCardsWithCertificateCount: function () {
var archivedCardsFilter = this.shouldIncludeArchivedCards()
? MochiKit.Async.succeed
: MochiKit.Base.partial(MochiKit.Base.filter, function (someRecordInfo) { return ! someRecordInfo['_isArchived']; });
return Clipperz.Async.callbacks("MainController.getCardsWithCertificateCount", [
MochiKit.Base.method(this.user(), 'getRecords'),
MochiKit.Base.partial(MochiKit.Base.map, Clipperz.Async.collectResults("collectResults", {'hasBeenCertified':MochiKit.Base.methodcaller('hasBeenCertified'), '_isArchived':MochiKit.Base.methodcaller('isArchived')}, {trace:false})),
Clipperz.Async.collectAll,
archivedCardsFilter,
function (aResult) {
return MochiKit.Base.filter(function (aRecordInfo) { return aRecordInfo['hasBeenCertified'] === true; }, aResult).length;
}
], {trace:false});
},
getCardsWithAttachmentsCount: function () {
var archivedCardsFilter = this.shouldIncludeArchivedCards()
? MochiKit.Async.succeed
: MochiKit.Base.partial(MochiKit.Base.filter, function (someRecordInfo) { return ! someRecordInfo['_isArchived']; });
return Clipperz.Async.callbacks("MainController.getCardsWithAttachmentsCount", [
MochiKit.Base.method(this.user(), 'getRecords'),
MochiKit.Base.partial(MochiKit.Base.map, Clipperz.Async.collectResults("collectResults", {'attachmentsCount':MochiKit.Base.methodcaller('attachmentsCount'), '_isArchived':MochiKit.Base.methodcaller('isArchived')}, {trace:false})),
Clipperz.Async.collectAll,
archivedCardsFilter,
function (aResult) {
return MochiKit.Base.filter(function (aRecordInfo) { return aRecordInfo['attachmentsCount'] > 0; }, aResult).length;
}
], {trace:false});
},
getArchivedCardsCount: function () {
return Clipperz.Async.callbacks("MainController.getArchivedCardsCount", [
MochiKit.Base.method(this.user(), 'getRecords'),
MochiKit.Base.partial(MochiKit.Base.map, Clipperz.Async.collectResults("collectResults", {'_isArchived':MochiKit.Base.methodcaller('isArchived')}, {trace:false})),
Clipperz.Async.collectAll,
function (aResult) {
return MochiKit.Base.filter(function (aRecordInfo) { return aRecordInfo['_isArchived']; }, aResult).length;
}
], {trace:false});
},
getUntaggedCardsCount: function () {
var archivedCardsFilter = this.shouldIncludeArchivedCards()
? MochiKit.Async.succeed
: MochiKit.Base.partial(MochiKit.Base.filter, function (someRecordInfo) { return ! someRecordInfo['_isArchived']; });
return Clipperz.Async.callbacks("MainController.getUntaggedCardsCount", [
MochiKit.Base.method(this.user(), 'getRecords'),
MochiKit.Base.partial(MochiKit.Base.map, Clipperz.Async.collectResults("collectResults", {'_fullLabel':MochiKit.Base.methodcaller('fullLabel'), '_isArchived':MochiKit.Base.methodcaller('isArchived')}, {trace:false})),
Clipperz.Async.collectAll,
archivedCardsFilter,
MochiKit.Base.partial(MochiKit.Base.filter, this.regExpFilterGenerator(Clipperz.PM.DataModel.Record.regExpForNoTag(), '_fullLabel')),
function (someCards) { return someCards.length; },
], {trace:false});
},
//----------------------------------------------------------------------------
setPageProperties: function (aPageName, aKey, aValue) {
var props = {};
props[aKey] = aValue;
this.pages()[aPageName].setProps(props);
return aValue;
},
allTags: function (shouldIncludeArchivedCards) {
return this.user().getTags(shouldIncludeArchivedCards);
},
renderTags: function () {
return Clipperz.Async.callbacks("MainController.renderTags", [
// MochiKit.Base.method(this.user(), 'getTags', this.shouldIncludeArchivedCards()),
MochiKit.Base.method(this, 'allTags', this.shouldIncludeArchivedCards()),
MochiKit.Base.method(this, 'setPageProperties', 'mainPage', 'tags'),
MochiKit.Base.method(this, 'allTags', true || this.shouldIncludeArchivedCards()),
MochiKit.Base.keys,
MochiKit.Base.method(this, 'setPageProperties', 'mainPage', 'allTags'),
MochiKit.Base.method(this, 'getAllCardsCount'),
MochiKit.Base.method(this, 'setPageProperties', 'mainPage', 'allCardsCount'),
MochiKit.Base.method(this, 'getCardsWithCertificateCount'),
MochiKit.Base.method(this, 'setPageProperties', 'mainPage', 'withCertificateCardsCount'),
MochiKit.Base.method(this, 'getCardsWithAttachmentsCount'),
MochiKit.Base.method(this, 'setPageProperties', 'mainPage', 'withAttachmentCardsCount'),
MochiKit.Base.method(this, 'getArchivedCardsCount'),
MochiKit.Base.method(this, 'setPageProperties', 'mainPage', 'archivedCardsCount'),
MochiKit.Base.method(this, 'getUntaggedCardsCount'),
MochiKit.Base.method(this, 'setPageProperties', 'mainPage', 'untaggedCardsCount'),
MochiKit.Base.method(this, 'setPageProperties', 'mainPage', 'shouldIncludeArchivedCards', this.shouldIncludeArchivedCards()),
], {trace:false});
},
renderAccountData: function () {
return Clipperz.Async.callbacks("MainController.renderAccountData", [
MochiKit.Base.method(this, 'setFilter', 'ALL'),
MochiKit.Base.method(this, 'refreshUI', null)
], {trace:false});
},
//=========================================================================
historyReplaceState: function (args) {
if ((window.document.origin != null) && (window.document.origin != "null")) {
window.history.replaceState.apply(window.history, arguments);
}
},
historyPushState: function (args) {
if ((window.document.origin != null) && (window.document.origin != "null")) {
window.history.pushState.apply(window.history, arguments);
}
},
historyState: function (args) {
if ((window.document.origin != null) && (window.document.origin != "null")) {
return window.history.state.apply(window.history, arguments);
}
},
//=========================================================================
runApplication: function (anUser) {
this.historyReplaceState({selectedCardInfo: null}, "", window.location.toString());
this.historyPushState({selectedCardInfo: null}, "", window.location.toString());
this.moveInPage(this.currentPage(), 'mainPage');
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'enableLock');
this.resetLockTimeout();
this.registerHistoryHandler();
return this.renderAccountData();
},
runDirectLogin_handler: function (someParameters) {
var deferredResult;
deferredResult = new Clipperz.Async.Deferred('MainController.runDirectLogin', {trace:false});
deferredResult.addMethod(this.user(), 'getRecord', someParameters['record']);
deferredResult.addMethodcaller('directLoginWithReference', someParameters['directLogin']);
deferredResult.addCallback(Clipperz.PM.UI.DirectLoginController.openDirectLogin);
deferredResult.callback();
return deferredResult;
},
removeDirectLogin_handler: function (someInfo) {
var deferredResult;
var record = someInfo['record'];
var directLoginReference = someInfo['directLoginReference'];
deferredResult = new Clipperz.Async.Deferred("MainController.removeDirectLogin_handler", {'trace': false});
deferredResult.addMethodcaller('directLogins');
deferredResult.addCallback(MochiKit.Base.itemgetter(directLoginReference));
deferredResult.addMethodcaller('remove');
deferredResult.addCallback(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'refreshCardEditDetail', record.reference());
deferredResult.callback(record);
return deferredResult;
},
/*
shouldExitApp: function (anEvent) {
//console.log("SHOULD EXIT APP");
anEvent.preventDefault();
anEvent.stopPropagation();
},
*/
//=========================================================================
/*
showPreferences_handler: function (anEvent) {
var deferredResult;
this.pages()['preferencePage'].setProps({});
deferredResult = new Clipperz.Async.Deferred('MainController.showPreferences', {trace:false});
deferredResult.addMethod(this, 'moveInPage', this.currentPage(), 'preferencePage', true);
deferredResult.callback();
return deferredResult;
},
*/
//=========================================================================
genericErrorHandler: function (anEvent, aMessage, anError) {
var errorMessage;
var result;
result = anError;
// errorMessage = "login failed";
errorMessage = aMessage;
if (anError['isPermanent'] === true) {
this.pages()['errorPage'].setProps({message:anError.message});
this.moveInPage(this.currentPage(), 'errorPage');
errorMessage = "failure";
} else {
if ('pin' in anEvent) {
var errorCount = Clipperz.PM.PIN.recordFailedAttempt();
if (errorCount == -1) {
errorMessage = "PIN resetted";
}
}
}
this.overlay().failed(errorMessage, 1);
return result;
},
//=========================================================================
slidePage: function (fromPage, toPage, direction) {
var fromPosition;
var toPosition;
var itemToTransition;
if (direction == "LEFT") {
fromPosition = 'right';
toPosition = 'left';
itemToTransition = toPage;
} else {
fromPosition = 'left';
toPosition = 'right';
itemToTransition = fromPage;
}
MochiKit.DOM.addElementClass(itemToTransition, 'transition');
MochiKit.Async.callLater(0, function () {
MochiKit.DOM.addElementClass(fromPage, toPosition);
MochiKit.DOM.removeElementClass(toPage, fromPosition);
})
MochiKit.Async.callLater(0.5, function () {
MochiKit.DOM.removeElementClass(itemToTransition, 'transition');
})
},
//.........................................................................
goBack_handler: function () {
var fromPage;
var toPage;
fromPage = this.pageStack().shift();
toPage = this.currentPage();
return Clipperz.Async.callbacks("MainController.goBack_handler", [
MochiKit.Base.method(this.pages()[toPage], 'setProps', {}),
MochiKit.Base.method(this, 'moveOutPage', fromPage, toPage)
], {trace:false});
},
// historyGoBack: function (anEvent) {
// anEvent.preventDefault();
// anEvent.stopPropagation();
// this.goBack();
// },
currentPage: function () {
return this.pageStack()[0];
},
setCurrentPage: function (aPage) {
this.pageStack().unshift(aPage);
this.refreshCurrentPage();
},
moveInPage: function (fromPage, toPage, addToHistory) {
if (fromPage != toPage) {
var shouldAddItemToHistory;
if (this.proxyInfo()['proxyType'] != 'OFFLINE_COPY') {
shouldAddItemToHistory = typeof(addToHistory) == 'undefined' ? false : addToHistory;
} else {
shouldAddItemToHistory = false;
}
this.slidePage(MochiKit.DOM.getElement(fromPage), MochiKit.DOM.getElement(toPage), 'LEFT');
this.setCurrentPage(toPage);
// Skipping push on page change: history needs to be more granular
// New states are pushed on user actions (view card, back to main page, ...)
// if (shouldAddItemToHistory) {
// window.history.pushState({'fromPage': fromPage, 'toPage': toPage}, "");
// } else {
//console.log("Skip HISTORY");
// }
} else {
//console.log("No need to move in the same page");
}
},
moveOutPage: function (fromPage, toPage) {
this.slidePage(MochiKit.DOM.getElement(fromPage), MochiKit.DOM.getElement(toPage), 'RIGHT');
this.setCurrentPage(toPage);
},
//-------------------------------------------------------------------------
featureSet: function () {
return this.userAccountInfo()['featureSet'];
},
features: function () {
// return this.userAccountInfo()['features'];
return Clipperz.PM.Proxy.defaultProxy.features(this.userAccountInfo()['features']);
},
//.........................................................................
userInfo: function () {
var result;
result = {};
result['checkPassphraseCallback'] = MochiKit.Base.bind(this.checkPassphrase, this);
if (this.user() != null) {
result['username'] = this.user().username();
}
return result;
},
userAccountInfo: function () {
var result;
result = {};
if (this.user() != null) {
var usefulFields = [
'currentSubscriptionType',
'expirationDate',
'referenceDate',
'featureSet',
'features',
'isExpired',
'isExpiring',
'paymentVerificationPending',
'attachmentQuota',
'certificateQuota'
];
var attributes = this.user().accountInfo()._attributes;
MochiKit.Iter.forEach(usefulFields, function (aFieldName) {
result[aFieldName] = attributes[aFieldName];
})
};
return result;
},
updateUserAccountInfo_handler: function (anEvent) {
var deferredResult;
deferredResult = new Clipperz.Async.Deferred("updateUserAccountInfo_handler", {trace:false});
deferredResult.addMethod(this.user(), 'updateAccountInfo');
deferredResult.addMethod(this, 'refreshCurrentPage');
deferredResult.callback();
return deferredResult;
},
proxyInfo: function () {
return {
'proxyType': Clipperz.PM.Proxy.defaultProxy.type(),
'proxyTypeDescription': Clipperz.PM.Proxy.defaultProxy.typeDescription()
}
},
attachmentController: function () {
return this._attachmentController;
},
attachmentQueueInfo: function() {
var queue;
var notifications;
var elementFetchCallback;
if (this._attachmentController) {
queue = this._attachmentController.getQueueInfo();
notifications = this._attachmentController.getNotificationsInfo();
elementFetchCallback = MochiKit.Base.method(this._attachmentController, 'getQueueElement');
} else {
queue = [];
notifications = [];
elementFetchCallback = null;
}
return {
'queue': queue,
'notifications': notifications,
'elementFetchCallback': elementFetchCallback,
}
},
//-------------------------------------------------------------------------
messageBoxContent: function () {
var message;
var level;
message = "";
level = 'HIDE';
if (this.featureSet() == 'EXPIRED') {
message = "Expired subscription";
level = 'ERROR';
}
return {
'message': message,
'level': level
};
},
deviceProperties: function () {
return {
'style': this.mediaQueryStyle(),
'isTouchDevice': this.isTouchDevice(),
'isDesktop': this.isDesktop(),
'hasKeyboard': this.hasKeyboard(),
'PIN': Clipperz.PM.PIN
};
},
pageProperties: function (aPageName) {
var result;
var extraProperties = null;
result = this.deviceProperties();
if (this.user() != null) {
result = MochiKit.Base.update(result, {'preferences': this.userPreferences()});
}
if (aPageName == 'loginPage') {
extraProperties = {
'mode': this.loginMode(),
'isNewUserRegistrationAvailable': Clipperz.PM.Proxy.defaultProxy.canRegisterNewUsers(),
'disabled': false,
'proxyInfo': this.proxyInfo(),
};
} else if (aPageName == 'unlockPage') {
extraProperties = {
'mode': this.loginMode(),
'proxyInfo': this.proxyInfo(),
}
} else if (aPageName == 'registrationPage') {
} else if (aPageName == 'mainPage') {
extraProperties = {
'messageBox': this.messageBoxContent(),
'userInfo': this.userInfo(),
'accountInfo': this.userAccountInfo(),
'selectionPanelStatus': this.isSelectionPanelOpen() ? 'OPEN' : 'CLOSED',
'settingsPanelStatus': this.isSettingsPanelOpen() ? 'OPEN' : 'CLOSED',
'attachmentQueueBoxStatus': this.isAttachmentQueueBoxOpen() ? 'OPEN' : 'CLOSED',
'certificateQueueBoxStatus': this.isCertificateQueueBoxOpen() ? 'OPEN' : 'CLOSED',
'featureSet': this.featureSet(),
'features': this.features(),
'proxyInfo': this.proxyInfo(),
'locked': false,
'attachmentQueueInfo': this.attachmentQueueInfo(),
'certificateQueueInfo': this.certificateQueueInfo(),
// 'shouldIncludeArchivedCards': this.shouldIncludeArchivedCards(),
// 'cards': …,
// 'tags': …,
// 'selectedCard': …,
};
} else if (aPageName == 'cardDetailPage') {
extraProperties = {
'attachmentQueueInfo': this.attachmentQueueInfo(),
'certificateQueueInfo': this.certificateQueueInfo(),
'proxyInfo': this.proxyInfo(),
};
} else if (aPageName == 'errorPage') {
extraProperties = {
'message': ''
};
}
result = MochiKit.Base.update(result, extraProperties);
return result;
},
refreshCurrentPage: function () {
if (this.pages()[this.currentPage()] != null) {
this.pages()[this.currentPage()].setProps(this.pageProperties(this.currentPage()));
}
},
//=========================================================================
/*
synchronizeLocalData_handler: function (anEvent) {
var deferredResult;
deferredResult = new Clipperz.Async.Deferred('MainController.synchronizeLocalData', {trace:false});
// deferredResult.addMethod(this.proxy(), 'message', 'downloadAccountData', {});
deferredResult.addMethod(this.user().connection(), 'message', 'downloadAccountData', {});
deferredResult.addCallback(function (aResult) {
Clipperz.PM.DataModel.devicePreferences.setAccountDataWityResponse(aResult);
// localStorage.setItem('clipperz_dump_data', aResult['data']);
// localStorage.setItem('clipperz_dump_version', aResult['version']);
// localStorage.setItem('clipperz_dump_date', new Date());
})
deferredResult.callback();
return deferredResult;
},
*/
//=========================================================================
resetPanels: function () {
this._isSelectionPanelOpen = false;
this._isSettingsPanelOpen = false;
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'closeSettingsPanel');
},
featureAvailableForStyles: function (listOfSupportedStyles) {
return MochiKit.Iter.some(listOfSupportedStyles, MochiKit.Base.partial(MochiKit.Base.operator.eq, this.mediaQueryStyle()));
},
shouldShowCardDetailWhenMovingBetweenCardsUsingKeys: function () {
return !(this.featureAvailableForStyles(['narrow']) && (this.currentPage() == 'mainPage'));
},
isSelectionPanelHidable: function () {
return !this.featureAvailableForStyles(['extra-wide']);
},
isSelectionPanelOpen: function () {
return this._isSelectionPanelOpen;
},
toggleSelectionPanel_handler: function (anEvent) {
if (this.isSelectionPanelHidable() == true) {
if (this.currentPage() == 'cardDetailPage') {
this.goBackToMainPage();
}
this._isSelectionPanelOpen = !this._isSelectionPanelOpen;
this.setCloseMaskAction(MochiKit.Base.method(this, 'toggleSelectionPanel_handler'));
this.refreshCurrentPage();
}
},
hideSelectionPanel_handler: function (anEvent) {
return Clipperz.Async.callbacks("MainController.hideSelectionPanel_handler", [
MochiKit.Base.bind(function () {
if (this.isSelectionPanelOpen()) {
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'toggleSelectionPanel');
}
}, this)
], {trace:false});
},
isSettingsPanelOpen: function () {
return this._isSettingsPanelOpen;
},
toggleSettingsPanel_handler: function (anEvent) {
return Clipperz.Async.callbacks("MainController.toggleSettingsPanel_handler", [
MochiKit.Base.bind(function () {
this._isSettingsPanelOpen = !this._isSettingsPanelOpen;
this.setCloseMaskAction(MochiKit.Base.method(this, 'toggleSettingsPanel_handler'));
if (this._isSettingsPanelOpen == false) {
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'closeSettingsPanel');
}
this.refreshCurrentPage();
}, this)
], {trace:false});
},
isAttachmentQueueBoxOpen: function() {
return this._isAttachmentQueueBoxOpen;
},
toggleAttachmentQueueBox_handler: function (anEvent) {
return Clipperz.Async.callbacks("MainController.toggleAttachmentQueueBox_handler", [
MochiKit.Base.bind(function () {
this._isAttachmentQueueBoxOpen = !this._isAttachmentQueueBoxOpen;
this._isCertificateQueueBoxOpen = false;
this.refreshCurrentPage();
}, this)
], {trace:false});
},
//----------------------------------------------------------------------------
isCertificateQueueBoxOpen: function() {
return this._isCertificateQueueBoxOpen;
},
toggleCertificateQueueBox_handler: function (anEvent) {
return Clipperz.Async.callbacks("MainController.toggleCertificateQueueBox_handler", [
MochiKit.Base.bind(function () {
this._isCertificateQueueBoxOpen = !this._isCertificateQueueBoxOpen;
this._isAttachmentQueueBoxOpen = false;
this.refreshCurrentPage();
}, this)
], {trace:false});
},
//----------------------------------------------------------------------------
selectedCardInfo: function () {
return this._selectedCardInfo;
},
selectedCardIndex: function () {
var selectedCardInfo;
var result;
result = -1;
selectedCardInfo = this.selectedCardInfo();
if (selectedCardInfo != null) {
var selectedCards;
var reference;
var i, c;
selectedCards = this.selectedCards();
reference = selectedCardInfo['reference'];
c = selectedCards.length;
i = 0;
while (i<c && result == -1) {
if (selectedCards[i]['_reference'] == reference) {
result = i;
} else {
i++;
}
}
}
return result;
},
cardInfoAtIndex: function (anIndex) {
var card;
card = this.selectedCards()[anIndex];
return {
'label': card['label'],
'reference': card['_reference']
};
},
previousCardInfo: function () {
var currentIndex;
var nextIndex;
var result;
currentIndex = this.selectedCardIndex();
if (currentIndex == -1) {
nextIndex = this.selectedCards().length - 1;
} else {
nextIndex = Math.max(currentIndex - 1, 0);
}
if (currentIndex == nextIndex) {
result = null;
} else {
result = this.cardInfoAtIndex(nextIndex);
}
return result;
},
nextCardInfo: function () {
var currentIndex;
var nextIndex;
var result;
currentIndex = this.selectedCardIndex();
if (currentIndex == -1) {
nextIndex = 0;
} else {
nextIndex = Math.min(currentIndex + 1, this.selectedCards().length - 1);
}
if (currentIndex == nextIndex) {
result = null;
} else {
result = this.cardInfoAtIndex(nextIndex);
}
return result;
},
//............................................................................
goBackToMainPage: function (anEvent) {
if (this.currentPage() == 'cardDetailPage') {
var resetSelection = null;
this.updateSelectedCard(resetSelection, true, false);
this.moveOutPage(this.currentPage(), 'mainPage');
}
},
selectCard: function (someInfo, shouldUpdateCardDetail) {
var result;
if (this.featureSet() != 'EXPIRED') {
this._selectedCardInfo = someInfo;
this.refreshSelectedCards();
result = this.updateSelectedCard(someInfo, true, shouldUpdateCardDetail);
// # TODO: make the selected element visible;
// this may not always be the case, as selection can also be changed using keys.
// MochiKit.Visual.ScrollTo(MochiKit.DOM.getElement("xxx"));
} else {
result = MochiKit.Async.succeed();
};
return result;
},
resetSelectedCard: function () {
this._selectedCardInfo = null;
},
selectCard_handler: function (someInfo) {
var cardInfo = someInfo['cardInfo'];
var shouldUpdateCardDetail = someInfo['update'];
return Clipperz.Async.callbacks("MainController.selectCard_handler", [
MochiKit.Base.method(this, 'selectCard', cardInfo, shouldUpdateCardDetail),
MochiKit.Base.method(this, 'historyPushState', {selectedCardInfo: cardInfo}, "", window.location.toString())
], {trace:false});
},
blockDragOver: function (anEvent) {
anEvent.stopPropagation();
anEvent.preventDefault();
anEvent.dataTransfer.dropEffect = 'none';
},
refreshCardEditDetail_handler: function (aRecordReference) {
return Clipperz.Async.callbacks("MainController.refreshCardEditDetail_handler", [
MochiKit.Base.method(this, 'updateSelectedCard', {'reference':aRecordReference}, false, true)
], {trace:false});
},
//----------------------------------------------------------------------------
downloadExport_handler: function () {
var exportController;
var deferredResult;
exportController = new Clipperz.PM.UI.ExportController();
deferredResult = new Clipperz.Async.Deferred("MainController.downloadExport_handler", {trace: false});
deferredResult.addMethod(this.overlay(), 'show', "loading …", true, true);
deferredResult.addMethod(this.user(), 'getRecordsLoadingAllData');
deferredResult.addCallbackPass(MochiKit.Base.method(this.overlay(), 'show', "exporting …", true, true));
deferredResult.addMethod(exportController, 'run');
deferredResult.addMethod(this.overlay(), 'done', "", 1);
deferredResult.callback();
return deferredResult;
},
//----------------------------------------------------------------------------
changePassphrase_handler: function(newPassphrase) {
var currentPage = this.pages()[this.currentPage()];
var deferredResult;
var getPassphraseDelegate;
var user;
getPassphraseDelegate = MochiKit.Base.partial(MochiKit.Async.succeed, newPassphrase);
user = new Clipperz.PM.DataModel.User({'username':this.user().username(), 'getPassphraseFunction':getPassphraseDelegate});
deferredResult = new Clipperz.Async.Deferred("MainController.changePassphrase_handler", {trace: false});
deferredResult.addMethod(this.overlay(), 'show', "changing …", true);
deferredResult.addMethod(this.user(), 'changePassphrase', getPassphraseDelegate);
deferredResult.addMethod(user, 'login');
deferredResult.addMethod(this, 'setUser', user);
deferredResult.addMethod(this.overlay(), 'done', "saved", 1);
deferredResult.callback();
return deferredResult;
},
deleteAccount_handler: function() {
var deferredResult;
var doneMessageDelay = 2;
deferredResult = new Clipperz.Async.Deferred("MainController.deleteAccount_handler", {trace: false});
deferredResult.addCallback(MochiKit.Base.method(this, 'ask', {
'question': "Do you really want to permanently delete your account?",
'possibleAnswers':{
'cancel': {'label':"No", 'isDefault':true, 'answer':MochiKit.Base.methodcaller('cancel', new MochiKit.Async.CancelledError())},
'revert': {'label':"Yes", 'isDefault':false, 'answer':MochiKit.Base.methodcaller('callback')}
}
})),
deferredResult.addMethod(this.overlay(), 'show', "deleting …", true);
deferredResult.addMethod(this.user(), 'deleteAccount');
deferredResult.addMethod(this.overlay(), 'done', "deleted", doneMessageDelay);
deferredResult.addCallback(MochiKit.Async.callLater, doneMessageDelay, function() { window.location.href = '/'; });
deferredResult.callback();
return deferredResult;
},
//----------------------------------------------------------------------------
userPreferences: function () {
return this._userPreferences;
},
setUserPreferences: function (someValues) {
this._userPreferences = someValues;
return someValues;
},
updateUserPreferences: function() {
return Clipperz.Async.callbacks("MainController.updateUserPreferences", [
MochiKit.Base.method(this.user(), 'getPreferences'),
MochiKit.Base.method(this, 'setUserPreferences'),
], {trace:false});
},
setPreferences_handler: function(anObject) {
return Clipperz.Async.callbacks("MainController.setPreferences_handler", [
MochiKit.Base.method(this.overlay(), 'show', "", true),
MochiKit.Base.method(this.user(), 'setPreferences', anObject),
MochiKit.Base.method(this, 'updateUserPreferences'),
MochiKit.Base.method(this, 'refreshCurrentPage'),
MochiKit.Base.method(this.overlay(), 'done', "", 0.5),
], {trace:false});
},
//----------------------------------------------------------------------------
importCards_handler: function(data) {
return Clipperz.Async.callbacks("MainController.importCards_handler", [
MochiKit.Base.method(this.overlay(), 'show', "importing …", true),
MochiKit.Base.partial(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'toggleSettingsPanel'),
function () { return data; },
MochiKit.Base.method(this,'importCards'),
MochiKit.Base.method(this.overlay(), 'done', "finished", 1),
MochiKit.Base.method(this.pages()[this.currentPage()], 'setProps', {'mode':'view', 'showGlobalMask':false}),
], {trace:false});
},
importCards: function(data) {
return Clipperz.Async.callbacks("MainController.importCards", [
function () { return data; },
MochiKit.Base.partial(MochiKit.Base.map, MochiKit.Base.method(this.user(), 'createNewRecordFromJSON')),
Clipperz.Async.collectAll,
MochiKit.Base.method(this.user(), 'saveChanges'),
MochiKit.Base.partial(MochiKit.Base.method(this, 'resetRecordsInfo')),
MochiKit.Base.partial(MochiKit.Base.method(this, 'refreshUI', null)),
], {trace:false});
},
//----------------------------------------------------------------------------
updateOTPListAndDetails: function() {
return Clipperz.Async.callbacks("MainController.updateOTPListAndDetails", [
Clipperz.Async.collectResults("MainController.updateOTPListAndDetails <inner results>", {
'userInfo': MochiKit.Base.method(this, 'userInfo'),
'otpDetails': Clipperz.Async.collectResults("User.updateOTPListAndDetails <otpDetails>", {
'otpList': MochiKit.Base.method(this.user(),'getOneTimePasswords'),
'otpsDetails': MochiKit.Base.method(this.user(),'getOneTimePasswordsDetails'),
}),
}, {trace:false}),
function (someData) {
return MochiKit.Base.update(someData['userInfo'], someData['otpDetails']);
},
MochiKit.Base.bind(function(someUserInfo) {
this.setPageProperties('mainPage', 'userInfo', someUserInfo);
}, this)
], {trace:false});
},
/* Used only one time (the first time the OTP ExtraFeature loads), other times
the list update is triggered by other operations. Maybe the first OTP list retrieval
could be done during init, so that this would not be necessary. */
updateOTPListAndDetails_handler: function () {
return this.updateOTPListAndDetails();
},
createNewOTP_handler: function () {
return Clipperz.Async.callbacks("MainController.createNewOTP_handler", [
MochiKit.Base.method(this.overlay(), 'show', "", true),
MochiKit.Base.method(this.user(), 'createNewOTP'),
MochiKit.Base.method(this, 'updateOTPListAndDetails'),
MochiKit.Base.method(this.overlay(), 'done', "", 0.5),
], {trace:false});
},
deleteOTPs_handler: function (aList) {
return Clipperz.Async.callbacks("MainController.deleteOTPs_handler", [
MochiKit.Base.method(this.overlay(), 'show', "", true),
MochiKit.Base.method(this.user(), 'deleteOTPs', aList),
MochiKit.Base.method(this, 'updateOTPListAndDetails'),
MochiKit.Base.method(this.overlay(), 'done', "", 0.5),
], {trace:false});
},
changeOTPLabel_handler: function (someInfo) {
var reference = someInfo['reference'];
var label = someInfo['label'];
return Clipperz.Async.callbacks("MainController.changeOTPLabel_handler", [
MochiKit.Base.method(this.overlay(), 'show', "", true),
MochiKit.Base.method(this.user(), 'changeOTPLabel', reference, label),
MochiKit.Base.method(this, 'updateOTPListAndDetails'),
MochiKit.Base.method(this.overlay(), 'done', "", 0.5),
], {trace:false});
},
//----------------------------------------------------------------------------
saveChanges: function () {
// TODO: handle errors while savings
return Clipperz.Async.callbacks("MainController.saveChanges", [
MochiKit.Base.method(this.overlay(), 'show', "saving …", true),
MochiKit.Base.method(this.user(), 'saveChanges'),
MochiKit.Base.method(this, 'resetRecordsInfo'),
MochiKit.Base.method(this.overlay(), 'done', "saved", 1),
], {trace:false});
},
saveCardEdits_handler: function (aRecordReference) {
var currentPage = this.pages()[this.currentPage()];
var self = this;
var record, wasBrandNew;
return Clipperz.Async.callbacks("MainController.saveCardEdits_handler", [
MochiKit.Base.method(currentPage, 'setProps', {'showGlobalMask':true}),
MochiKit.Base.method(this.user(), 'getRecord', aRecordReference),
function(aRecord) { record = aRecord; wasBrandNew = aRecord.isBrandNew(); },
MochiKit.Base.method(this, 'saveChanges'),
// When new record has attachments, server status should be updated as soon as it is available
function() { return wasBrandNew; },
Clipperz.Async.deferredIf('WasBrandNew',[
function() { return record; },
MochiKit.Base.method(this, 'reloadAttachmentServerStatusCallback')
], [
// MochiKit.Async.succeed
]),
MochiKit.Base.method(currentPage, 'setProps', {'mode':'view', 'showGlobalMask':false}),
MochiKit.Base.method(this, 'refreshUI', aRecordReference),
MochiKit.Base.partial(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'enableLock'),
], {trace:false});
},
cancelCardEdits_handler: function (aRecordReference) {
return this.cancelCardEdits(aRecordReference);
},
cancelCardEdits: function (aRecordReference) {
var currentPage = this.pages()[this.currentPage()];
var self = this;
var wasBrandNew;
return Clipperz.Async.callbacks("MainController.cancelCardEdits_handler", [
MochiKit.Base.method(this.user(), 'getRecord', aRecordReference),
MochiKit.Base.methodcaller('isBrandNew'),
function (aValue) { wasBrandNew = aValue },
MochiKit.Base.method(this.user(), 'hasPendingChanges'),
Clipperz.Async.deferredIf('HasPendingChanges',[
MochiKit.Base.method(self, 'ask', {
'question': "There are pending changes to your card. Ignore changes?",
'possibleAnswers':{
'cancel': {'label':"No", 'isDefault':true, 'answer':MochiKit.Base.methodcaller('cancel', new MochiKit.Async.CancelledError())},
'revert': {'label':"Yes", 'isDefault':false, 'answer':MochiKit.Base.methodcaller('callback')}
}
}),
], [
// MochiKit.Async.succeed
]),
MochiKit.Base.method(this.user(), 'revertChanges'),
MochiKit.Base.method(currentPage, 'setProps', {'mode':'view'}),
MochiKit.Base.bind(function () {
var info;
if (wasBrandNew == true) {
info = null;
} else {
info = {'reference': aRecordReference};
}
this.updateSelectedCard(info, false, true);
}, this),
MochiKit.Base.bind(function () {
if ((wasBrandNew == true) && (this.currentPage() == 'cardDetailPage')) {
this.goBackToMainPage();
}
},this),
MochiKit.Base.partial(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'enableLock'),
], {trace:false});
},
//----------------------------------------------------------------------------
ask: function (someInfo) {
var deferredResult;
var currentPage = this.pages()[this.currentPage()];
deferredResult = new Clipperz.Async.Deferred('MainController.ask', {trace:false});
currentPage.setProps({'ask': {'info': someInfo, 'deferred':deferredResult}, 'showGlobalMask':true });
deferredResult.addBothPass(MochiKit.Base.method(currentPage, 'setProps', {'ask': null, 'showGlobalMask':false }));
return deferredResult;
},
//----------------------------------------------------------------------------
addCardClick_handler: function () {
var newRecord;
this.selectAllCards();
return Clipperz.Async.callbacks("MainController.addCardClick_handler", [
MochiKit.Base.method(this.user(), 'createNewRecord'),
function (aValue) {
newRecord = aValue;
return newRecord;
},
// MochiKit.Base.methodcaller('addField', {'label':"username", 'value':"", 'hidden':false}),
// function () { return newRecord; },
// MochiKit.Base.methodcaller('addField', {'label':"password", 'value':"", 'hidden':true}),
// function () { return newRecord; },
MochiKit.Base.methodcaller('reference'),
MochiKit.Base.method(this, 'refreshUI'),
function () { return newRecord; },
MochiKit.Base.methodcaller('reference'),
MochiKit.Base.bind(function (aRecordReference) {
return this.selectCard({
'reference': aRecordReference,
'label': ""
}, true);
}, this),
MochiKit.Base.method(this, 'enterEditMode'),
], {trace:false});
},
deleteCard_handler: function (anEvent) {
var self = this;
return Clipperz.Async.callbacks("MainController.deleteCard_handler", [
MochiKit.Base.method(self, 'ask', {
'question': "Delete card?",
'possibleAnswers':{
'cancel': {'label':"No", 'isDefault':true, 'answer':MochiKit.Base.methodcaller('cancel', new MochiKit.Async.CancelledError())},
'delete': {'label':"Yes", 'isDefault':false, 'answer':MochiKit.Base.methodcaller('callback')}
}
}),
MochiKit.Base.method(this.user(), 'getRecord', anEvent['reference']),
MochiKit.Base.method(this.user(), 'deleteRecord'),
MochiKit.Base.method(this, 'saveChanges'),
MochiKit.Base.method(this, 'exitCurrentSelection'),
MochiKit.Base.method(this, 'refreshUI')
], {trace:false});
},
toggleArchiveCard_handler: function (anEvent) {
return Clipperz.Async.callbacks("MainController.archiveCard_handler", [
MochiKit.Base.method(this.user(), 'getRecord', anEvent['reference']),
MochiKit.Base.methodcaller('toggleArchive'),
MochiKit.Base.method(this, 'saveChanges'),
MochiKit.Base.method(this, 'refreshUI', anEvent['reference'])
], {trace:false});
},
cloneCard_handler: function (anEvent) {
var cardInfo;
return Clipperz.Async.callbacks("MainController.cloneCard_handler", [
MochiKit.Base.method(this.user(), 'getRecord', anEvent['reference']),
MochiKit.Base.method(this.user(), 'cloneRecord'),
Clipperz.Async.collectResults("MainController.cloneCard_handler <card info>", {
'label': MochiKit.Base.methodcaller('label'),
'reference': MochiKit.Base.methodcaller('reference')
}, {trace:false}),
function (aValue) { cardInfo = aValue; return aValue; },
MochiKit.Base.method(this, 'saveChanges'),
function () {
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'selectCard', {'cardInfo':cardInfo, 'update':false});
},
function (aValue) { return cardInfo['reference']; },
MochiKit.Base.method(this, 'refreshUI'),
], {trace:false});
},
isPageInEditMode: function() {
var currentPage = this.pages()[this.currentPage()];
return currentPage ? currentPage.props['mode'] == 'edit' : false;
},
enterEditMode: function () {
var currentPage = this.pages()[this.currentPage()];
currentPage.setProps({'mode': 'edit'});
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'disableLock');
return Clipperz.Async.callbacks("MainController.enterEditMode", [
MochiKit.Base.method(this, 'allTags', true),
MochiKit.Base.keys,
function (aValue) {
currentPage.setProps({'allTags': aValue});
},
], {trace:false});
},
editCard_handler: function (anEvent) {
this.enterEditMode();
},
certificateDetails: function (aRecordReference) {
return Clipperz.Async.callbacks("MainController.certificateDetails", [
Clipperz.Async.collectResults("MainController.certificateDetails <inner results>", {
'wallet': MochiKit.Base.method(this.user(), 'getWallet'),
'record': MochiKit.Base.method(this.user(), 'getRecord', aRecordReference),
}, {trace:false}),
Clipperz.Async.collectResults("MainController.showCertificatePreview_handler <inner results>", {
'transaction': function (someValues) { return someValues['record'].computeCertificateInfo(someValues['wallet']); },
'metadata': [
MochiKit.Base.itemgetter('record'),
MochiKit.Base.methodcaller('certificateMetadata'),
Clipperz.Base.evalJSON
]
}, {trace:false}),
], {trace:false});
},
downloadCertificate_handler: function (aRecordReference) {
//console.log("DOWNLOAD CERTIFICATE", aRecordReference);
var certificateDownloadController;
var deferredResult;
certificateDownloadController = new Clipperz.PM.UI.CertificateDownloadController();
deferredResult = new Clipperz.Async.Deferred("MainController.downloadCertificate_handler", {trace: false});
deferredResult.addMethod(this.overlay(), 'show', "", true, false);
deferredResult.addMethod(this.user(), 'getRecord', aRecordReference);
deferredResult.collectResults({
'attachments': MochiKit.Base.methodcaller('attachmentsInfo'),
'certificateInfo': MochiKit.Base.methodcaller('certificateInfo'),
'certificateDetails': MochiKit.Base.method(this, 'certificateDetails', aRecordReference),
}, {trace:false});
deferredResult.addMethod(certificateDownloadController, 'run');
deferredResult.addMethod(this.overlay(), 'done', "", 1);
deferredResult.callback();
return deferredResult;
},
showCertificatePreview_handler: function (aRecordReference) {
var currentPage = this.pages()[this.currentPage()];
currentPage.setProps({'showCertificatePreview': true});
return Clipperz.Async.callbacks("MainController.showCertificatePreview_handler", [
MochiKit.Base.method(this, 'certificateDetails', aRecordReference),
function (aValue) {
currentPage.setProps({'certificateDetails': aValue});
},
], {trace:false});
},
hideCertificatePreview_handler: function (aRecordReference) {
return Clipperz.Async.callbacks("MainController.hideCertificatePreview_handler", [
MochiKit.Base.method(this.pages()[this.currentPage()], 'setProps', {'showCertificatePreview': false})
], {trace:false});
},
createCertificate_handler: function (anEvent) {
//console.log("CREATE CERTIFICATE HANDLER", anEvent);
//console.log("CREATE CERTIFICATE", this.user().accountInfo(), this.userAccountInfo());
var certificateQuota = this.userAccountInfo()['certificateQuota'];
var availableCertificates =
certificateQuota['totalNumber']
- (certificateQuota['used']['published'] + certificateQuota['used']['requested']);
var result;
var self = this;
if (availableCertificates > 0) {
var documentID;
//console.log("CREATE CERTIFICATE - availableCertificates", availableCertificates);
result = Clipperz.Async.callbacks("MainController.createCertificate_handler [option A]", [
MochiKit.Base.method(self, 'ask', {
'question': "Create certificate?",
'description': [
React.DOM.p({'className':'cardCertificateWarning'}, "You are going to register the content of this card on the Bitcoin blockchain."),
React.DOM.p({'className':'cardCertificateWarning'}, "Afterward you won't be able to make any change, so make sure the card contains all the desired data and files before proceeding."),
React.DOM.p({'className':'cardCertificateWarning'}, availableCertificates + " registrations left"),
],
'possibleAnswers':{
'cancel': {'label':"Cancel", 'isDefault':false, 'answer':MochiKit.Base.methodcaller('cancel', new MochiKit.Async.CancelledError())},
'delete': {'label':"Continue",'isDefault':true, 'answer':MochiKit.Base.methodcaller('callback')}
}
}),
MochiKit.Base.method(this.overlay(), 'show', "registering", true),
MochiKit.Base.method(this.user(), 'getRecord', anEvent['reference']),
MochiKit.Base.method(this.user(), 'createCertificateForRecord'),
MochiKit.Base.method(this.user(), 'saveChangesWithExtraParameters'),
MochiKit.Base.method(this.user(), 'getRecord', anEvent['reference']),
MochiKit.Base.methodcaller('updateCertificateInfo'),
MochiKit.Base.method(this.overlay(), 'done', "", 1),
MochiKit.Base.method(this, 'updateCertificateQueueInfo'),
MochiKit.Base.method(this, 'resetRecordsInfo'),
MochiKit.Base.method(this, 'refreshUI', anEvent['reference']),
], {trace:false});
} else {
result = Clipperz.Async.callbacks("MainController.createCertificate_handler [option B]", [
MochiKit.Base.method(self, 'ask', {
'question': "Sorry, registration not available",
'description': [
React.DOM.p({'className':'cardCertificateWarning'}, "You can't register this card on the Bitcoin blockchain because you have already consumed all your quota. Replenish your supply!"),
],
'possibleAnswers':{
'cancel': {'label':"Ok", 'isDefault':false, 'answer':MochiKit.Base.methodcaller('cancel', new MochiKit.Async.CancelledError())},
// 'subscribe': {'label':"Upgrade", 'isDefault':true, 'answer':MochiKit.Base.noop, 'disabled':true}
}
}),
], {trace:false});
}
return result;
},
//...........................................................................
updateCertificateQueueInfo: function () {
return Clipperz.Async.callbacks("MainController.updateCertificateQueueInfo", [
MochiKit.Base.method(this.user().connection(), 'message', 'getCertificatesStatus', {}),
MochiKit.Base.bind(function (certificatesStatus) {
return MochiKit.Base.map(MochiKit.Base.bind(function (certificateStatus) {
var matchingRecords;
var result;
matchingRecords = MochiKit.Base.filter(function (aRecordInfo) { return aRecordInfo['_reference'] == certificateStatus[0]; }, this._recordsInfo);
if (matchingRecords.length == 1) {
result = {'reference':certificateStatus[0], 'status':certificateStatus[1], 'label':matchingRecords[0]['label']};
} else {
result = null;
}
return result;
}, this), MochiKit.Base.zip(MochiKit.Base.keys(certificatesStatus), MochiKit.Base.values(certificatesStatus)));
}, this),
MochiKit.Base.method(this, '_updatedCertificateQueueInfo'),
MochiKit.Base.method(this, 'setPageProperties', 'mainPage', 'certificateQueueInfo'),
MochiKit.Base.method(this, 'setPageProperties', 'cardDetailPage', 'certificateQueueInfo'),
], {trace:false});
},
_updatedCertificateQueueInfo: function (newQueueStatus) {
var hasPendingPublishingCertificate;
this._certificateQueueStatus = newQueueStatus;
hasPendingPublishingCertificate = MochiKit.Iter.some(this._certificateQueueStatus, function (anInfo) { return (anInfo && (anInfo['status'] == 'requested')); });
//console.log("hasPendingPublishingCertificate", hasPendingPublishingCertificate);
if (hasPendingPublishingCertificate) {
//console.log("Rescheduled call to 'updateCertificateQueueInfo'");
MochiKit.Async.callLater(10 * 60, MochiKit.Base.method(this, 'updateCertificateQueueInfo'));
}
return this._certificateQueueStatus;
},
certificateQueueInfo: function() {
return this._certificateQueueStatus;
},
closeCertificateNotification_handler: function (aRecordReference) {
return Clipperz.Async.callbacks("MainController.closeCertificateNotification_handler", [
MochiKit.Base.method(this.user().connection(), 'message', 'acknowledgeCertificateStatus', {'reference':aRecordReference}),
MochiKit.Base.method(this, 'updateCertificateQueueInfo'),
], {trace:false});
},
showCertificateCard_handler: function (aRecordReference) {
console.log("showCertificateCard_handler");
return Clipperz.Async.callbacks("MainController.showCertificateCard_handler", [
// MochiKit.Base.bind(function () { this._isAttachmentQueueBoxOpen = false; }, this),
MochiKit.Base.method(this, 'selectCard_handler', {'cardInfo': {'reference':aRecordReference}, 'update': true}),
], {trace:false});
},
//===========================================================================
addTag_handler: function (anEvent) {
var record = this.pages()[this.currentPage()].props['selectedCard']['_record'];
var tag = anEvent;
var deferredResult;
deferredResult = new Clipperz.Async.Deferred('MainController.addTag', {trace:false});
deferredResult.addMethod(record, 'addTag', tag);
deferredResult.addMethod(this, 'collectRecordInfo', record);
deferredResult.addMethod(this, 'setPageProperties', this.currentPage(), 'selectedCard');
// deferredResult.addMethod(this, 'refreshCurrentPage');
deferredResult.callback();
return deferredResult;
},
removeTag_handler: function (anEvent) {
var record = this.pages()[this.currentPage()].props['selectedCard']['_record'];
var tag = anEvent;
var deferredResult;
deferredResult = new Clipperz.Async.Deferred('MainController.removeTag', {trace:false});
deferredResult.addMethod(record, 'removeTag', tag);
deferredResult.addMethod(this, 'collectRecordInfo', record);
deferredResult.addMethod(this, 'setPageProperties', this.currentPage(), 'selectedCard');
// deferredResult.addMethod(this, 'refreshCurrentPage');
deferredResult.callback();
return deferredResult;
},
goBackToMainPage_handler: function (anEvent) {
return Clipperz.Async.callbacks("MainController.goBackToMainPage_handler", [
MochiKit.Base.method(this, 'goBackToMainPage', anEvent),
MochiKit.Base.method(this, 'historyPushState', {selectedCardInfo: null}, "", window.location.toString())
], {trace:false});
},
//============================================================================
selectAllCards_handler: function () {
return Clipperz.Async.callbacks("MainController.selectAllCards_handler", [
MochiKit.Base.method(this, 'selectAllCards')
], {trace:false});
},
selectAllCards: function () {
this.setPageProperties('mainPage', 'searchTerm', '');
this.resetSelectedCard();
this.setFilter('ALL');
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'hideSelectionPanel');
return this.refreshSelectedCards();
},
selectRecentCards_handler: function () {
return Clipperz.Async.callbacks("MainController.selectRecentCards_handler", [
MochiKit.Base.method(this, 'resetSelectedCard'),
MochiKit.Base.method(this, 'setFilter', 'RECENT'),
MochiKit.Base.partial(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'hideSelectionPanel'),
MochiKit.Base.method(this, 'refreshSelectedCards')
], {trace:false});
},
selectCardsWithCertificate_handler: function () {
return Clipperz.Async.callbacks("MainController.selectCardsWithCertificate_handler", [
MochiKit.Base.method(this, 'resetSelectedCard'),
MochiKit.Base.method(this, 'setFilter', 'WITH_CERTIFICATE'),
MochiKit.Base.partial(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'hideSelectionPanel'),
MochiKit.Base.method(this, 'refreshSelectedCards')
], {trace:false});
},
selectCardsWithAttachments_handler: function () {
return Clipperz.Async.callbacks("MainController.selectCardsWithAttachments_handler", [
MochiKit.Base.method(this, 'resetSelectedCard'),
MochiKit.Base.method(this, 'setFilter', 'WITH_ATTACHMENTS'),
MochiKit.Base.partial(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'hideSelectionPanel'),
MochiKit.Base.method(this, 'refreshSelectedCards')
], {trace:false});
},
search_handler: function (aValue) {
var searchType;
if (aValue == "") {
searchType = 'ALL';
} else {
searchType = 'SEARCH';
}
return Clipperz.Async.callbacks("MainController.search_handler", [
MochiKit.Base.method(this, 'resetSelectedCard'),
MochiKit.Base.method(this, 'setFilter', searchType, aValue),
MochiKit.Base.method(this, 'setPageProperties', 'mainPage', 'searchTerm', aValue),
MochiKit.Base.method(this, 'refreshSelectedCards')
], {trace:false});
},
tagSelected_handler: function (aTag) {
return Clipperz.Async.callbacks("MainController.tagSelected_handler", [
MochiKit.Base.method(this, 'resetSelectedCard'),
MochiKit.Base.method(this, 'setFilter', 'TAG', aTag),
MochiKit.Base.partial(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'hideSelectionPanel'),
MochiKit.Base.method(this, 'refreshSelectedCards')
], {trace:false});
},
selectUntaggedCards_handler: function () {
return Clipperz.Async.callbacks("MainController.selectUntaggedCards_handler", [
MochiKit.Base.method(this, 'resetSelectedCard'),
MochiKit.Base.method(this, 'setFilter', 'UNTAGGED'),
MochiKit.Base.partial(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'hideSelectionPanel'),
MochiKit.Base.method(this, 'refreshSelectedCards')
], {trace:false});
},
//............................................................................
showArchivedCards_handler: function () {
return Clipperz.Async.callbacks("MainController.showArchivedCards_handler", [
MochiKit.Base.method(this, 'setShouldIncludeArchivedCards', true),
MochiKit.Base.method(this, 'refreshUI')
], {trace:false});
},
hideArchivedCards_handler: function () {
return Clipperz.Async.callbacks("MainController.hideArchivedCards_handler", [
MochiKit.Base.method(this, 'setShouldIncludeArchivedCards', false),
MochiKit.Base.method(this, 'refreshUI')
], {trace:false});
},
//----------------------------------------------------------------------------
setCloseMaskAction: function (aFunction) {
this._closeMaskAction = aFunction;
},
maskClick_handler: function () {
return Clipperz.Async.callbacks("MainController.maskClick_handler", [
MochiKit.Base.bind(function () {
this._closeMaskAction.apply(this);
this._closeMaskAction = null;
}, this)
], {trace:false});
},
//............................................................................
showHelp_handler: function () {
return Clipperz.Async.callbacks("MainController.showHelp_handler", [
MochiKit.Base.bind(function () {
if (this.currentPage() == 'mainPage') {
this.setPageProperties(this.currentPage(), 'showHelp', true);
}
}, this)
], {trace:false});
},
closeHelp_handler: function () {
return Clipperz.Async.callbacks("MainController.closeHelp_handler", [
MochiKit.Base.method(this, 'setPageProperties', this.currentPage(), 'showHelp', false)
], {trace:false});
},
isShowingHelp: function () {
return this.pages()[this.currentPage()].props['showHelp'];
},
//============================================================================
matchMediaQuery_handler: function (newQueryStyle) {
var wasInEditMode = this.isPageInEditMode();
var currentPage = this.currentPage();
var selectedCardInfo = this.selectedCardInfo();
this._mediaQueryStyle = newQueryStyle;
MochiKit.DOM.setElementClass(document.body, newQueryStyle);
if (currentPage == 'cardDetailPage') {
this.moveOutPage(this.currentPage(), 'mainPage');
}
if (selectedCardInfo) {
this.pages()[currentPage].setProps({'mode': 'view'});
if (currentPage == 'mainPage' && newQueryStyle == 'narrow') {
this.selectCard(selectedCardInfo, true);
}
if (wasInEditMode) {
MochiKit.Async.callLater(0.1, MochiKit.Base.method(this, 'enterEditMode'));
MochiKit.Async.callLater(0.1, MochiKit.Base.method(this, 'updateSelectedCard', this.selectedCardInfo(), false, true));
}
}
this.resetPanels();
this.refreshCurrentPage();
},
unmatchMediaQuery_handler: function (queryStyle) {
},
mediaQueryStyle: function () {
return this._mediaQueryStyle;
},
//----------------------------------------------------------------------------
isTouchDevice: function () {
return this._isTouchDevice;
},
isDesktop: function () {
return this._isDesktop;
},
hasKeyboard: function () {
return this._hasKeyboard;
},
//============================================================================
downloadOfflineCopy_handler: function (anEvent) {
var downloadHref;
var deferredResult;
var newWindow;
downloadHref = window.location.href.replace(/\/[^\/]*$/,'') + Clipperz_dumpUrl;
newWindow = window.open("", "");
deferredResult = new Clipperz.Async.Deferred("AppController.handleDownloadOfflineCopy", {trace:false});
deferredResult.addCallback(MochiKit.Base.method(this.user().connection(), 'message'), 'echo', {'echo':"echo"});
deferredResult.addCallback(function(aWindow) {
aWindow.location.href = downloadHref;
}, newWindow);
deferredResult.callback();
return deferredResult;
},
//============================================================================
focusOnSearch: function (anEvent) {
anEvent.preventDefault();
if (this.pages()[this.currentPage()].props['mode'] == 'edit') {
// pass
} else {
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'toggleSelectionPanel');
MochiKit.DOM.getElement('searchValue').focus();
MochiKit.DOM.getElement('searchValue').select();
}
},
exitSearch_handler: function (anEvent) {
return Clipperz.Async.callbacks("MainController.exitSearch_handler", [
MochiKit.Base.partial(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'toggleSelectionPanel'),
MochiKit.Base.method(MochiKit.DOM.getElement('searchValue'), 'blur')
], {trace:false});
},
selectPreviousCard: function () {
var prevCardInfo;
var shouldUpdateCardDetail;
prevCardInfo = this.previousCardInfo();
shouldUpdateCardDetail = this.shouldShowCardDetailWhenMovingBetweenCardsUsingKeys();
if (prevCardInfo != null) {
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'selectCard', {'cardInfo':prevCardInfo, 'update':shouldUpdateCardDetail});
}
},
selectNextCard: function () {
var nextCardInfo;
var shouldUpdateCardDetail;
nextCardInfo = this.nextCardInfo();
shouldUpdateCardDetail = this.shouldShowCardDetailWhenMovingBetweenCardsUsingKeys();
if (nextCardInfo != null) {
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'selectCard', {'cardInfo':nextCardInfo, 'update':shouldUpdateCardDetail});
}
},
selectDetail: function () {
//console.log("TODO: SELECT DETAIL (right arrow key)", this.mediaQueryStyle(), this.currentPage(), this.selectedCardInfo());
if ((this.mediaQueryStyle() == 'narrow') && (this.currentPage() == 'mainPage')) {
Clipperz.Async.callbacks("MainController.selectDetail", [
MochiKit.Base.method(this.user(), 'getRecord', this.selectedCardInfo()['reference']),
MochiKit.Base.method(this, 'collectRecordInfo'),
MochiKit.Base.method(this, 'showCardDetailInNarrowView'),
], {trace:false}).callback();
}
},
exitCurrentSelection: function () {
if (this.isShowingHelp()) {
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'closeHelp');
} else {
var currentPage = this.pages()[this.currentPage()];
if (currentPage.props['showCertificatePreview'] == true) {
currentPage.setProps({'showCertificatePreview': false});
} else if (this.currentPage() == 'cardDetailPage') {
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'goBackToMainPage', {'reference':this.selectedCardInfo()['reference']});
} else if (this.currentPage() == 'mainPage') {
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'selectCard', {'cardInfo':null, 'update':true});
}
}
},
//============================================================================
updateAttachmentQueueInfo_handler: function(someProperties) {
return Clipperz.Async.callbacks("MainController.updateAttachmentQueueInfo_handler", [
MochiKit.Base.method(this, 'setPageProperties', this.currentPage(), 'attachmentQueueInfo', this.attachmentQueueInfo())
], {trace:false});
},
addAttachment_handler: function (aFileInfo) { // aReference, someMetadata, aKey, aNonce
var deferredResult;
var record = aFileInfo['record'];
var file = aFileInfo['file'];
//console.log("addAttachment_handler", aFileInfo, record, file);
deferredResult = new Clipperz.Async.Deferred("MainController.addCardAttachment_handler", {'trace':false});
deferredResult.addMethod(this.overlay(), 'show', "reading", true);
deferredResult.addMethod(record, 'createNewAttachment');
deferredResult.addCallback(MochiKit.Base.methodcaller('setFile', file));
deferredResult.addMethod(this.attachmentController(), 'addAttachment');
deferredResult.addMethod(this.overlay(), 'hide', true);
deferredResult.addCallback(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'refreshCardEditDetail', record.reference());
deferredResult.callback();
return deferredResult;
},
uploadMessageCallback: function (someArguments, aProgressCallback) {
var deferredResult;
deferredResult = new Clipperz.Async.Deferred("MainController.uploadMessageCallback", {'trace':false});
deferredResult.addMethod(this.user().connection(), 'uploadAttachment', someArguments, aProgressCallback);
deferredResult.callback();
return deferredResult;
},
//----------------------------------------------------------------------------
removeAttachment_handler: function (anAttachmentInfo) {
var deferredResult;
var record = anAttachmentInfo['record'];
var attachment = anAttachmentInfo['attachment'];
deferredResult = new Clipperz.Async.Deferred("MainController.removeAttachment_handler", {trace: false});
deferredResult.addCallback(MochiKit.Base.method(this, 'ask', {
'question': "Do you really want to delete this attachment?",
'possibleAnswers':{
'cancel': {'label':"No", 'isDefault':true, 'answer':MochiKit.Base.methodcaller('cancel', new MochiKit.Async.CancelledError())},
'revert': {'label':"Yes", 'isDefault':false, 'answer':MochiKit.Base.methodcaller('callback')}
}
})),
deferredResult.addMethod(this, 'cancelAttachment_handler', attachment);
deferredResult.addMethod(record, 'removeAttachment', attachment);
deferredResult.addCallback(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'refreshCardEditDetail', record.reference());
deferredResult.callback();
return deferredResult;
},
//----------------------------------------------------------------------------
getAttachment_handler: function (anAttachment) {
this.attachmentController().getAttachment(anAttachment);
},
downloadMessageCallback: function(anAttachment, aProgressCallback) {
var deferredResult;
deferredResult = new Clipperz.Async.Deferred("MainController.downloadAttachment_handler", {'trace':false});
deferredResult.addMethod(this.user().connection(), 'downloadAttachment', {
'reference': anAttachment.reference()
}, aProgressCallback);
deferredResult.callback();
return deferredResult;
},
//----------------------------------------------------------------------------
cancelAttachment_handler: function(anAttachment) {
return this.attachmentController().cancelAttachment(anAttachment);
},
closeAttachmentNotification_handler: function(aNotificationId) {
return Clipperz.Async.callbacks("MainController.", [
MochiKit.Base.method(this.attachmentController(), 'removeNotification', aNotificationId)
], {trace:false});
},
//----------------------------------------------------------------------------
reloadAttachmentServerStatusCallback: function(aRecord) {
if (! aRecord.isBrandNew()) {
return Clipperz.Async.callbacks("MainController.reloadAttachmentServerStatus_handler", [
MochiKit.Base.method(aRecord, 'updatedAttachmentServerStatus'),
MochiKit.Base.bind(function () {
if (this._selectedCardInfo && this._selectedCardInfo['reference']) {
this.refreshUI(this._selectedCardInfo['reference']);
}
}, this),
], {trace:false});
}
},
//============================================================================
registerHistoryHandler: function() {
window.onpopstate = MochiKit.Base.method(this, 'handleOnpopstate');
},
handleOnpopstate: function (anEvent) {
if (this.filter().type != 'ALL') {
this.selectAllCards();
// window.history.pushState(window.history.state, "", window.location.toString());
this.historyPushState(this.historyState, "", window.location.toString());
} else if(anEvent.state) {
if (this.isPageInEditMode()) {
// window.history.pushState({selectedCardInfo: this.selectedCardInfo()}, "", window.location.toString());
this.historyPushState({selectedCardInfo: this.selectedCardInfo()}, "", window.location.toString());
this.cancelCardEdits(this.selectedCardReference());
} else {
if (anEvent.state['selectedCardInfo']) {
this.selectCard(anEvent.state['selectedCardInfo'], true);
} else {
this.selectCard(null, true);
this.goBackToMainPage();
}
}
}
// console.log('History changed', anEvent.state);
},
//============================================================================
/*
wrongAppVersion: function (anError) {
// this.pages()['errorPage'].setProps({message:anError.message});
// this.moveInPage('errorPage', this.currentPage());
},
*/
//=========================================================================
__syntaxFix__: "syntax fix"
});