summaryrefslogtreecommitdiff
path: root/frontend/delta/js/Clipperz/PM/UI/MainController.js
Unidiff
Diffstat (limited to 'frontend/delta/js/Clipperz/PM/UI/MainController.js') (more/less context) (ignore whitespace changes)
-rw-r--r--frontend/delta/js/Clipperz/PM/UI/MainController.js491
1 files changed, 491 insertions, 0 deletions
diff --git a/frontend/delta/js/Clipperz/PM/UI/MainController.js b/frontend/delta/js/Clipperz/PM/UI/MainController.js
new file mode 100644
index 0000000..da7540e
--- a/dev/null
+++ b/frontend/delta/js/Clipperz/PM/UI/MainController.js
@@ -0,0 +1,491 @@
1/*
2
3Copyright 2008-2013 Clipperz Srl
4
5This file is part of Clipperz, the online password manager.
6For further information about its features and functionalities please
7refer to http://www.clipperz.com.
8
9* Clipperz is free software: you can redistribute it and/or modify it
10 under the terms of the GNU Affero General Public License as published
11 by the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14* Clipperz is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 See the GNU Affero General Public License for more details.
18
19* You should have received a copy of the GNU Affero General Public
20 License along with Clipperz. If not, see http://www.gnu.org/licenses/.
21
22*/
23
24Clipperz.Base.module('Clipperz.PM.UI');
25
26Clipperz.PM.UI.MainController = function() {
27 var pages;
28
29 this._proxy = null;
30 this._user = null;
31 this._filter= '';
32
33 //this._currentPage = 'loadingPage';
34
35 this._pageStack = ['loadingPage'];
36 this._overlay = new Clipperz.PM.UI.Components.Overlay();
37 pages = {
38 'loginPage': new Clipperz.PM.UI.Components.LoginForm(),
39 'registrationPage':new Clipperz.PM.UI.Components.RegistrationWizard(),
40 'cardListPage': new Clipperz.PM.UI.Components.CardList(),
41 'cardDetailPage':new Clipperz.PM.UI.Components.CardDetail({card: {}}),
42 'errorPage': new Clipperz.PM.UI.Components.ErrorPage({message:''})
43 };
44
45 MochiKit.Base.map(function (anId) {React.renderComponent(pages[anId], MochiKit.DOM.getElement(anId))}, MochiKit.Base.keys(pages));
46 this._pages = pages;
47 this.registerForNotificationCenterEvents();
48
49 return this;
50}
51
52MochiKit.Base.update(Clipperz.PM.UI.MainController.prototype, {
53
54 toString: function () {
55 return "Clipperz.PM.UI.MainController";
56 },
57
58 //=========================================================================
59
60 overlay: function () {
61 return this._overlay;
62 },
63
64 loginForm: function () {
65 return this._loginForm;
66 },
67
68 registrationWizard: function () {
69 return this._registrationWizard;
70 },
71
72 //=========================================================================
73
74 isOnline: function() {
75 return navigator.onLine;
76 },
77
78 hasLocalData: function() {
79 return false;
80 },
81
82 loginMode: function () {
83 //PIN is set using this command:
84 //Clipperz.PM.PIN.setCredentialsWithPIN('1234', {'username':'joe', 'passphrase':'clipperz'});
85
86 return Clipperz.PM.PIN.isSet() ? 'PIN' : 'CREDENTIALS';
87 },
88
89 //=========================================================================
90
91 pages: function () {
92 return this._pages;
93 },
94
95 pageStack: function () {
96 return this._pageStack;
97 },
98
99 //=========================================================================
100
101 selectInitialProxy: function () {
102 if (this.isOnline()) {
103 this._proxy = Clipperz.PM.Proxy.defaultProxy;
104 } else {
105 if (this.hasLocalData()) {
106 this._proxy = new Clipperz.PM.Proxy.Offline({dataStore: new Clipperz.PM.Proxy.Offline.LocalStorageDataStore(), shouldPayTolls:false});
107 } else {
108 this.showOfflineError();
109 }
110 }
111 },
112
113 proxy: function () {
114 return this._proxy;
115 },
116
117 //=========================================================================
118
119 registerForNotificationCenterEvents: function () {
120 var events= ['doLogin', 'registerNewUser', 'showRegistrationForm', 'goBack', 'showRecord', 'searchCards', 'runDirectLogin'];
121 var self= this;
122
123 MochiKit.Base.map(function (anEvent) {
124 MochiKit.Signal.connect(Clipperz.Signal.NotificationCenter, anEvent, MochiKit.Base.method(self, anEvent));
125 }, events);
126
127 // MochiKit.Signal.connect(window, 'onpopstate', MochiKit.Base.method(this, 'historyGoBack'));
128 MochiKit.Signal.connect(window, 'onbeforeunload',MochiKit.Base.method(this, 'shouldExitApp'));
129 },
130
131 //-------------------------------------------------------------------------
132
133 run: function (parameters) {
134 var shouldShowRegistrationForm;
135
136 this.selectInitialProxy();
137 shouldShowRegistrationForm = parameters['shouldShowRegistrationForm'] && this.proxy().canRegisterNewUsers();
138 this.pages()['loginPage'].setProps({'mode':this.loginMode(), 'isNewUserRegistrationAvailable': this.proxy().canRegisterNewUsers()});
139
140 if (shouldShowRegistrationForm) {
141 this.showRegistrationForm();
142 } else {
143 this.showLoginForm();
144 }
145 this.overlay().done("", 0.5);
146 },
147
148 //-------------------------------------------------------------------------
149
150 showLoginForm: function () {
151 varloginFormPage;
152
153 loginFormPage = this.pages()['loginPage'];
154 loginFormPage.setProps({'mode':this.loginMode(), 'isNewUserRegistrationAvailable': this.proxy().canRegisterNewUsers()});
155 this.moveInPage(this.currentPage(), 'loginPage');
156 MochiKit.Async.callLater(0.5, MochiKit.Base.method(loginFormPage, 'setInitialFocus'));
157 },
158
159 showRegistrationForm: function () {
160 var currentPage;
161 varregistrationPage;
162
163 currentPage = this.currentPage();
164 registrationPage = this.pages()['registrationPage'];
165 this.setCurrentPage('loginPage');
166 registrationPage.setProps({});
167 this.moveInPage(currentPage, 'registrationPage');
168 MochiKit.Async.callLater(0.5, MochiKit.Base.method(registrationPage, 'setInitialFocus'));
169 },
170
171 //=========================================================================
172
173 doLogin: function (event) {
174 varcredentials;
175 var getPassphraseDelegate;
176 varuser;
177
178 user = null;
179
180 this.overlay().show("logging in");
181 this.pages()['loginPage'].setProps({disabled:true});
182
183 if ('pin' in event) {
184 credentials = Clipperz.PM.PIN.credentialsWithPIN(event['pin']);
185 } else {
186 credentials = event;
187 }
188 getPassphraseDelegate = MochiKit.Base.partial(MochiKit.Async.succeed, credentials.passphrase);
189 user = new Clipperz.PM.DataModel.User({'username':credentials.username, 'getPassphraseFunction':getPassphraseDelegate});
190
191 deferredResult = new Clipperz.Async.Deferred('MainController.doLogin', {trace:false});
192 deferredResult.addCallback(MochiKit.Async.wait, 0.1);
193 deferredResult.addMethod(Clipperz.Crypto.PRNG.defaultRandomGenerator(), 'deferredEntropyCollection');
194 deferredResult.addMethod(user, 'login');
195 deferredResult.addMethod(Clipperz.PM.PIN, 'resetFailedAttemptCount');
196 deferredResult.addMethod(this, 'setUser', user);
197
198 // deferredResult.addMethod(this, 'setupApplication');
199 deferredResult.addMethod(this, 'runApplication');
200 deferredResult.addMethod(this.overlay(), 'done', "", 1);
201 deferredResult.addErrback(MochiKit.Base.method(this, 'genericErrorHandler', event));
202 deferredResult.addErrback(MochiKit.Base.bind(function (anEvent, anError) {
203 if (anError['isPermanent'] != true) {
204 this.pages()['loginPage'].setProps({disabled:false, 'mode':this.loginMode()});
205 this.pages()['loginPage'].setInitialFocus();
206 }
207 return anError;
208 }, this, event))
209 deferredResult.callback();
210
211 return deferredResult;
212 },
213
214 //-------------------------------------------------------------------------
215
216 registerNewUser: function (credentials) {
217 vardeferredResult;
218
219 this.overlay().show("creating user");
220
221 this.pages()['registrationPage'].setProps({disabled:true});
222 deferredResult = new Clipperz.Async.Deferred('MainController.registerNewUser', {trace:false});
223 deferredResult.addCallback(Clipperz.PM.DataModel.User.registerNewAccount,
224 credentials['username'],
225 MochiKit.Base.partial(MochiKit.Async.succeed, credentials['passphrase'])
226 );
227 deferredResult.addMethod(this, 'doLogin', credentials);
228 deferredResult.addErrback(MochiKit.Base.method(this, 'genericErrorHandler', event));
229 deferredResult.addErrback(MochiKit.Base.bind(function (anError) {
230 if (anError['isPermanent'] != true) {
231 this.pages()['registrationPage'].setProps({disabled:false});
232 this.pages()['registrationPage'].setInitialFocus();
233 }
234 return anError;
235 }, this));
236
237 deferredResult.callback();
238
239 return deferredResult;
240
241 },
242
243 //-------------------------------------------------------------------------
244
245 user: function () {
246 return this._user;
247 },
248
249 setUser: function (aUser) {
250 this._user = aUser;
251 return this._user;
252 },
253
254 //=========================================================================
255
256 allCardInfo: function () {
257 var deferredResult;
258 varcardInfo;
259
260 cardInfo = {
261 '_rowObject': MochiKit.Async.succeed,
262 '_reference': MochiKit.Base.methodcaller('reference'),
263 '_searchableContent':MochiKit.Base.methodcaller('searchableContent'),
264 'label': MochiKit.Base.methodcaller('label'),
265 'favicon': MochiKit.Base.methodcaller('favicon')
266 };
267
268 deferredResult = new Clipperz.Async.Deferred('MainController.allCardInfo', {trace:false});
269 deferredResult.addMethod(this.user(), 'getRecords');
270 deferredResult.addCallback(MochiKit.Base.map, Clipperz.Async.collectResults("CardList.value - collectResults", cardInfo, {trace:false}));
271 deferredResult.addCallback(Clipperz.Async.collectAll);
272 deferredResult.callback();
273
274 return deferredResult;
275 },
276
277 filterCards: function (someCardInfo) {
278 var filter;
279 varfilterRegExp;
280 varresult;
281
282 filter = this.filter().replace(/[^A-Za-z0-9]/g, "\\$&");
283 filterRegExp = new RegExp(filter, "i");
284 result = MochiKit.Base.filter(function (aCardInfo) { return filterRegExp.test(aCardInfo['_searchableContent'])}, someCardInfo);
285
286 return result;
287 },
288
289 sortCards: function (someCardInfo) {
290 return someCardInfo.sort(Clipperz.Base.caseInsensitiveKeyComparator('label'));
291 },
292
293 showRecordList: function () {
294 var deferredResult;
295
296 deferredResult = new Clipperz.Async.Deferred('MainController.showRecordList', {trace:false});
297 deferredResult.addMethod(this, 'allCardInfo');
298 deferredResult.addMethod(this, 'filterCards');
299 deferredResult.addMethod(this, 'sortCards');
300 deferredResult.addCallback(MochiKit.Base.bind(function (someRecordInfo) {
301 this.pages()['cardListPage'].setProps({cardList: someRecordInfo});
302 }, this));
303 deferredResult.callback();
304
305 return deferredResult;
306 },
307
308 filter: function (){
309 return this._filter;
310 },
311
312 setFilter: function (aValue) {
313 this._filter = aValue;
314 },
315
316 searchCards: function (someParameters) {
317//console.log("SEARCH CARDS", someParameters);
318 this.setFilter(someParameters);
319 this.showRecordList();
320 },
321
322 //=========================================================================
323
324 runApplication: function () {
325 MochiKit.Signal.connect(window, 'onpopstate',MochiKit.Base.method(this, 'historyGoBack'));
326 this.moveInPage(this.currentPage(), 'cardListPage');
327 return this.showRecordList();
328 },
329
330 showRecord: function (aRecordReference) {
331//console.log("Show Record", aRecordReference);
332 vardeferredResult;
333
334 this.pages()['cardListPage'].setProps({selectedCard:aRecordReference});
335 deferredResult = new Clipperz.Async.Deferred('MainController.runApplication', {trace:false});
336 // deferredResult.addMethod(this.user(), 'getRecord', aRecordReference['_reference']);
337 deferredResult.addMethod(this.user(), 'getRecord', aRecordReference);
338 deferredResult.addMethodcaller('content');
339 deferredResult.addCallback(MochiKit.Base.bind(function (aCard) {
340//console.log("CARD DETAILS", aCard);
341 this.pages()['cardDetailPage'].setProps({card: aCard});
342 this.pages()['cardListPage'].setProps({selectedCard: null});
343 }, this));
344 deferredResult.addMethod(this, 'moveInPage', this.currentPage(), 'cardDetailPage', true);
345 deferredResult.callback();
346
347 return deferredResult;
348 },
349
350 runDirectLogin: function (someParameters) {
351console.log("RUN DIRECT LOGIN", someParameters);
352 vardeferredResult;
353
354 // this.pages()['cardListPage'].setProps({selectedCard:aRecordReference});
355 deferredResult = new Clipperz.Async.Deferred('MainController.runDirectLogin', {trace:false});
356 // deferredResult.addMethod(this.user(), 'getRecord', aRecordReference['_reference']);
357 deferredResult.addMethod(this.user(), 'getRecord', someParameters['record']);
358 deferredResult.addMethodcaller('directLoginWithReference', someParameters['directLogin']);
359 deferredResult.addCallback(Clipperz.PM.UI.DirectLoginRunner.openDirectLogin);
360 deferredResult.callback();
361
362 return deferredResult;
363 },
364
365 shouldExitApp: function (anEvent) {
366console.log("SHOULD EXIT APP");
367 anEvent.preventDefault();
368 anEvent.stopPropagation();
369 },
370
371 //=========================================================================
372
373 genericErrorHandler: function (anEvent, anError) {
374 var errorMessage;
375 varresult;
376
377 result = anError;
378 errorMessage = "login failed";
379
380 if (anError['isPermanent'] === true) {
381 this.pages()['errorPage'].setProps({message:anError.message});
382 this.moveInPage(this.currentPage(), 'errorPage');
383 errorMessage = "failure";
384 } else {
385 if ('pin' in anEvent) {
386 errorCount = Clipperz.PM.PIN.recordFailedAttempt();
387 if (errorCount == -1) {
388 errorMessage = "PIN resetted";
389 }
390 }
391 }
392 this.overlay().failed(errorMessage, 1);
393
394 return result;
395 },
396
397 //=========================================================================
398
399 slidePage: function (fromPage, toPage, direction) {
400 varfromPosition;
401 var toPosition;
402
403 if (direction == "LEFT") {
404 fromPosition = 'right';
405 toPosition = 'left'
406 } else {
407 fromPosition = 'left';
408 toPosition = 'right'
409 }
410
411 MochiKit.DOM.addElementClass(fromPage, toPosition + ' transition');
412
413 MochiKit.DOM.addElementClass(toPage, fromPosition);
414 MochiKit.DOM.removeElementClass(toPage, toPosition);
415 MochiKit.DOM.addElementClass(toPage, 'transition');
416 MochiKit.Async.callLater(0.1, function () {
417 MochiKit.DOM.removeElementClass(toPage, fromPosition);
418 })
419
420 MochiKit.Async.callLater(0.5, function () {
421 MochiKit.DOM.removeElementClass(fromPage, 'transition');
422 MochiKit.DOM.removeElementClass(toPage, 'transition');
423 })
424 },
425
426 rotateInPage: function (fromPage, toPage) {
427 //Broken! :(
428 MochiKit.DOM.addElementClass(MochiKit.DOM.getElement('mainDiv'), 'show-right');
429 },
430
431 //.........................................................................
432
433 goBack: function () {
434 varfromPage;
435 var toPage;
436
437 fromPage = this.pageStack().shift();
438 toPage = this.currentPage();
439 this.pages()[toPage].setProps({});
440 this.moveOutPage(fromPage, toPage);
441 },
442
443 historyGoBack: function (anEvent) {
444 anEvent.preventDefault();
445 anEvent.stopPropagation();
446 this.goBack();
447 },
448
449 currentPage: function () {
450 return this.pageStack()[0];
451 },
452
453 setCurrentPage: function (aPage) {
454 this.pageStack().unshift(aPage);
455 },
456
457 moveInPage: function (fromPage, toPage, addToHistory) {
458 varshouldAddItemToHistory;
459
460 shouldAddItemToHistory = typeof(addToHistory) == 'undefined' ? false : addToHistory;
461
462 this.slidePage(MochiKit.DOM.getElement(fromPage), MochiKit.DOM.getElement(toPage), 'LEFT');
463 this.setCurrentPage(toPage);
464
465 if (shouldAddItemToHistory) {
466//console.log("ADD ITEM TO HISTORY");
467//console.log("ADD ITEM TO HISTORY - window", window);
468//console.log("ADD ITEM TO HISTORY - window.history", window.history);
469 window.history.pushState({'fromPage': fromPage, 'toPage': toPage});
470 //# window.history.pushState();
471//console.log("ADDED ITEM TO HISTORY");
472 } else {
473//console.log("Skip HISTORY");
474 }
475 },
476
477 moveOutPage: function (fromPage, toPage) {
478 this.slidePage(MochiKit.DOM.getElement(fromPage), MochiKit.DOM.getElement(toPage), 'RIGHT');
479 this.setCurrentPage(toPage);
480 },
481
482 //=========================================================================
483/*
484 wrongAppVersion: function (anError) {
485 // this.pages()['errorPage'].setProps({message:anError.message});
486 // this.moveInPage('errorPage', this.currentPage());
487 },
488*/
489 //=========================================================================
490 __syntaxFix__: "syntax fix"
491});