summaryrefslogtreecommitdiff
path: root/frontend/delta/js/Clipperz
authorGiulio Cesare Solaroli <giulio.cesare@clipperz.com>2013-10-02 07:59:30 (UTC)
committer Giulio Cesare Solaroli <giulio.cesare@clipperz.com>2013-10-02 07:59:30 (UTC)
commit1180b7b195157aaeb4f0d5380e0c886bbd06c2e2 (patch) (unidiff)
tree709e33a09d9325d382aabaf0a0828e20ebdb96db /frontend/delta/js/Clipperz
parent20bea94ab6b91c85b171dcf86baba0a64169d508 (diff)
downloadclipperz-1180b7b195157aaeb4f0d5380e0c886bbd06c2e2.zip
clipperz-1180b7b195157aaeb4f0d5380e0c886bbd06c2e2.tar.gz
clipperz-1180b7b195157aaeb4f0d5380e0c886bbd06c2e2.tar.bz2
Updated /delta
Switched from less to scss. Still no build script to update the final CSS, though. Added preliminary support for storing account data on browser's local storage for offline viewing. No public backend currently support this feature.
Diffstat (limited to 'frontend/delta/js/Clipperz') (more/less context) (ignore whitespace changes)
-rw-r--r--frontend/delta/js/Clipperz/PM/DataModel/DevicePreferences.js90
-rw-r--r--frontend/delta/js/Clipperz/PM/Proxy.js1
-rwxr-xr-xfrontend/delta/js/Clipperz/PM/Proxy/Proxy.JSON.js4
-rw-r--r--frontend/delta/js/Clipperz/PM/Proxy/Proxy.Offline.LocalStorageDataStore.js4
-rw-r--r--frontend/delta/js/Clipperz/PM/UI/Components/CardDetail.js85
-rw-r--r--frontend/delta/js/Clipperz/PM/UI/Components/CardList.js13
-rw-r--r--frontend/delta/js/Clipperz/PM/UI/Components/Checkbox.js44
-rw-r--r--frontend/delta/js/Clipperz/PM/UI/Components/LoginForm.js6
-rw-r--r--frontend/delta/js/Clipperz/PM/UI/Components/Overlay.js7
-rw-r--r--frontend/delta/js/Clipperz/PM/UI/Components/PreferencePage.js88
-rw-r--r--frontend/delta/js/Clipperz/PM/UI/MainController.js130
11 files changed, 425 insertions, 47 deletions
diff --git a/frontend/delta/js/Clipperz/PM/DataModel/DevicePreferences.js b/frontend/delta/js/Clipperz/PM/DataModel/DevicePreferences.js
new file mode 100644
index 0000000..ff3b33f
--- a/dev/null
+++ b/frontend/delta/js/Clipperz/PM/DataModel/DevicePreferences.js
@@ -0,0 +1,90 @@
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.PM.DataModel.DevicePreferences = function (args) {
25 args = args || {};
26
27 this._data = null;
28
29 Clipperz.PM.DataModel.DevicePreferences.superclass.constructor.apply(this, arguments);
30
31 return this;
32}
33
34Clipperz.Base.extend(Clipperz.PM.DataModel.DevicePreferences, Object, {
35
36 toString: function () {
37 return "Clipperz.PM.DataModel.DevicePreferences";
38 },
39
40 //-------------------------------------------------------------------------
41
42 shouldStoreDataLocally: function () {
43 return (localStorage.getItem('shouldStoreDataLocally') === 'true');
44 },
45
46 setShouldStoreDataLocally: function (aValue) {
47 localStorage.setItem('shouldStoreDataLocally', aValue);
48 },
49
50 //-------------------------------------------------------------------------
51
52 setAccountDataWityResponse: function (aResponse) {
53 localStorage.setItem('clipperz_dump_data', aResponse['data']);
54 localStorage.setItem('clipperz_dump_version',aResponse['version']);
55 localStorage.setItem('clipperz_dump_date', new Date());
56
57 this._data = null;
58 },
59
60 accountData: function () {
61 if (this._data == null) {
62 vardata;
63
64 data = localStorage.getItem('clipperz_dump_data');
65 if (data != null) {
66 this._data = JSON.parse(data);
67 }
68 }
69
70 return this._data;
71 },
72
73 latestDownload: function () {
74 varresult;
75 vardate;
76
77 date = localStorage.getItem('clipperz_dump_date');
78 if (date != null) {
79 result = new Date(date);
80 } else {
81 result = null;
82 }
83
84 return result;
85 },
86
87 //=========================================================================
88 __syntaxFix__: "syntax fix"
89});
90
diff --git a/frontend/delta/js/Clipperz/PM/Proxy.js b/frontend/delta/js/Clipperz/PM/Proxy.js
index 2ac684a..71c784f 100644
--- a/frontend/delta/js/Clipperz/PM/Proxy.js
+++ b/frontend/delta/js/Clipperz/PM/Proxy.js
@@ -131,48 +131,49 @@ Clipperz.PM.Proxy.prototype = MochiKit.Base.update(null, {
131 131
132 //========================================================================= 132 //=========================================================================
133 133
134 'processMessage': function (aFunctionName, someParameters, aRequestType) { 134 'processMessage': function (aFunctionName, someParameters, aRequestType) {
135 vardeferredResult; 135 vardeferredResult;
136 136
137 deferredResult = new Clipperz.Async.Deferred("Proxy.processMessage", {trace:false}); 137 deferredResult = new Clipperz.Async.Deferred("Proxy.processMessage", {trace:false});
138 deferredResult.addMethod(this, 'payToll', aRequestType); 138 deferredResult.addMethod(this, 'payToll', aRequestType);
139 deferredResult.addMethod(this, 'sendMessage', aFunctionName); 139 deferredResult.addMethod(this, 'sendMessage', aFunctionName);
140 deferredResult.addMethod(this, 'setTollCallback'); 140 deferredResult.addMethod(this, 'setTollCallback');
141 deferredResult.callback(someParameters); 141 deferredResult.callback(someParameters);
142 142
143 return deferredResult; 143 return deferredResult;
144 }, 144 },
145 145
146 //========================================================================= 146 //=========================================================================
147 147
148 '_sendMessage': function (aFunctionName, aVersion, someParameters) { 148 '_sendMessage': function (aFunctionName, aVersion, someParameters) {
149 throw Clipperz.Base.exception.AbstractMethod; 149 throw Clipperz.Base.exception.AbstractMethod;
150 }, 150 },
151 151
152 'sendMessage': function (aFunctionName, someParameters) { 152 'sendMessage': function (aFunctionName, someParameters) {
153 var deferredResult; 153 var deferredResult;
154 154
155console.log("PROXY.sendMessage", aFunctionName, someParameters);
155 //TODO: read actual application version for a property set at build time 156 //TODO: read actual application version for a property set at build time
156 deferredResult = new Clipperz.Async.Deferred("Proxy.sendMessage", {trace:false}); 157 deferredResult = new Clipperz.Async.Deferred("Proxy.sendMessage", {trace:false});
157 deferredResult.addMethod(this, '_sendMessage', aFunctionName, 'fake-app-version'); 158 deferredResult.addMethod(this, '_sendMessage', aFunctionName, 'fake-app-version');
158 deferredResult.addErrback(MochiKit.Base.method(this, 'handleError')); 159 deferredResult.addErrback(MochiKit.Base.method(this, 'handleError'));
159 deferredResult.callback(someParameters); 160 deferredResult.callback(someParameters);
160 161
161 return deferredResult; 162 return deferredResult;
162 }, 163 },
163 164
164 //------------------------------------------------------------------------- 165 //-------------------------------------------------------------------------
165 166
166 'handleError': function (anError) { 167 'handleError': function (anError) {
167 if (anError['message'] == 'Wrong application version') { 168 if (anError['message'] == 'Wrong application version') {
168 anError['isPermanent'] = true; 169 anError['isPermanent'] = true;
169 } 170 }
170 return anError; 171 return anError;
171 }, 172 },
172 173
173 //========================================================================= 174 //=========================================================================
174 175
175 'isReadOnly': function () { 176 'isReadOnly': function () {
176 return false; 177 return false;
177 }, 178 },
178 179
diff --git a/frontend/delta/js/Clipperz/PM/Proxy/Proxy.JSON.js b/frontend/delta/js/Clipperz/PM/Proxy/Proxy.JSON.js
index 1638d99..6deee3d 100755
--- a/frontend/delta/js/Clipperz/PM/Proxy/Proxy.JSON.js
+++ b/frontend/delta/js/Clipperz/PM/Proxy/Proxy.JSON.js
@@ -36,50 +36,50 @@ Clipperz.PM.Proxy.JSON = function(args) {
36 36
37Clipperz.Base.extend(Clipperz.PM.Proxy.JSON, Clipperz.PM.Proxy, { 37Clipperz.Base.extend(Clipperz.PM.Proxy.JSON, Clipperz.PM.Proxy, {
38 38
39 'toString': function() { 39 'toString': function() {
40 return "Clipperz.PM.Proxy.JSON"; 40 return "Clipperz.PM.Proxy.JSON";
41 }, 41 },
42 42
43 //========================================================================= 43 //=========================================================================
44 44
45 'url': function () { 45 'url': function () {
46 return this._url; 46 return this._url;
47 }, 47 },
48 48
49 //========================================================================= 49 //=========================================================================
50 50
51 '_sendMessage': function(aFunctionName, aVersion, someParameters) { 51 '_sendMessage': function(aFunctionName, aVersion, someParameters) {
52 vardeferredResult; 52 vardeferredResult;
53 var parameters; 53 var parameters;
54 54
55 parameters = { 55 parameters = {
56 method: aFunctionName, 56 method: aFunctionName,
57 version: aVersion, 57 version: aVersion,
58 parameters: Clipperz.Base.serializeJSON(someParameters) 58 parameters: Clipperz.Base.serializeJSON(someParameters)
59 }; 59 };
60 60console.log("PROXY.JSON._sendMessage", parameters);
61 deferredResult = new Clipperz.Async.Deferred("Proxy.JSON.sendMessage", {trace:false}); 61 deferredResult = new Clipperz.Async.Deferred("Proxy.JSON._sendMessage", {trace:false});
62 deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'remoteRequestSent'); 62 deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'remoteRequestSent');
63 deferredResult.addCallback(MochiKit.Async.doXHR, this.url(), { 63 deferredResult.addCallback(MochiKit.Async.doXHR, this.url(), {
64 method:'POST', 64 method:'POST',
65 sendContent:MochiKit.Base.queryString(parameters), 65 sendContent:MochiKit.Base.queryString(parameters),
66 headers:{"Content-Type":"application/x-www-form-urlencoded"} 66 headers:{"Content-Type":"application/x-www-form-urlencoded"}
67 }); 67 });
68 deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'remoteRequestReceived'); 68 deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'remoteRequestReceived');
69 deferredResult.addCallback(MochiKit.Base.itemgetter('responseText')); 69 deferredResult.addCallback(MochiKit.Base.itemgetter('responseText'));
70 deferredResult.addCallback(Clipperz.Base.evalJSON); 70 deferredResult.addCallback(Clipperz.Base.evalJSON);
71 deferredResult.addCallback(function (someValues) { 71 deferredResult.addCallback(function (someValues) {
72 if (someValues['result'] == 'EXCEPTION') { 72 if (someValues['result'] == 'EXCEPTION') {
73 throw someValues['message']; 73 throw someValues['message'];
74 } 74 }
75 75
76 return someValues; 76 return someValues;
77 }) 77 })
78 deferredResult.callback(); 78 deferredResult.callback();
79 79
80 return deferredResult; 80 return deferredResult;
81 }, 81 },
82 82
83 //========================================================================= 83 //=========================================================================
84 __syntaxFix__: "syntax fix" 84 __syntaxFix__: "syntax fix"
85 85
diff --git a/frontend/delta/js/Clipperz/PM/Proxy/Proxy.Offline.LocalStorageDataStore.js b/frontend/delta/js/Clipperz/PM/Proxy/Proxy.Offline.LocalStorageDataStore.js
index a3c238c..3f16f70 100644
--- a/frontend/delta/js/Clipperz/PM/Proxy/Proxy.Offline.LocalStorageDataStore.js
+++ b/frontend/delta/js/Clipperz/PM/Proxy/Proxy.Offline.LocalStorageDataStore.js
@@ -9,49 +9,51 @@ refer to http://www.clipperz.com.
9* Clipperz is free software: you can redistribute it and/or modify it 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 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 11 by the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version. 12 (at your option) any later version.
13 13
14* Clipperz is distributed in the hope that it will be useful, but 14* Clipperz is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of 15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 See the GNU Affero General Public License for more details. 17 See the GNU Affero General Public License for more details.
18 18
19* You should have received a copy of the GNU Affero General Public 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/. 20 License along with Clipperz. If not, see http://www.gnu.org/licenses/.
21 21
22*/ 22*/
23 23
24try { if (typeof(Clipperz.PM.Proxy.Offline.DataStore) == 'undefined') { throw ""; }} catch (e) { 24try { if (typeof(Clipperz.PM.Proxy.Offline.DataStore) == 'undefined') { throw ""; }} catch (e) {
25 throw "Clipperz.PM.Proxy.Offline.LocalStorageDataStore depends on Clipperz.PM.Proxy.Offline.DataStore!"; 25 throw "Clipperz.PM.Proxy.Offline.LocalStorageDataStore depends on Clipperz.PM.Proxy.Offline.DataStore!";
26} 26}
27 27
28//============================================================================= 28//=============================================================================
29 29
30Clipperz.PM.Proxy.Offline.LocalStorageDataStore = function(args) { 30Clipperz.PM.Proxy.Offline.LocalStorageDataStore = function(args) {
31 args = args || {}; 31 args = args || {};
32 32
33 this._data = args.data || (typeof(_clipperz_dump_data_) != 'undefined' ? _clipperz_dump_data_ : null); 33 //this._data = args.data || (typeof(_clipperz_dump_data_) != 'undefined' ? _clipperz_dump_data_ : null);
34 this._data = JSON.parse(localStorage.getItem('clipperz_dump_data'));
35
34 this._isReadOnly = (typeof(args.readOnly) == 'undefined' ? true : args.readOnly); 36 this._isReadOnly = (typeof(args.readOnly) == 'undefined' ? true : args.readOnly);
35 this._shouldPayTolls = args.shouldPayTolls || false; 37 this._shouldPayTolls = args.shouldPayTolls || false;
36 38
37 this._tolls = {}; 39 this._tolls = {};
38 this._currentStaticConnection = null; 40 this._currentStaticConnection = null;
39 41
40 //Clipperz.PM.Proxy.Offline.LocalStorageDataStore.superclass.constructor.apply(this, arguments); 42 //Clipperz.PM.Proxy.Offline.LocalStorageDataStore.superclass.constructor.apply(this, arguments);
41 43
42 return this; 44 return this;
43} 45}
44 46
45Clipperz.Base.extend(Clipperz.PM.Proxy.Offline.LocalStorageDataStore, Clipperz.PM.Proxy.Offline.DataStore, { 47Clipperz.Base.extend(Clipperz.PM.Proxy.Offline.LocalStorageDataStore, Clipperz.PM.Proxy.Offline.DataStore, {
46 48
47 //========================================================================= 49 //=========================================================================
48 50
49 '_knock': function(aConnection, someParameters) { 51 '_knock': function(aConnection, someParameters) {
50 var result; 52 var result;
51 53
52 result = { 54 result = {
53 toll: this.getTollForRequestType(someParameters['requestType']) 55 toll: this.getTollForRequestType(someParameters['requestType'])
54 } 56 }
55 57
56 return result; 58 return result;
57 }, 59 },
diff --git a/frontend/delta/js/Clipperz/PM/UI/Components/CardDetail.js b/frontend/delta/js/Clipperz/PM/UI/Components/CardDetail.js
index df514a2..12ddce3 100644
--- a/frontend/delta/js/Clipperz/PM/UI/Components/CardDetail.js
+++ b/frontend/delta/js/Clipperz/PM/UI/Components/CardDetail.js
@@ -16,127 +16,180 @@ refer to http://www.clipperz.com.
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 See the GNU Affero General Public License for more details. 17 See the GNU Affero General Public License for more details.
18 18
19* You should have received a copy of the GNU Affero General Public 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/. 20 License along with Clipperz. If not, see http://www.gnu.org/licenses/.
21 21
22*/ 22*/
23 23
24Clipperz.PM.UI.Components.CardDetail = React.createClass({ 24Clipperz.PM.UI.Components.CardDetail = React.createClass({
25 25
26 getDefaultProps: function () { 26 getDefaultProps: function () {
27 return { 27 return {
28 // searchDelay: 0.3 28 // searchDelay: 0.3
29 } 29 }
30 }, 30 },
31 31
32 propTypes: { 32 propTypes: {
33 card: React.PropTypes.object.isRequired 33 card: React.PropTypes.object.isRequired
34 }, 34 },
35 35
36 getInitialState: function () { 36 getInitialState: function () {
37 return { 37 return {
38 // showSearch: false, 38 // showSearch: false,
39 // searchTimer: null, 39 // searchTimer: null,
40 unmaskedFields: new Clipperz.Set(),
40 starred: false 41 starred: false
41 }; 42 };
42 }, 43 },
43 44
44 handleDirectLoginClick: function (aDirectLoginReference, anEvent) { 45 handleDirectLoginClick: function (aDirectLoginReference, anEvent) {
45 MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'runDirectLogin', {record:this.props.card['reference'], directLogin:aDirectLoginReference}); 46 MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'runDirectLogin', {record:this.props.card['reference'], directLogin:aDirectLoginReference});
46 }, 47 },
47 48
49 toggleFieldVisibility: function (aField, anEvent) {
50 var unmaskedFields;
51 var fieldReference;
52
53 unmaskedFields = this.state['unmaskedFields'];
54 fieldReference = aField['reference']
55 if (unmaskedFields.contains(fieldReference)) {
56 unmaskedFields.remove(fieldReference)
57 } else {
58 unmaskedFields.add(fieldReference)
59 }
60
61 this.setState({'unmaskedFields': unmaskedFields});
62 },
63
64 handleGoAction: function (aField, anEvent) {
65 var newWindow;
66
67 newWindow = MochiKit.DOM.currentWindow().open(aField['value'], '_blank');
68 newWindow.focus();
69 },
70
71 handleEmailAction: function (aField, anEvent) {
72 MochiKit.DOM.currentWindow().location = 'mailto:' + aField['value'];
73 },
74
48 //========================================================================= 75 //=========================================================================
49 76
50 normalizeFieldValue: function (aValue) { 77 normalizeFieldValue: function (aValue) {
51 varresult = []; 78 varresult = [];
52 varrows = aValue.split('\n'); 79 varrows = aValue.split('\n');
53 80
54 for (var i = 0; i < rows.length; i++) { 81 for (var i = 0; i < rows.length; i++) {
55 if (i > 0) { 82 if (i > 0) {
56 result.push(React.DOM.br()); 83 result.push(React.DOM.br());
57 } 84 }
58 result.push(rows[i].replace(/[\s]/g, '\u00A0')); 85 result.push(rows[i].replace(/[\s]/g, '\u00A0'));
59 } 86 }
60 87
61 return result; 88 return result;
62 }, 89 },
63 90
64 renderField: function (aField) { 91 renderFieldActionButton: function (aField) {
65//console.log("FIELD", aField); 92 // varactionLabel;
66 varactionLabel; 93 var result;
67 94
68 if (aField['actionType'] == 'URL') { 95 if (aField['actionType'] == 'URL') {
69 actionLabel = "go"; 96 result = React.DOM.div({className:'actionWrapper', onClick:MochiKit.Base.method(this, 'handleGoAction', aField)}, [
97 React.DOM.a({className:aField['actionType']}, "go")
98 ]);
70 } else if (aField['actionType'] == 'PASSWORD') { 99 } else if (aField['actionType'] == 'PASSWORD') {
71 actionLabel = "locked"; 100 var icon;
101
102 if (this.state['unmaskedFields'].contains(aField['reference'])) {
103 icon = "unlocked";
104 } else {
105 icon = "locked";
106 }
107 result =React.DOM.div({className:'actionWrapper', onClick:MochiKit.Base.method(this, 'toggleFieldVisibility', aField)}, [
108 React.DOM.a({className:aField['actionType']}, icon)
109 ]);
72 } else if (aField['actionType'] == 'EMAIL') { 110 } else if (aField['actionType'] == 'EMAIL') {
73 actionLabel = "email"; 111 result =React.DOM.div({className:'actionWrapper', onClick:MochiKit.Base.method(this, 'handleEmailAction', aField)}, [
112 React.DOM.a({className:aField['actionType']}, "email")
113 ]);
74 } else { 114 } else {
75 actionLabel = ""; 115 result = null;
116 }
117
118 return result;
119 },
120
121 renderField: function (aField) {
122//console.log("FIELD", aField);
123 var fieldExtraClass;
124
125 fieldExtraClass = aField['actionType'];
126 if (this.state['unmaskedFields'].contains(aField['reference'])) {
127 fieldExtraClass = fieldExtraClass + ' unlocked';
76 } 128 }
77 129
78 returnReact.DOM.div({className:'listItem ' + aField['actionType']}, [ 130 returnReact.DOM.div({className:'listItem ' + fieldExtraClass, key:aField['reference']}, [
79 React.DOM.div({className:'fieldWrapper'}, [ 131 React.DOM.div({className:'fieldWrapper'}, [
80 React.DOM.div({className:'fieldInnerWrapper'}, [ 132 React.DOM.div({className:'fieldInnerWrapper'}, [
81 React.DOM.div({className:'labelWrapper'}, React.DOM.span({className:'label'}, aField['label'])), 133 React.DOM.div({className:'labelWrapper'}, React.DOM.span({className:'label'}, aField['label'])),
82 React.DOM.div({className:'valueWrapper'}, React.DOM.span({className:'value ' + aField['actionType']}, this.normalizeFieldValue(aField['value']))) 134 React.DOM.div({className:'valueWrapper'}, React.DOM.span({className:'value ' + fieldExtraClass}, this.normalizeFieldValue(aField['value'])))
83 ]) 135 ])
84 ]), 136 ]),
85 React.DOM.div({className:'actionWrapper'}, [ 137 this.renderFieldActionButton(aField)
86 React.DOM.div({className:aField['actionType']}, actionLabel) 138 // React.DOM.div({className:'actionWrapper'}, [
87 ]) 139 // React.DOM.div({className:aField['actionType']}, actionLabel)
140 // ])
88 ]); 141 ]);
89 }, 142 },
90 143
91 renderDirectLogin: function (aDirectLogin) { 144 renderDirectLogin: function (aDirectLogin) {
92//console.log("DIRECT LOGIN", aDirectLogin); 145//console.log("DIRECT LOGIN", aDirectLogin);
93 returnReact.DOM.div({className:'listItem', onClick:MochiKit.Base.method(this, 'handleDirectLoginClick', aDirectLogin['reference'])}, [ 146 returnReact.DOM.div({className:'listItem', onClick:MochiKit.Base.method(this, 'handleDirectLoginClick', aDirectLogin['reference'])}, [
94 React.DOM.div({className:'labelWrapper'}, React.DOM.span({className:'label'}, aDirectLogin['label'])), 147 React.DOM.div({className:'labelWrapper'}, React.DOM.span({className:'label'}, aDirectLogin['label'])),
95 React.DOM.div({className:'faviconWrapper'}, React.DOM.img({className:'favicon', src:aDirectLogin['favicon']})), 148 React.DOM.div({className:'faviconWrapper'}, React.DOM.img({className:'favicon', src:aDirectLogin['favicon']})),
96 React.DOM.div({className:'directLoginLinkWrapper'}, React.DOM.span({className:'directLoginLink'}, "go")) 149 React.DOM.div({className:'directLoginLinkWrapper'}, React.DOM.span({className:'directLoginLink'}, "go"))
97 ]); 150 ]);
98 }, 151 },
99 152
100 handleBackClick: function (anEvent) { 153 handleBackClick: function (anEvent) {
101 window.history.back(); 154 // window.history.back();
155 MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'goBack');
102 }, 156 },
103 157
104 handleStarClick: function (anEvent) { 158 handleStarClick: function (anEvent) {
105 this.setState({starred: !this.state['starred']}); 159 this.setState({starred: !this.state['starred']});
106 }, 160 },
107 161
108 //========================================================================= 162 //=========================================================================
109 163
110 render: function () { 164 render: function () {
111 var card = this.props.card; 165 var card = this.props.card;
112 var starredStatus = (this.state['starred'] ? "starred" : "unstarred"); 166 // var starredStatus = (this.state['starred'] ? "starred" : "unstarred");
113 167
114 if ((typeof(card['fields']) != 'undefined') && (card['notes'] != '')) { 168 if ((typeof(card['fields']) != 'undefined') && (card['notes'] != '')) {
115 card['fields'].push({ 'actionType': 'NOTES', 'isHidden': false, 'label': "notes", 'reference': "notes", 'value': card['notes'] }) 169 card['fields'].push({ 'actionType': 'NOTES', 'isHidden': false, 'label': "notes", 'reference': "notes", 'value': card['notes'] })
116 } 170 }
117 171
118 returnReact.DOM.div({className:'cardDetail'}, [ 172 returnReact.DOM.div({className:'cardDetail'}, [
119 React.DOM.div({className:'header'}, [ 173 React.DOM.div({className:'header'}, [
120 React.DOM.div({className:'titleWrapper'}, React.DOM.div({className:'title'}, card.title)), 174 React.DOM.div({className:'titleWrapper'}, React.DOM.div({className:'title'}, card.title)),
121 // React.DOM.div({className:'titleWrapper'}, React.DOM.div({className:'title'}, card.title + ' ' + card.title + ' ' + card.title + ' ' + card.title)),
122 React.DOM.div({className:'backWrapper'}, React.DOM.a({className:'button back', onClick:this.handleBackClick}, "back")), 175 React.DOM.div({className:'backWrapper'}, React.DOM.a({className:'button back', onClick:this.handleBackClick}, "back")),
123 React.DOM.div({className:'starWrapper'}, React.DOM.a({className:'star', onClick:this.handleStarClick}, starredStatus)) 176 // React.DOM.div({className:'starWrapper'}, React.DOM.a({className:'star', onClick:this.handleStarClick}, starredStatus))
124 ]), 177 ]),
125 React.DOM.div({className:'content'}, [ 178 React.DOM.div({className:'content'}, [
126 card.fields ? React.DOM.div({className:'fields'}, MochiKit.Base.map(this.renderField, card.fields)) : null, 179 card.fields ? React.DOM.div({className:'fields'}, MochiKit.Base.map(this.renderField, card.fields)) : null,
127 card.directLogins ? React.DOM.div({className:'directLogins'}, MochiKit.Base.map(this.renderDirectLogin,card.directLogins)): null 180 card.directLogins ? React.DOM.div({className:'directLogins'}, MochiKit.Base.map(this.renderDirectLogin,card.directLogins)): null
128 ]), 181 ]),
129 React.DOM.div({className:'footer'}, [ 182 React.DOM.div({className:'footer'}, [
130 /* 183 /*
131 // React.DOM.a({className:'cancel'}, "cancel"), 184 // React.DOM.a({className:'cancel'}, "cancel"),
132 // React.DOM.a({className:'save'}, "save") 185 // React.DOM.a({className:'save'}, "save")
133 186
134 React.DOM.a({className:'cancel button'}, "failed"), 187 React.DOM.a({className:'cancel button'}, "failed"),
135 React.DOM.a({className:'save button'}, "done") 188 React.DOM.a({className:'save button'}, "done")
136*/ 189*/
137 ]) 190 ])
138 ]); 191 ]);
139 } 192 }
140 193
141 //========================================================================= 194 //=========================================================================
142}); 195});
diff --git a/frontend/delta/js/Clipperz/PM/UI/Components/CardList.js b/frontend/delta/js/Clipperz/PM/UI/Components/CardList.js
index 66d20f1..5a44a4a 100644
--- a/frontend/delta/js/Clipperz/PM/UI/Components/CardList.js
+++ b/frontend/delta/js/Clipperz/PM/UI/Components/CardList.js
@@ -76,86 +76,93 @@ Clipperz.PM.UI.Components.CardList = React.createClass({
76 76
77 focusOnSearchField: function () { 77 focusOnSearchField: function () {
78console.log("focusOnSearchField", this.refs['searchField']); 78console.log("focusOnSearchField", this.refs['searchField']);
79 this.refs['searchField'].getDOMNode.focus(); 79 this.refs['searchField'].getDOMNode.focus();
80 }, 80 },
81 81
82 searchBox: function () { 82 searchBox: function () {
83 var result; 83 var result;
84 84
85 if (this.state.showSearch) { 85 if (this.state.showSearch) {
86 result =React.DOM.div({className:'searchBox'}, [ 86 result =React.DOM.div({className:'searchBox'}, [
87 React.DOM.div(null, [ 87 React.DOM.div(null, [
88 React.DOM.input({type:'search', placeholder:"search", ref:'searchField', onChange:this.updateSearchText}) 88 React.DOM.input({type:'search', placeholder:"search", ref:'searchField', onChange:this.updateSearchText})
89 ]) 89 ])
90 ]); 90 ]);
91 } else { 91 } else {
92 result = null; 92 result = null;
93 } 93 }
94 94
95 return result; 95 return result;
96 }, 96 },
97 97
98 //========================================================================= 98 //=========================================================================
99 99
100 showPreferences: function (anEvent) {
101 MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'showPreferences', anEvent);
102 },
103
104 //=========================================================================
105
100 cardItem: function (aRecordReference) { 106 cardItem: function (aRecordReference) {
101 varreference = aRecordReference['_reference']; 107 varreference = aRecordReference['_reference'];
102 varselectedCard = (reference == this.props.selectedCard); 108 varselectedCard = (reference == this.props.selectedCard);
103 109
104 returnReact.DOM.div({className:'listItem', onClick:MochiKit.Base.method(this, 'handleClickOnCardDetail', reference)}, [ 110 //TODO: verify if it is possible to put the onClick handler on the container 'div', instead of adding it to each 'div' item.
111 returnReact.DOM.div({className:'listItem', key:reference, onClick:MochiKit.Base.method(this, 'handleClickOnCardDetail', reference)}, [
105 React.DOM.div({className:'labelWrapper'}, React.DOM.span({className:'label'}, aRecordReference.label)), 112 React.DOM.div({className:'labelWrapper'}, React.DOM.span({className:'label'}, aRecordReference.label)),
106 // React.DOM.div({className:'labelWrapper'}, React.DOM.span({className:'label'}, aRecordReference.label + ' ' + aRecordReference.label + ' ' + aRecordReference.label + ' ' + aRecordReference.label + ' ' + aRecordReference.label)), 113 // React.DOM.div({className:'labelWrapper'}, React.DOM.span({className:'label'}, aRecordReference.label + ' ' + aRecordReference.label + ' ' + aRecordReference.label + ' ' + aRecordReference.label + ' ' + aRecordReference.label)),
107 React.DOM.div({className:'faviconWrapper'}, aRecordReference.favicon ? React.DOM.img({className:'favicon', src:aRecordReference.favicon}) : React.DOM.div({className:'favicon'}, '\u00A0')), 114 React.DOM.div({className:'faviconWrapper'}, aRecordReference.favicon ? React.DOM.img({className:'favicon', src:aRecordReference.favicon}) : React.DOM.div({className:'favicon'}, '\u00A0')),
108 React.DOM.div({className:'detailLinkWrapper'}, React.DOM.span({className:'detailLink ' + (selectedCard ? 'icon-spin' : '')}, (selectedCard ? "loading" : "detail"))) 115 React.DOM.div({className:'detailLinkWrapper'}, React.DOM.span({className:'detailLink ' + (selectedCard ? 'icon-spin' : '')}, (selectedCard ? "loading" : "detail")))
109 ]); 116 ]);
110 }, 117 },
111 118
112 handleClickOnCardDetail: function (aRecordReference, anEvent) { 119 handleClickOnCardDetail: function (aRecordReference, anEvent) {
113 MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'showRecord', aRecordReference); 120 MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'showRecord', aRecordReference);
114 }, 121 },
115 122
116 cardListItems: function () { 123 cardListItems: function () {
117 varlist; 124 varlist;
118 varresult; 125 varresult;
119 126
120 list = this.props['cardList']; 127 list = this.props['cardList'];
121 128
122 if (typeof(list) != 'undefined') { 129 if (typeof(list) != 'undefined') {
123 result = MochiKit.Base.map(MochiKit.Base.method(this, 'cardItem'), list); 130 result = MochiKit.Base.map(MochiKit.Base.method(this, 'cardItem'), list);
124 } else { 131 } else {
125 result = null; 132 result = null;
126 } 133 }
127 134
128 return result; 135 return result;
129 }, 136 },
130 137
131 //========================================================================= 138 //=========================================================================
132 139
133 handleChange: function (anEvent) { 140 handleChange: function (anEvent) {
134 // varrefs = this.refs; 141 // varrefs = this.refs;
135 // var refName = MochiKit.Base.filter(function (aRefName) { return refs[aRefName].getDOMNode() == anEvent.target}, MochiKit.Base.keys(this.refs))[0]; 142 // var refName = MochiKit.Base.filter(function (aRefName) { return refs[aRefName].getDOMNode() == anEvent.target}, MochiKit.Base.keys(this.refs))[0];
136 // var newState = {}; 143 // var newState = {};
137// 144//
138 // newState[refName] = event.target.value; 145 // newState[refName] = event.target.value;
139 // this.setState(newState); 146 // this.setState(newState);
140 }, 147 },
141 148
142 //========================================================================= 149 //=========================================================================
143 150
144 render: function() { 151 render: function() {
145 returnReact.DOM.div(null, [ 152 returnReact.DOM.div(null, [
146 React.DOM.div({className:'header'}, [ 153 React.DOM.div({className:'header'}, [
147 React.DOM.a({className:'account'}, 'clipperz'), 154 React.DOM.a({className:'account'}, 'clipperz'),
148 React.DOM.div({className:'features'}, [ 155 React.DOM.div({className:'features'}, [
149 React.DOM.a({className:'addCard'}, 'add'), 156 // React.DOM.a({className:'addCard'}, 'add'),
150 React.DOM.a({className:'search ' + (this.state.showSearch ? 'selected' : ''), onClick:this.toggleSearch}, 'search'), 157 React.DOM.a({className:'search ' + (this.state.showSearch ? 'selected' : ''), onClick:this.toggleSearch}, 'search'),
151 React.DOM.a({className:'settings'}, 'settings') 158 React.DOM.a({className:'settings', onClick:this.showPreferences}, 'settings')
152 ]), 159 ]),
153 // this.searchBox() 160 // this.searchBox()
154 ]), 161 ]),
155 this.searchBox(), 162 this.searchBox(),
156 React.DOM.div({className:'content cardList'}, this.cardListItems()), 163 React.DOM.div({className:'content cardList'}, this.cardListItems()),
157 ]); 164 ]);
158 } 165 }
159 166
160 //========================================================================= 167 //=========================================================================
161}); 168});
diff --git a/frontend/delta/js/Clipperz/PM/UI/Components/Checkbox.js b/frontend/delta/js/Clipperz/PM/UI/Components/Checkbox.js
new file mode 100644
index 0000000..9538063
--- a/dev/null
+++ b/frontend/delta/js/Clipperz/PM/UI/Components/Checkbox.js
@@ -0,0 +1,44 @@
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.PM.UI.Components.Checkbox = React.createClass({
25 //http://development.tobypitman.com/iphoneCheckboxes/iphoneCheckboxes2.html
26
27 propTypes: {
28 'checked': React.PropTypes.bool.isRequired,
29 'id': React.PropTypes.string.isRequired,
30 'eventHandler':React.PropTypes.func.isRequired
31 },
32
33 //=========================================================================
34
35 render: function () {
36 returnReact.DOM.div({className:'checkbox', onClick:this.props['eventHandler']}, [
37 React.DOM.input({name:this.props['id'], id:this.props['id'], value:this.props['id'], type:'checkbox', checked:this.props['checked']}),
38 React.DOM.label({className:'check', 'for':this.props['id']}),
39 React.DOM.label({className:'info', 'for':this.props['id']}, "enable local storage")
40 ]);
41 }
42
43 //=========================================================================
44});
diff --git a/frontend/delta/js/Clipperz/PM/UI/Components/LoginForm.js b/frontend/delta/js/Clipperz/PM/UI/Components/LoginForm.js
index 2b5b4a4..801549f 100644
--- a/frontend/delta/js/Clipperz/PM/UI/Components/LoginForm.js
+++ b/frontend/delta/js/Clipperz/PM/UI/Components/LoginForm.js
@@ -71,56 +71,56 @@ Clipperz.PM.UI.Components.LoginForm = React.createClass({
71 } 71 }
72 MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'doLogin', credentials); 72 MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'doLogin', credentials);
73 }, 73 },
74 74
75 handleRegistrationLinkClick: function (event) { 75 handleRegistrationLinkClick: function (event) {
76 event.preventDefault(); 76 event.preventDefault();
77 MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'showRegistrationForm'); 77 MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'showRegistrationForm');
78 }, 78 },
79 79
80 //------------------------------------------------------------------------- 80 //-------------------------------------------------------------------------
81 81
82 shouldEnableLoginButton: function () { 82 shouldEnableLoginButton: function () {
83 var result; 83 var result;
84 84
85 return( 85 return(
86 ((this.state['username'] != '') && (this.state['passphrase'] != '')) 86 ((this.state['username'] != '') && (this.state['passphrase'] != ''))
87 || 87 ||
88 (this.state['pin'] != '') 88 (this.state['pin'] != '')
89 ) && !this.props['disabled']; 89 ) && !this.props['disabled'];
90 }, 90 },
91 91
92 92
93 loginForm: function () { 93 loginForm: function () {
94 registrationLink =React.DOM.div({'className':'registrationLink'}, [ 94 registrationLink =React.DOM.div({'className':'registrationLink'}, [
95 React.DOM.a({'onClick':this.handleRegistrationLinkClick}, "Need an account") 95 React.DOM.a({'onClick':this.handleRegistrationLinkClick}, "Sign up")
96 ]); 96 ]);
97 returnReact.DOM.div({'className':'loginForm credentials'},[ 97 returnReact.DOM.div({'className':'loginForm credentials'},[
98 React.DOM.form({onChange: this.handleChange, onSubmit:this.handleCredentialSubmit}, [ 98 React.DOM.form({onChange: this.handleChange, onSubmit:this.handleCredentialSubmit}, [
99 React.DOM.div(null,[ 99 React.DOM.div(null,[
100 React.DOM.label({'for':'name'}, "username"), 100 React.DOM.label({'for' :'name'}, "username"),
101 React.DOM.input({'type':'text', 'name':'name', 'ref':'username', 'placeholder':"username", 'key':'username', 'autoCapitalize':'none'}), 101 React.DOM.input({'type':'text', 'name':'name', 'ref':'username', 'placeholder':"username", 'key':'username', 'autoCapitalize':'none'}),
102 React.DOM.label({'for':'passphrase'}, "passphrase"), 102 React.DOM.label({'for' :'passphrase'}, "passphrase"),
103 React.DOM.input({'type':'password', 'name':'passphrase', 'ref':'passphrase', 'placeholder':"passphrase", 'key':'passphrase'}) 103 React.DOM.input({'type':'password', 'name':'passphrase', 'ref':'passphrase', 'placeholder':"passphrase", 'key':'passphrase'})
104 ]), 104 ]),
105 React.DOM.button({'type':'submit', 'disabled':!this.shouldEnableLoginButton(), 'className':'button'}, "login") 105 React.DOM.button({'type':'submit', 'disabled':!this.shouldEnableLoginButton(), 'className':'button'}, "login")
106 ]), 106 ]),
107 this.props.isNewUserRegistrationAvailable ? registrationLink : null 107 this.props.isNewUserRegistrationAvailable ? registrationLink : null
108 ]); 108 ]);
109 }, 109 },
110 110
111 handlePINSubmit: function (event) { 111 handlePINSubmit: function (event) {
112 event.preventDefault(); 112 event.preventDefault();
113 113
114 this.refs['pin'].getDOMNode().blur(); 114 this.refs['pin'].getDOMNode().blur();
115 115
116 var credentials = { 116 var credentials = {
117 pin: this.refs['pin'].getDOMNode().value 117 pin: this.refs['pin'].getDOMNode().value
118 } 118 }
119 119
120 MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'doLogin', credentials); 120 MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'doLogin', credentials);
121 }, 121 },
122 122
123 pinForm: function () { 123 pinForm: function () {
124 returnReact.DOM.div({'className':'loginForm pin'},[ 124 returnReact.DOM.div({'className':'loginForm pin'},[
125 React.DOM.form({onChange: this.handleChange, onSubmit:this.handlePINSubmit}, [ 125 React.DOM.form({onChange: this.handleChange, onSubmit:this.handlePINSubmit}, [
126 React.DOM.div(null,[ 126 React.DOM.div(null,[
diff --git a/frontend/delta/js/Clipperz/PM/UI/Components/Overlay.js b/frontend/delta/js/Clipperz/PM/UI/Components/Overlay.js
index cc4a06c..cb5f81a 100644
--- a/frontend/delta/js/Clipperz/PM/UI/Components/Overlay.js
+++ b/frontend/delta/js/Clipperz/PM/UI/Components/Overlay.js
@@ -73,50 +73,51 @@ Clipperz.Base.extend(Clipperz.PM.UI.Components.Overlay, Object, {
73 'resetStatus': function () { 73 'resetStatus': function () {
74 MochiKit.Style.showElement(this.element()); 74 MochiKit.Style.showElement(this.element());
75 MochiKit.Style.showElement(this.getElement('spinner')); 75 MochiKit.Style.showElement(this.getElement('spinner'));
76 MochiKit.Style.hideElement(this.getElement('done')); 76 MochiKit.Style.hideElement(this.getElement('done'));
77 MochiKit.Style.hideElement(this.getElement('failed')); 77 MochiKit.Style.hideElement(this.getElement('failed'));
78 }, 78 },
79 79
80 'setMessage': function (aMessage) { 80 'setMessage': function (aMessage) {
81 if (typeof(aMessage) != 'undefined') { 81 if (typeof(aMessage) != 'undefined') {
82 this.getElement('title').innerHTML = aMessage; 82 this.getElement('title').innerHTML = aMessage;
83 } 83 }
84 }, 84 },
85 85
86 'completed': function (aFunctionToShowResult, aMessage, aDelayBeforeHiding) { 86 'completed': function (aFunctionToShowResult, aMessage, aDelayBeforeHiding) {
87 var delay = aDelayBeforeHiding || this.defaultDelay(); 87 var delay = aDelayBeforeHiding || this.defaultDelay();
88 88
89 this.hideSpinner(); 89 this.hideSpinner();
90 MochiKit.Base.bind(aFunctionToShowResult, this)(); 90 MochiKit.Base.bind(aFunctionToShowResult, this)();
91 this.setMessage(aMessage); 91 this.setMessage(aMessage);
92 92
93 MochiKit.Async.callLater(delay, MochiKit.Base.bind(this.hide, this)) 93 MochiKit.Async.callLater(delay, MochiKit.Base.bind(this.hide, this))
94 }, 94 },
95 95
96 'hide': function () { 96 'hide': function () {
97 MochiKit.DOM.removeElementClass(this.element(), 'ios-overlay-show'); 97 var element = this.element();
98 MochiKit.DOM.addElementClass(this.element(), 'ios-overlay-hide'); 98 MochiKit.DOM.removeElementClass(element, 'ios-overlay-show');
99 MochiKit.Async.callLater(1, MochiKit.Style.hideElement, this.element()); 99 MochiKit.DOM.addElementClass(element, 'ios-overlay-hide');
100 MochiKit.Async.callLater(1, MochiKit.Style.hideElement, element);
100 }, 101 },
101 102
102 'hideSpinner': function () { 103 'hideSpinner': function () {
103 MochiKit.Style.hideElement(this.getElement('spinner')); 104 MochiKit.Style.hideElement(this.getElement('spinner'));
104 }, 105 },
105 106
106 'showDoneIcon': function () { 107 'showDoneIcon': function () {
107 MochiKit.Style.showElement(this.getElement('done')); 108 MochiKit.Style.showElement(this.getElement('done'));
108 }, 109 },
109 110
110 'showFailIcon': function () { 111 'showFailIcon': function () {
111 MochiKit.Style.showElement(this.getElement('failed')); 112 MochiKit.Style.showElement(this.getElement('failed'));
112 }, 113 },
113 114
114 //------------------------------------------------------------------------- 115 //-------------------------------------------------------------------------
115 116
116 'defaultDelay': function () { 117 'defaultDelay': function () {
117 return this._defaultDelay; 118 return this._defaultDelay;
118 }, 119 },
119 120
120 //------------------------------------------------------------------------- 121 //-------------------------------------------------------------------------
121 __syntaxFix__: "syntax fix" 122 __syntaxFix__: "syntax fix"
122}); 123});
diff --git a/frontend/delta/js/Clipperz/PM/UI/Components/PreferencePage.js b/frontend/delta/js/Clipperz/PM/UI/Components/PreferencePage.js
new file mode 100644
index 0000000..822acc2
--- a/dev/null
+++ b/frontend/delta/js/Clipperz/PM/UI/Components/PreferencePage.js
@@ -0,0 +1,88 @@
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.PM.UI.Components.PreferencePage = React.createClass({
25
26 getDefaultProps: function () {
27 return {
28 }
29 },
30
31 propTypes: {
32 // card: React.PropTypes.object.isRequired
33 // checked: React.PropTypes.boolean.isRequired
34 },
35
36 getInitialState: function () {
37 // return {
38 // shouldStoreDataLocally: false
39 // };
40 },
41
42 handleBackClick: function (anEvent) {
43 MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'goBack');
44 },
45
46 toggleShouldStoreDataLocally: function (anEvent) {
47 // this.setState({shouldStoreDataLocally: !this.state['shouldStoreDataLocally']});
48 Clipperz.PM.DataModel.devicePreferences.setShouldStoreDataLocally(!Clipperz.PM.DataModel.devicePreferences.shouldStoreDataLocally());
49 this.setState({});
50 },
51
52 shouldStoreDataLocally: function () {
53 return Clipperz.PM.DataModel.devicePreferences.shouldStoreDataLocally();
54 },
55
56 syncNow: function (anEvent) {
57 MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'synchronizeLocalData');
58 },
59
60 //=========================================================================
61
62 render: function () {
63 returnReact.DOM.div({className:'preferences'}, [
64 React.DOM.div({className:'header'}, [
65 React.DOM.div({className:'titleWrapper'}, React.DOM.div({className:'title'}, "Preferences")),
66 React.DOM.div({className:'backWrapper'}, React.DOM.a({className:'button back', onClick:this.handleBackClick}, "back")),
67 ]),
68 React.DOM.div({className:'content'}, [
69 React.DOM.form(null, [
70 React.DOM.div({className:'section'}, [
71 React.DOM.h4(null, "Local storage"),
72 React.DOM.p(null, "Store you account data locally for offline viewing"),
73 new Clipperz.PM.UI.Components.Checkbox({'id':'shouldStoreLocally_checkbox', 'checked':this.shouldStoreDataLocally(), 'eventHandler':this.toggleShouldStoreDataLocally}),
74 this.shouldStoreDataLocally() ? React.DOM.div({className:'syncInfo'}, [
75 // React.DOM.h5(null, "data were never synchronized before"),
76 React.DOM.a({className:'button', onClick:this.syncNow}, "Sync now")
77 ]) : null
78 ])
79 ])
80 ]),
81 React.DOM.div({className:'footer'}, [
82
83 ])
84 ]);
85 }
86
87 //=========================================================================
88});
diff --git a/frontend/delta/js/Clipperz/PM/UI/MainController.js b/frontend/delta/js/Clipperz/PM/UI/MainController.js
index da7540e..20ff041 100644
--- a/frontend/delta/js/Clipperz/PM/UI/MainController.js
+++ b/frontend/delta/js/Clipperz/PM/UI/MainController.js
@@ -5,174 +5,234 @@ Copyright 2008-2013 Clipperz Srl
5This file is part of Clipperz, the online password manager. 5This file is part of Clipperz, the online password manager.
6For further information about its features and functionalities please 6For further information about its features and functionalities please
7refer to http://www.clipperz.com. 7refer to http://www.clipperz.com.
8 8
9* Clipperz is free software: you can redistribute it and/or modify it 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 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 11 by the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version. 12 (at your option) any later version.
13 13
14* Clipperz is distributed in the hope that it will be useful, but 14* Clipperz is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of 15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 See the GNU Affero General Public License for more details. 17 See the GNU Affero General Public License for more details.
18 18
19* You should have received a copy of the GNU Affero General Public 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/. 20 License along with Clipperz. If not, see http://www.gnu.org/licenses/.
21 21
22*/ 22*/
23 23
24Clipperz.Base.module('Clipperz.PM.UI'); 24Clipperz.Base.module('Clipperz.PM.UI');
25 25
26Clipperz.PM.UI.MainController = function() { 26Clipperz.PM.UI.MainController = function() {
27 var pages; 27 var pages;
28 28
29 this._proxy = null; 29 // this._proxy = null;
30 this._user = null; 30 this._user = null;
31 this._filter= ''; 31 this._filter= '';
32 32
33 //this._currentPage = 'loadingPage'; 33 //this._currentPage = 'loadingPage';
34 34
35 this._pageStack = ['loadingPage']; 35 this._pageStack = ['loadingPage'];
36 this._overlay = new Clipperz.PM.UI.Components.Overlay(); 36 this._overlay = new Clipperz.PM.UI.Components.Overlay();
37 pages = { 37 pages = {
38 'loginPage': new Clipperz.PM.UI.Components.LoginForm(), 38 'loginPage': new Clipperz.PM.UI.Components.LoginForm(),
39 'registrationPage':new Clipperz.PM.UI.Components.RegistrationWizard(), 39 'registrationPage':new Clipperz.PM.UI.Components.RegistrationWizard(),
40 'cardListPage': new Clipperz.PM.UI.Components.CardList(), 40 'cardListPage': new Clipperz.PM.UI.Components.CardList(),
41 'cardDetailPage':new Clipperz.PM.UI.Components.CardDetail({card: {}}), 41 'cardDetailPage':new Clipperz.PM.UI.Components.CardDetail({card: {}}),
42 'preferencePage':new Clipperz.PM.UI.Components.PreferencePage(),
42 'errorPage': new Clipperz.PM.UI.Components.ErrorPage({message:''}) 43 'errorPage': new Clipperz.PM.UI.Components.ErrorPage({message:''})
43 }; 44 };
44 45
45 MochiKit.Base.map(function (anId) {React.renderComponent(pages[anId], MochiKit.DOM.getElement(anId))}, MochiKit.Base.keys(pages)); 46 MochiKit.Base.map(function (anId) {React.renderComponent(pages[anId], MochiKit.DOM.getElement(anId))}, MochiKit.Base.keys(pages));
46 this._pages = pages; 47 this._pages = pages;
47 this.registerForNotificationCenterEvents(); 48 this.registerForNotificationCenterEvents();
49 MochiKit.Signal.connect(MochiKit.DOM.currentDocument(), 'onselectionchange', this, 'selectionChangeHandler');
48 50
49 return this; 51 return this;
50} 52}
51 53
52MochiKit.Base.update(Clipperz.PM.UI.MainController.prototype, { 54MochiKit.Base.update(Clipperz.PM.UI.MainController.prototype, {
53 55
54 toString: function () { 56 toString: function () {
55 return "Clipperz.PM.UI.MainController"; 57 return "Clipperz.PM.UI.MainController";
56 }, 58 },
57 59
58 //========================================================================= 60 //=========================================================================
59 61
60 overlay: function () { 62 overlay: function () {
61 return this._overlay; 63 return this._overlay;
62 }, 64 },
63 65
64 loginForm: function () { 66 loginForm: function () {
65 return this._loginForm; 67 return this._loginForm;
66 }, 68 },
67 69
68 registrationWizard: function () { 70 registrationWizard: function () {
69 return this._registrationWizard; 71 return this._registrationWizard;
70 }, 72 },
71 73
72 //========================================================================= 74 //=========================================================================
73 75
74 isOnline: function() { 76 isOnline: function() {
75 return navigator.onLine; 77 return navigator.onLine;
78 // return false;
76 }, 79 },
77 80
78 hasLocalData: function() { 81 hasLocalData: function() {
79 return false; 82 // return false;
83 return (Clipperz.PM.DataModel.devicePreferences.accountData() != null);
80 }, 84 },
81 85
82 loginMode: function () { 86 loginMode: function () {
83 //PIN is set using this command: 87 //PIN is set using this command:
84 //Clipperz.PM.PIN.setCredentialsWithPIN('1234', {'username':'joe', 'passphrase':'clipperz'}); 88 //Clipperz.PM.PIN.setCredentialsWithPIN('1234', {'username':'joe', 'passphrase':'clipperz'});
85 89
86 return Clipperz.PM.PIN.isSet() ? 'PIN' : 'CREDENTIALS'; 90 return Clipperz.PM.PIN.isSet() ? 'PIN' : 'CREDENTIALS';
87 }, 91 },
88 92
89 //========================================================================= 93 //=========================================================================
90 94
91 pages: function () { 95 pages: function () {
92 return this._pages; 96 return this._pages;
93 }, 97 },
94 98
95 pageStack: function () { 99 pageStack: function () {
96 return this._pageStack; 100 return this._pageStack;
97 }, 101 },
98 102
99 //========================================================================= 103 //=========================================================================
100 104
105 showOfflineError: function () {
106console.log("THE BROWSER IS OFFLINE");
107 },
108
101 selectInitialProxy: function () { 109 selectInitialProxy: function () {
102 if (this.isOnline()) { 110 if (this.isOnline()) {
103 this._proxy = Clipperz.PM.Proxy.defaultProxy; 111 // this._proxy = Clipperz.PM.Proxy.defaultProxy;
104 } else { 112 } else {
105 if (this.hasLocalData()) { 113 if (this.hasLocalData()) {
106 this._proxy = new Clipperz.PM.Proxy.Offline({dataStore: new Clipperz.PM.Proxy.Offline.LocalStorageDataStore(), shouldPayTolls:false}); 114 // this._proxy = new Clipperz.PM.Proxy.Offline({dataStore: new Clipperz.PM.Proxy.Offline.LocalStorageDataStore(), shouldPayTolls:false});
115 Clipperz.PM.Proxy.defaultProxy = new Clipperz.PM.Proxy.Offline({dataStore: new Clipperz.PM.Proxy.Offline.LocalStorageDataStore(), shouldPayTolls:false});
107 } else { 116 } else {
108 this.showOfflineError(); 117 this.showOfflineError();
109 } 118 }
110 } 119 }
111 }, 120 },
112 121
113 proxy: function () { 122 //proxy: function () {
114 return this._proxy; 123 // return this._proxy;
115 }, 124 //},
116 125
117 //========================================================================= 126 //=========================================================================
118 127
119 registerForNotificationCenterEvents: function () { 128 registerForNotificationCenterEvents: function () {
120 var events= ['doLogin', 'registerNewUser', 'showRegistrationForm', 'goBack', 'showRecord', 'searchCards', 'runDirectLogin']; 129 var events= [
130 'doLogin',
131 'registerNewUser',
132 'showRegistrationForm',
133 'goBack',
134 'showRecord',
135 'searchCards',
136 'showPreferences',
137 'runDirectLogin',
138 'synchronizeLocalData'
139 ];
121 var self= this; 140 var self= this;
122 141
123 MochiKit.Base.map(function (anEvent) { 142 MochiKit.Base.map(function (anEvent) {
124 MochiKit.Signal.connect(Clipperz.Signal.NotificationCenter, anEvent, MochiKit.Base.method(self, anEvent)); 143 MochiKit.Signal.connect(Clipperz.Signal.NotificationCenter, anEvent, MochiKit.Base.method(self, anEvent));
125 }, events); 144 }, events);
126 145
127 // MochiKit.Signal.connect(window, 'onpopstate', MochiKit.Base.method(this, 'historyGoBack')); 146 // MochiKit.Signal.connect(window, 'onpopstate', MochiKit.Base.method(this, 'historyGoBack'));
128 MochiKit.Signal.connect(window, 'onbeforeunload',MochiKit.Base.method(this, 'shouldExitApp')); 147 MochiKit.Signal.connect(window, 'onbeforeunload',MochiKit.Base.method(this, 'shouldExitApp'));
129 }, 148 },
130 149
131 //------------------------------------------------------------------------- 150 //-------------------------------------------------------------------------
132 151
152 selectionChangeHandler: function (anEvent) {
153 varselection;
154 varselectionRange;
155 varselectionNode;
156 varvalueElement;
157 //other hints: http://www.bearpanther.com/2013/05/27/easy-text-selection-in-mobile-safari/
158 //SELECTION: https://developer.mozilla.org/en-US/docs/Web/API/Selection
159 //RANGE: https://developer.mozilla.org/en-US/docs/Web/API/Range
160 //NODE TYPES: https://developer.mozilla.org/en-US/docs/Web/API/Node.nodeType
161
162 selection = MochiKit.DOM.currentWindow().getSelection();
163//console.log("-- selection", selection);
164 selectionRange = selection.getRangeAt(0);
165 selectionNode = selectionRange.startContainer.childNodes[selectionRange.startOffset];
166//console.log("-- selectionNode", selectionNode);
167
168 if (selectionNode != undefined) {
169 valueElement = MochiKit.DOM.getFirstElementByTagAndClassName('*', 'value', selectionNode);
170//console.log("-- valueElement", valueElement);
171 }
172
173 if ((valueElement != null) && (valueElement != selectionNode)) {
174 var range;
175 range = MochiKit.DOM.currentDocument().createRange();
176 range.selectNodeContents(valueElement);
177 selection.removeAllRanges();
178 selection.addRange(range);
179
180 anEvent.preventDefault();
181 anEvent.stopPropagation();
182
183//console.log("updated selection", MochiKit.DOM.currentWindow().getSelection());
184 }
185//console.log("-----------");
186 },
187
188 //-------------------------------------------------------------------------
189
133 run: function (parameters) { 190 run: function (parameters) {
134 var shouldShowRegistrationForm; 191 var shouldShowRegistrationForm;
192 varcanRegisterNewUsers;
193
194 canRegisterNewUsers = Clipperz.PM.Proxy.defaultProxy.canRegisterNewUsers();
135 195
136 this.selectInitialProxy(); 196 this.selectInitialProxy();
137 shouldShowRegistrationForm = parameters['shouldShowRegistrationForm'] && this.proxy().canRegisterNewUsers(); 197 shouldShowRegistrationForm = parameters['shouldShowRegistrationForm'] && canRegisterNewUsers;
138 this.pages()['loginPage'].setProps({'mode':this.loginMode(), 'isNewUserRegistrationAvailable': this.proxy().canRegisterNewUsers()}); 198 this.pages()['loginPage'].setProps({'mode':this.loginMode(), 'isNewUserRegistrationAvailable':canRegisterNewUsers});
139 199
140 if (shouldShowRegistrationForm) { 200 if (shouldShowRegistrationForm) {
141 this.showRegistrationForm(); 201 this.showRegistrationForm();
142 } else { 202 } else {
143 this.showLoginForm(); 203 this.showLoginForm();
144 } 204 }
145 this.overlay().done("", 0.5); 205 this.overlay().done("", 0.5);
146 }, 206 },
147 207
148 //------------------------------------------------------------------------- 208 //-------------------------------------------------------------------------
149 209
150 showLoginForm: function () { 210 showLoginForm: function () {
151 varloginFormPage; 211 varloginFormPage;
152 212
153 loginFormPage = this.pages()['loginPage']; 213 loginFormPage = this.pages()['loginPage'];
154 loginFormPage.setProps({'mode':this.loginMode(), 'isNewUserRegistrationAvailable': this.proxy().canRegisterNewUsers()}); 214 loginFormPage.setProps({'mode':this.loginMode(), 'isNewUserRegistrationAvailable':Clipperz.PM.Proxy.defaultProxy.canRegisterNewUsers()});
155 this.moveInPage(this.currentPage(), 'loginPage'); 215 this.moveInPage(this.currentPage(), 'loginPage');
156 MochiKit.Async.callLater(0.5, MochiKit.Base.method(loginFormPage, 'setInitialFocus')); 216 MochiKit.Async.callLater(0.5, MochiKit.Base.method(loginFormPage, 'setInitialFocus'));
157 }, 217 },
158 218
159 showRegistrationForm: function () { 219 showRegistrationForm: function () {
160 var currentPage; 220 var currentPage;
161 varregistrationPage; 221 varregistrationPage;
162 222
163 currentPage = this.currentPage(); 223 currentPage = this.currentPage();
164 registrationPage = this.pages()['registrationPage']; 224 registrationPage = this.pages()['registrationPage'];
165 this.setCurrentPage('loginPage'); 225 this.setCurrentPage('loginPage');
166 registrationPage.setProps({}); 226 registrationPage.setProps({});
167 this.moveInPage(currentPage, 'registrationPage'); 227 this.moveInPage(currentPage, 'registrationPage');
168 MochiKit.Async.callLater(0.5, MochiKit.Base.method(registrationPage, 'setInitialFocus')); 228 MochiKit.Async.callLater(0.5, MochiKit.Base.method(registrationPage, 'setInitialFocus'));
169 }, 229 },
170 230
171 //========================================================================= 231 //=========================================================================
172 232
173 doLogin: function (event) { 233 doLogin: function (event) {
174 varcredentials; 234 varcredentials;
175 var getPassphraseDelegate; 235 var getPassphraseDelegate;
176 varuser; 236 varuser;
177 237
178 user = null; 238 user = null;
@@ -181,51 +241,51 @@ MochiKit.Base.update(Clipperz.PM.UI.MainController.prototype, {
181 this.pages()['loginPage'].setProps({disabled:true}); 241 this.pages()['loginPage'].setProps({disabled:true});
182 242
183 if ('pin' in event) { 243 if ('pin' in event) {
184 credentials = Clipperz.PM.PIN.credentialsWithPIN(event['pin']); 244 credentials = Clipperz.PM.PIN.credentialsWithPIN(event['pin']);
185 } else { 245 } else {
186 credentials = event; 246 credentials = event;
187 } 247 }
188 getPassphraseDelegate = MochiKit.Base.partial(MochiKit.Async.succeed, credentials.passphrase); 248 getPassphraseDelegate = MochiKit.Base.partial(MochiKit.Async.succeed, credentials.passphrase);
189 user = new Clipperz.PM.DataModel.User({'username':credentials.username, 'getPassphraseFunction':getPassphraseDelegate}); 249 user = new Clipperz.PM.DataModel.User({'username':credentials.username, 'getPassphraseFunction':getPassphraseDelegate});
190 250
191 deferredResult = new Clipperz.Async.Deferred('MainController.doLogin', {trace:false}); 251 deferredResult = new Clipperz.Async.Deferred('MainController.doLogin', {trace:false});
192 deferredResult.addCallback(MochiKit.Async.wait, 0.1); 252 deferredResult.addCallback(MochiKit.Async.wait, 0.1);
193 deferredResult.addMethod(Clipperz.Crypto.PRNG.defaultRandomGenerator(), 'deferredEntropyCollection'); 253 deferredResult.addMethod(Clipperz.Crypto.PRNG.defaultRandomGenerator(), 'deferredEntropyCollection');
194 deferredResult.addMethod(user, 'login'); 254 deferredResult.addMethod(user, 'login');
195 deferredResult.addMethod(Clipperz.PM.PIN, 'resetFailedAttemptCount'); 255 deferredResult.addMethod(Clipperz.PM.PIN, 'resetFailedAttemptCount');
196 deferredResult.addMethod(this, 'setUser', user); 256 deferredResult.addMethod(this, 'setUser', user);
197 257
198 // deferredResult.addMethod(this, 'setupApplication'); 258 // deferredResult.addMethod(this, 'setupApplication');
199 deferredResult.addMethod(this, 'runApplication'); 259 deferredResult.addMethod(this, 'runApplication');
200 deferredResult.addMethod(this.overlay(), 'done', "", 1); 260 deferredResult.addMethod(this.overlay(), 'done', "", 1);
201 deferredResult.addErrback(MochiKit.Base.method(this, 'genericErrorHandler', event)); 261 deferredResult.addErrback(MochiKit.Base.method(this, 'genericErrorHandler', event));
202 deferredResult.addErrback(MochiKit.Base.bind(function (anEvent, anError) { 262 deferredResult.addErrback(MochiKit.Base.bind(function (anEvent, anError) {
203 if (anError['isPermanent'] != true) { 263 if (anError['isPermanent'] != true) {
204 this.pages()['loginPage'].setProps({disabled:false, 'mode':this.loginMode()}); 264 this.pages()['loginPage'].setProps({disabled:false, 'mode':this.loginMode()});
205 this.pages()['loginPage'].setInitialFocus(); 265 this.pages()['loginPage'].setInitialFocus();
206 } 266 }
207 return anError; 267 return anError;
208 }, this, event)) 268 }, this, event))
209 deferredResult.callback(); 269 deferredResult.callback();
210 270
211 return deferredResult; 271 return deferredResult;
212 }, 272 },
213 273
214 //------------------------------------------------------------------------- 274 //-------------------------------------------------------------------------
215 275
216 registerNewUser: function (credentials) { 276 registerNewUser: function (credentials) {
217 vardeferredResult; 277 vardeferredResult;
218 278
219 this.overlay().show("creating user"); 279 this.overlay().show("creating user");
220 280
221 this.pages()['registrationPage'].setProps({disabled:true}); 281 this.pages()['registrationPage'].setProps({disabled:true});
222 deferredResult = new Clipperz.Async.Deferred('MainController.registerNewUser', {trace:false}); 282 deferredResult = new Clipperz.Async.Deferred('MainController.registerNewUser', {trace:false});
223 deferredResult.addCallback(Clipperz.PM.DataModel.User.registerNewAccount, 283 deferredResult.addCallback(Clipperz.PM.DataModel.User.registerNewAccount,
224 credentials['username'], 284 credentials['username'],
225 MochiKit.Base.partial(MochiKit.Async.succeed, credentials['passphrase']) 285 MochiKit.Base.partial(MochiKit.Async.succeed, credentials['passphrase'])
226 ); 286 );
227 deferredResult.addMethod(this, 'doLogin', credentials); 287 deferredResult.addMethod(this, 'doLogin', credentials);
228 deferredResult.addErrback(MochiKit.Base.method(this, 'genericErrorHandler', event)); 288 deferredResult.addErrback(MochiKit.Base.method(this, 'genericErrorHandler', event));
229 deferredResult.addErrback(MochiKit.Base.bind(function (anError) { 289 deferredResult.addErrback(MochiKit.Base.bind(function (anError) {
230 if (anError['isPermanent'] != true) { 290 if (anError['isPermanent'] != true) {
231 this.pages()['registrationPage'].setProps({disabled:false}); 291 this.pages()['registrationPage'].setProps({disabled:false});
@@ -302,95 +362,108 @@ MochiKit.Base.update(Clipperz.PM.UI.MainController.prototype, {
302 }, this)); 362 }, this));
303 deferredResult.callback(); 363 deferredResult.callback();
304 364
305 return deferredResult; 365 return deferredResult;
306 }, 366 },
307 367
308 filter: function (){ 368 filter: function (){
309 return this._filter; 369 return this._filter;
310 }, 370 },
311 371
312 setFilter: function (aValue) { 372 setFilter: function (aValue) {
313 this._filter = aValue; 373 this._filter = aValue;
314 }, 374 },
315 375
316 searchCards: function (someParameters) { 376 searchCards: function (someParameters) {
317//console.log("SEARCH CARDS", someParameters); 377//console.log("SEARCH CARDS", someParameters);
318 this.setFilter(someParameters); 378 this.setFilter(someParameters);
319 this.showRecordList(); 379 this.showRecordList();
320 }, 380 },
321 381
322 //========================================================================= 382 //=========================================================================
323 383
324 runApplication: function () { 384 runApplication: function () {
325 MochiKit.Signal.connect(window, 'onpopstate',MochiKit.Base.method(this, 'historyGoBack')); 385 MochiKit.Signal.connect(window, 'onpopstate',MochiKit.Base.method(this, 'historyGoBack'));
386 /// TODO: remove this TEST HACK
326 this.moveInPage(this.currentPage(), 'cardListPage'); 387 this.moveInPage(this.currentPage(), 'cardListPage');
327 return this.showRecordList(); 388 return this.showRecordList();
389
390 // this.moveInPage(this.currentPage(), 'preferencePage');
328 }, 391 },
329 392
330 showRecord: function (aRecordReference) { 393 showRecord: function (aRecordReference) {
331//console.log("Show Record", aRecordReference); 394//console.log("Show Record", aRecordReference);
332 vardeferredResult; 395 vardeferredResult;
333 396
334 this.pages()['cardListPage'].setProps({selectedCard:aRecordReference}); 397 this.pages()['cardListPage'].setProps({selectedCard:aRecordReference});
335 deferredResult = new Clipperz.Async.Deferred('MainController.runApplication', {trace:false}); 398 deferredResult = new Clipperz.Async.Deferred('MainController.runApplication', {trace:false});
336 // deferredResult.addMethod(this.user(), 'getRecord', aRecordReference['_reference']);
337 deferredResult.addMethod(this.user(), 'getRecord', aRecordReference); 399 deferredResult.addMethod(this.user(), 'getRecord', aRecordReference);
338 deferredResult.addMethodcaller('content'); 400 deferredResult.addMethodcaller('content');
339 deferredResult.addCallback(MochiKit.Base.bind(function (aCard) { 401 deferredResult.addCallback(MochiKit.Base.bind(function (aCard) {
340//console.log("CARD DETAILS", aCard); 402//console.log("CARD DETAILS", aCard);
341 this.pages()['cardDetailPage'].setProps({card: aCard}); 403 this.pages()['cardDetailPage'].setProps({card: aCard});
342 this.pages()['cardListPage'].setProps({selectedCard: null}); 404 this.pages()['cardListPage'].setProps({selectedCard: null});
343 }, this)); 405 }, this));
344 deferredResult.addMethod(this, 'moveInPage', this.currentPage(), 'cardDetailPage', true); 406 deferredResult.addMethod(this, 'moveInPage', this.currentPage(), 'cardDetailPage', true);
345 deferredResult.callback(); 407 deferredResult.callback();
346 408
347 return deferredResult; 409 return deferredResult;
348 }, 410 },
349 411
350 runDirectLogin: function (someParameters) { 412 runDirectLogin: function (someParameters) {
351console.log("RUN DIRECT LOGIN", someParameters); 413//console.log("RUN DIRECT LOGIN", someParameters);
352 vardeferredResult; 414 vardeferredResult;
353 415
354 // this.pages()['cardListPage'].setProps({selectedCard:aRecordReference});
355 deferredResult = new Clipperz.Async.Deferred('MainController.runDirectLogin', {trace:false}); 416 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']); 417 deferredResult.addMethod(this.user(), 'getRecord', someParameters['record']);
358 deferredResult.addMethodcaller('directLoginWithReference', someParameters['directLogin']); 418 deferredResult.addMethodcaller('directLoginWithReference', someParameters['directLogin']);
359 deferredResult.addCallback(Clipperz.PM.UI.DirectLoginRunner.openDirectLogin); 419 deferredResult.addCallback(Clipperz.PM.UI.DirectLoginRunner.openDirectLogin);
360 deferredResult.callback(); 420 deferredResult.callback();
361 421
362 return deferredResult; 422 return deferredResult;
363 }, 423 },
364 424
365 shouldExitApp: function (anEvent) { 425 shouldExitApp: function (anEvent) {
366console.log("SHOULD EXIT APP"); 426//console.log("SHOULD EXIT APP");
367 anEvent.preventDefault(); 427 anEvent.preventDefault();
368 anEvent.stopPropagation(); 428 anEvent.stopPropagation();
369 }, 429 },
370 430
371 //========================================================================= 431 //=========================================================================
372 432
433 showPreferences: function (anEvent) {
434 vardeferredResult;
435
436 this.pages()['preferencePage'].setProps({});
437 deferredResult = new Clipperz.Async.Deferred('MainController.showPreferences', {trace:false});
438 deferredResult.addMethod(this, 'moveInPage', this.currentPage(), 'preferencePage', true);
439 deferredResult.callback();
440
441 return deferredResult;
442 },
443
444 //=========================================================================
445
373 genericErrorHandler: function (anEvent, anError) { 446 genericErrorHandler: function (anEvent, anError) {
374 var errorMessage; 447 var errorMessage;
375 varresult; 448 varresult;
376 449
377 result = anError; 450 result = anError;
378 errorMessage = "login failed"; 451 errorMessage = "login failed";
379 452
380 if (anError['isPermanent'] === true) { 453 if (anError['isPermanent'] === true) {
381 this.pages()['errorPage'].setProps({message:anError.message}); 454 this.pages()['errorPage'].setProps({message:anError.message});
382 this.moveInPage(this.currentPage(), 'errorPage'); 455 this.moveInPage(this.currentPage(), 'errorPage');
383 errorMessage = "failure"; 456 errorMessage = "failure";
384 } else { 457 } else {
385 if ('pin' in anEvent) { 458 if ('pin' in anEvent) {
386 errorCount = Clipperz.PM.PIN.recordFailedAttempt(); 459 errorCount = Clipperz.PM.PIN.recordFailedAttempt();
387 if (errorCount == -1) { 460 if (errorCount == -1) {
388 errorMessage = "PIN resetted"; 461 errorMessage = "PIN resetted";
389 } 462 }
390 } 463 }
391 } 464 }
392 this.overlay().failed(errorMessage, 1); 465 this.overlay().failed(errorMessage, 1);
393 466
394 return result; 467 return result;
395 }, 468 },
396 469
@@ -459,33 +532,52 @@ console.log("SHOULD EXIT APP");
459 532
460 shouldAddItemToHistory = typeof(addToHistory) == 'undefined' ? false : addToHistory; 533 shouldAddItemToHistory = typeof(addToHistory) == 'undefined' ? false : addToHistory;
461 534
462 this.slidePage(MochiKit.DOM.getElement(fromPage), MochiKit.DOM.getElement(toPage), 'LEFT'); 535 this.slidePage(MochiKit.DOM.getElement(fromPage), MochiKit.DOM.getElement(toPage), 'LEFT');
463 this.setCurrentPage(toPage); 536 this.setCurrentPage(toPage);
464 537
465 if (shouldAddItemToHistory) { 538 if (shouldAddItemToHistory) {
466//console.log("ADD ITEM TO HISTORY"); 539//console.log("ADD ITEM TO HISTORY");
467//console.log("ADD ITEM TO HISTORY - window", window); 540//console.log("ADD ITEM TO HISTORY - window", window);
468//console.log("ADD ITEM TO HISTORY - window.history", window.history); 541//console.log("ADD ITEM TO HISTORY - window.history", window.history);
469 window.history.pushState({'fromPage': fromPage, 'toPage': toPage}); 542 window.history.pushState({'fromPage': fromPage, 'toPage': toPage});
470 //# window.history.pushState(); 543 //# window.history.pushState();
471//console.log("ADDED ITEM TO HISTORY"); 544//console.log("ADDED ITEM TO HISTORY");
472 } else { 545 } else {
473//console.log("Skip HISTORY"); 546//console.log("Skip HISTORY");
474 } 547 }
475 }, 548 },
476 549
477 moveOutPage: function (fromPage, toPage) { 550 moveOutPage: function (fromPage, toPage) {
478 this.slidePage(MochiKit.DOM.getElement(fromPage), MochiKit.DOM.getElement(toPage), 'RIGHT'); 551 this.slidePage(MochiKit.DOM.getElement(fromPage), MochiKit.DOM.getElement(toPage), 'RIGHT');
479 this.setCurrentPage(toPage); 552 this.setCurrentPage(toPage);
480 }, 553 },
481 554
482 //========================================================================= 555 //=========================================================================
556
557 synchronizeLocalData: function (anEvent) {
558 vardeferredResult;
559
560 deferredResult = new Clipperz.Async.Deferred('MainController.synchronizeLocalData', {trace:true});
561 // deferredResult.addMethod(this.proxy(), 'message', 'downloadAccountData', {});
562 deferredResult.addMethod(this.user().connection(), 'message', 'downloadAccountData', {});
563 deferredResult.addCallback(function (aResult) {
564 Clipperz.PM.DataModel.devicePreferences.setAccountDataWityResponse(aResult);
565 // localStorage.setItem('clipperz_dump_data', aResult['data']);
566 // localStorage.setItem('clipperz_dump_version', aResult['version']);
567 // localStorage.setItem('clipperz_dump_date', new Date());
568 })
569 deferredResult.callback();
570
571 return deferredResult;
572 },
573
574 //=========================================================================
483/* 575/*
484 wrongAppVersion: function (anError) { 576 wrongAppVersion: function (anError) {
485 // this.pages()['errorPage'].setProps({message:anError.message}); 577 // this.pages()['errorPage'].setProps({message:anError.message});
486 // this.moveInPage('errorPage', this.currentPage()); 578 // this.moveInPage('errorPage', this.currentPage());
487 }, 579 },
488*/ 580*/
489 //========================================================================= 581 //=========================================================================
490 __syntaxFix__: "syntax fix" 582 __syntaxFix__: "syntax fix"
491}); 583});