Diffstat (limited to 'frontend/delta/js/Clipperz/PM/UI') (more/less context) (ignore whitespace changes)
9 files changed, 1641 insertions, 0 deletions
diff --git a/frontend/delta/js/Clipperz/PM/UI/Components/CardDetail.js b/frontend/delta/js/Clipperz/PM/UI/Components/CardDetail.js new file mode 100644 index 0000000..df514a2 --- a/dev/null +++ b/frontend/delta/js/Clipperz/PM/UI/Components/CardDetail.js | |||
@@ -0,0 +1,142 @@ | |||
1 | /* | ||
2 | |||
3 | Copyright 2008-2013 Clipperz Srl | ||
4 | |||
5 | This file is part of Clipperz, the online password manager. | ||
6 | For further information about its features and functionalities please | ||
7 | refer 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 | |||
24 | Clipperz.PM.UI.Components.CardDetail = React.createClass({ | ||
25 | |||
26 | getDefaultProps: function () { | ||
27 | return { | ||
28 | // searchDelay: 0.3 | ||
29 | } | ||
30 | }, | ||
31 | |||
32 | propTypes: { | ||
33 | card: React.PropTypes.object.isRequired | ||
34 | }, | ||
35 | |||
36 | getInitialState: function () { | ||
37 | return { | ||
38 | // showSearch: false, | ||
39 | // searchTimer: null, | ||
40 | starred: false | ||
41 | }; | ||
42 | }, | ||
43 | |||
44 | handleDirectLoginClick: function (aDirectLoginReference, anEvent) { | ||
45 | MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'runDirectLogin', {record:this.props.card['reference'], directLogin:aDirectLoginReference}); | ||
46 | }, | ||
47 | |||
48 | //========================================================================= | ||
49 | |||
50 | normalizeFieldValue: function (aValue) { | ||
51 | varresult = []; | ||
52 | varrows = aValue.split('\n'); | ||
53 | |||
54 | for (var i = 0; i < rows.length; i++) { | ||
55 | if (i > 0) { | ||
56 | result.push(React.DOM.br()); | ||
57 | } | ||
58 | result.push(rows[i].replace(/[\s]/g, '\u00A0')); | ||
59 | } | ||
60 | |||
61 | return result; | ||
62 | }, | ||
63 | |||
64 | renderField: function (aField) { | ||
65 | //console.log("FIELD", aField); | ||
66 | varactionLabel; | ||
67 | |||
68 | if (aField['actionType'] == 'URL') { | ||
69 | actionLabel = "go"; | ||
70 | } else if (aField['actionType'] == 'PASSWORD') { | ||
71 | actionLabel = "locked"; | ||
72 | } else if (aField['actionType'] == 'EMAIL') { | ||
73 | actionLabel = "email"; | ||
74 | } else { | ||
75 | actionLabel = ""; | ||
76 | } | ||
77 | |||
78 | returnReact.DOM.div({className:'listItem ' + aField['actionType']}, [ | ||
79 | React.DOM.div({className:'fieldWrapper'}, [ | ||
80 | React.DOM.div({className:'fieldInnerWrapper'}, [ | ||
81 | 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']))) | ||
83 | ]) | ||
84 | ]), | ||
85 | React.DOM.div({className:'actionWrapper'}, [ | ||
86 | React.DOM.div({className:aField['actionType']}, actionLabel) | ||
87 | ]) | ||
88 | ]); | ||
89 | }, | ||
90 | |||
91 | renderDirectLogin: function (aDirectLogin) { | ||
92 | //console.log("DIRECT LOGIN", aDirectLogin); | ||
93 | 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'])), | ||
95 | 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")) | ||
97 | ]); | ||
98 | }, | ||
99 | |||
100 | handleBackClick: function (anEvent) { | ||
101 | window.history.back(); | ||
102 | }, | ||
103 | |||
104 | handleStarClick: function (anEvent) { | ||
105 | this.setState({starred: !this.state['starred']}); | ||
106 | }, | ||
107 | |||
108 | //========================================================================= | ||
109 | |||
110 | render: function () { | ||
111 | var card = this.props.card; | ||
112 | var starredStatus = (this.state['starred'] ? "starred" : "unstarred"); | ||
113 | |||
114 | if ((typeof(card['fields']) != 'undefined') && (card['notes'] != '')) { | ||
115 | card['fields'].push({ 'actionType': 'NOTES', 'isHidden': false, 'label': "notes", 'reference': "notes", 'value': card['notes'] }) | ||
116 | } | ||
117 | |||
118 | returnReact.DOM.div({className:'cardDetail'}, [ | ||
119 | React.DOM.div({className:'header'}, [ | ||
120 | 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")), | ||
123 | React.DOM.div({className:'starWrapper'}, React.DOM.a({className:'star', onClick:this.handleStarClick}, starredStatus)) | ||
124 | ]), | ||
125 | React.DOM.div({className:'content'}, [ | ||
126 | 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 | ||
128 | ]), | ||
129 | React.DOM.div({className:'footer'}, [ | ||
130 | /* | ||
131 | // React.DOM.a({className:'cancel'}, "cancel"), | ||
132 | // React.DOM.a({className:'save'}, "save") | ||
133 | |||
134 | React.DOM.a({className:'cancel button'}, "failed"), | ||
135 | React.DOM.a({className:'save button'}, "done") | ||
136 | */ | ||
137 | ]) | ||
138 | ]); | ||
139 | } | ||
140 | |||
141 | //========================================================================= | ||
142 | }); | ||
diff --git a/frontend/delta/js/Clipperz/PM/UI/Components/CardList.js b/frontend/delta/js/Clipperz/PM/UI/Components/CardList.js new file mode 100644 index 0000000..66d20f1 --- a/dev/null +++ b/frontend/delta/js/Clipperz/PM/UI/Components/CardList.js | |||
@@ -0,0 +1,161 @@ | |||
1 | /* | ||
2 | |||
3 | Copyright 2008-2013 Clipperz Srl | ||
4 | |||
5 | This file is part of Clipperz, the online password manager. | ||
6 | For further information about its features and functionalities please | ||
7 | refer 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 | |||
24 | Clipperz.PM.UI.Components.CardList = React.createClass({ | ||
25 | |||
26 | getDefaultProps: function () { | ||
27 | return { | ||
28 | selectedCard: null, | ||
29 | searchDelay: 0.3 | ||
30 | } | ||
31 | }, | ||
32 | |||
33 | propTypes: { | ||
34 | searchDelay: React.PropTypes.number | ||
35 | }, | ||
36 | |||
37 | getInitialState: function () { | ||
38 | return { | ||
39 | showSearch: false, | ||
40 | searchTimer: null, | ||
41 | searchText: '', | ||
42 | // passphrase: '', | ||
43 | // pin: '' | ||
44 | }; | ||
45 | }, | ||
46 | |||
47 | //========================================================================= | ||
48 | |||
49 | toggleSearch: function (anEvent) { | ||
50 | varshowSearchBox; | ||
51 | |||
52 | showSearchBox = !this.state.showSearch; | ||
53 | |||
54 | this.setState({showSearch: showSearchBox}); | ||
55 | |||
56 | if (showSearchBox) { | ||
57 | MochiKit.Async.callLater(0.1, MochiKit.Base.method(this, 'focusOnSearchField')); | ||
58 | } | ||
59 | }, | ||
60 | |||
61 | updateSearchText: function (anEvent) { | ||
62 | varsearchText; | ||
63 | |||
64 | searchText = anEvent.target.value; | ||
65 | //console.log(">>> updateSearchText", searchText); | ||
66 | |||
67 | if ((this.state['searchTimer'] != null) && (searchText != this.state['searchText'])) { | ||
68 | this.state['searchTimer'].cancel(); | ||
69 | } | ||
70 | |||
71 | if (searchText != this.state['searchText']) { | ||
72 | this.state['searchText'] = searchText; | ||
73 | this.state['searchTimer'] = MochiKit.Async.callLater(this.props['searchDelay'], MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'searchCards', searchText); | ||
74 | } | ||
75 | }, | ||
76 | |||
77 | focusOnSearchField: function () { | ||
78 | console.log("focusOnSearchField", this.refs['searchField']); | ||
79 | this.refs['searchField'].getDOMNode.focus(); | ||
80 | }, | ||
81 | |||
82 | searchBox: function () { | ||
83 | var result; | ||
84 | |||
85 | if (this.state.showSearch) { | ||
86 | result =React.DOM.div({className:'searchBox'}, [ | ||
87 | React.DOM.div(null, [ | ||
88 | React.DOM.input({type:'search', placeholder:"search", ref:'searchField', onChange:this.updateSearchText}) | ||
89 | ]) | ||
90 | ]); | ||
91 | } else { | ||
92 | result = null; | ||
93 | } | ||
94 | |||
95 | return result; | ||
96 | }, | ||
97 | |||
98 | //========================================================================= | ||
99 | |||
100 | cardItem: function (aRecordReference) { | ||
101 | varreference = aRecordReference['_reference']; | ||
102 | varselectedCard = (reference == this.props.selectedCard); | ||
103 | |||
104 | returnReact.DOM.div({className:'listItem', onClick:MochiKit.Base.method(this, 'handleClickOnCardDetail', reference)}, [ | ||
105 | 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)), | ||
107 | 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"))) | ||
109 | ]); | ||
110 | }, | ||
111 | |||
112 | handleClickOnCardDetail: function (aRecordReference, anEvent) { | ||
113 | MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'showRecord', aRecordReference); | ||
114 | }, | ||
115 | |||
116 | cardListItems: function () { | ||
117 | varlist; | ||
118 | varresult; | ||
119 | |||
120 | list = this.props['cardList']; | ||
121 | |||
122 | if (typeof(list) != 'undefined') { | ||
123 | result = MochiKit.Base.map(MochiKit.Base.method(this, 'cardItem'), list); | ||
124 | } else { | ||
125 | result = null; | ||
126 | } | ||
127 | |||
128 | return result; | ||
129 | }, | ||
130 | |||
131 | //========================================================================= | ||
132 | |||
133 | handleChange: function (anEvent) { | ||
134 | // varrefs = this.refs; | ||
135 | // var refName = MochiKit.Base.filter(function (aRefName) { return refs[aRefName].getDOMNode() == anEvent.target}, MochiKit.Base.keys(this.refs))[0]; | ||
136 | // var newState = {}; | ||
137 | // | ||
138 | // newState[refName] = event.target.value; | ||
139 | // this.setState(newState); | ||
140 | }, | ||
141 | |||
142 | //========================================================================= | ||
143 | |||
144 | render: function() { | ||
145 | returnReact.DOM.div(null, [ | ||
146 | React.DOM.div({className:'header'}, [ | ||
147 | React.DOM.a({className:'account'}, 'clipperz'), | ||
148 | React.DOM.div({className:'features'}, [ | ||
149 | React.DOM.a({className:'addCard'}, 'add'), | ||
150 | React.DOM.a({className:'search ' + (this.state.showSearch ? 'selected' : ''), onClick:this.toggleSearch}, 'search'), | ||
151 | React.DOM.a({className:'settings'}, 'settings') | ||
152 | ]), | ||
153 | // this.searchBox() | ||
154 | ]), | ||
155 | this.searchBox(), | ||
156 | React.DOM.div({className:'content cardList'}, this.cardListItems()), | ||
157 | ]); | ||
158 | } | ||
159 | |||
160 | //========================================================================= | ||
161 | }); | ||
diff --git a/frontend/delta/js/Clipperz/PM/UI/Components/ErrorPage.js b/frontend/delta/js/Clipperz/PM/UI/Components/ErrorPage.js new file mode 100644 index 0000000..a1979ec --- a/dev/null +++ b/frontend/delta/js/Clipperz/PM/UI/Components/ErrorPage.js | |||
@@ -0,0 +1,46 @@ | |||
1 | /* | ||
2 | |||
3 | Copyright 2008-2013 Clipperz Srl | ||
4 | |||
5 | This file is part of Clipperz, the online password manager. | ||
6 | For further information about its features and functionalities please | ||
7 | refer 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 | |||
24 | Clipperz.PM.UI.Components.ErrorPage = React.createClass({ | ||
25 | |||
26 | getDefaultProps: function () { | ||
27 | return { | ||
28 | template: Clipperz.PM.UI.Components.PageTemplate | ||
29 | } | ||
30 | }, | ||
31 | |||
32 | 'propTypes': { | ||
33 | // type: React.PropTypes.oneOf(['PERMANENT', 'TEMPORARY']), | ||
34 | message:React.PropTypes.string.isRequired, | ||
35 | template:React.PropTypes.func | ||
36 | }, | ||
37 | |||
38 | |||
39 | _render: function () { | ||
40 | returnReact.DOM.div({className:'error-message'}, this.props.message); | ||
41 | }, | ||
42 | |||
43 | render: function () { | ||
44 | returnnew this.props.template({'innerComponent': this._render()}); | ||
45 | } | ||
46 | }); | ||
diff --git a/frontend/delta/js/Clipperz/PM/UI/Components/LoginForm.js b/frontend/delta/js/Clipperz/PM/UI/Components/LoginForm.js new file mode 100644 index 0000000..2b5b4a4 --- a/dev/null +++ b/frontend/delta/js/Clipperz/PM/UI/Components/LoginForm.js | |||
@@ -0,0 +1,150 @@ | |||
1 | /* | ||
2 | |||
3 | Copyright 2008-2013 Clipperz Srl | ||
4 | |||
5 | This file is part of Clipperz, the online password manager. | ||
6 | For further information about its features and functionalities please | ||
7 | refer 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 | |||
24 | Clipperz.PM.UI.Components.LoginForm = React.createClass({ | ||
25 | |||
26 | getDefaultProps: function () { | ||
27 | return { | ||
28 | mode: 'CREDENTIALS', | ||
29 | isNewUserRegistrationAvailable: false, | ||
30 | disabled: false, | ||
31 | template: Clipperz.PM.UI.Components.PageTemplate | ||
32 | } | ||
33 | }, | ||
34 | |||
35 | propTypes: { | ||
36 | mode: React.PropTypes.oneOf(['CREDENTIALS','PIN']), | ||
37 | isNewUserRegistrationAvailable:React.PropTypes.bool, | ||
38 | disabled: React.PropTypes.bool, | ||
39 | template: React.PropTypes.func | ||
40 | }, | ||
41 | |||
42 | getInitialState: function () { | ||
43 | return { | ||
44 | username: '', | ||
45 | passphrase: '', | ||
46 | pin: '' | ||
47 | }; | ||
48 | }, | ||
49 | |||
50 | //========================================================================= | ||
51 | |||
52 | handleChange: function (anEvent) { | ||
53 | varrefs = this.refs; | ||
54 | var refName = MochiKit.Base.filter(function (aRefName) { return refs[aRefName].getDOMNode() == anEvent.target}, MochiKit.Base.keys(this.refs))[0]; | ||
55 | var newState = {}; | ||
56 | |||
57 | newState[refName] = event.target.value; | ||
58 | this.setState(newState); | ||
59 | }, | ||
60 | |||
61 | //========================================================================= | ||
62 | |||
63 | handleCredentialSubmit: function (event) { | ||
64 | event.preventDefault(); | ||
65 | |||
66 | this.refs['passphrase'].getDOMNode().blur(); | ||
67 | |||
68 | var credentials = { | ||
69 | 'username': this.refs['username'].getDOMNode().value, | ||
70 | 'passphrase': this.refs['passphrase'].getDOMNode().value | ||
71 | } | ||
72 | MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'doLogin', credentials); | ||
73 | }, | ||
74 | |||
75 | handleRegistrationLinkClick: function (event) { | ||
76 | event.preventDefault(); | ||
77 | MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'showRegistrationForm'); | ||
78 | }, | ||
79 | |||
80 | //------------------------------------------------------------------------- | ||
81 | |||
82 | shouldEnableLoginButton: function () { | ||
83 | var result; | ||
84 | |||
85 | return( | ||
86 | ((this.state['username'] != '') && (this.state['passphrase'] != '')) | ||
87 | || | ||
88 | (this.state['pin'] != '') | ||
89 | ) && !this.props['disabled']; | ||
90 | }, | ||
91 | |||
92 | |||
93 | loginForm: function () { | ||
94 | registrationLink =React.DOM.div({'className':'registrationLink'}, [ | ||
95 | React.DOM.a({'onClick':this.handleRegistrationLinkClick}, "Need an account") | ||
96 | ]); | ||
97 | returnReact.DOM.div({'className':'loginForm credentials'},[ | ||
98 | React.DOM.form({onChange: this.handleChange, onSubmit:this.handleCredentialSubmit}, [ | ||
99 | React.DOM.div(null,[ | ||
100 | React.DOM.label({'for':'name'}, "username"), | ||
101 | React.DOM.input({'type':'text', 'name':'name', 'ref':'username', 'placeholder':"username", 'key':'username', 'autoCapitalize':'none'}), | ||
102 | React.DOM.label({'for':'passphrase'}, "passphrase"), | ||
103 | React.DOM.input({'type':'password', 'name':'passphrase', 'ref':'passphrase', 'placeholder':"passphrase", 'key':'passphrase'}) | ||
104 | ]), | ||
105 | React.DOM.button({'type':'submit', 'disabled':!this.shouldEnableLoginButton(), 'className':'button'}, "login") | ||
106 | ]), | ||
107 | this.props.isNewUserRegistrationAvailable ? registrationLink : null | ||
108 | ]); | ||
109 | }, | ||
110 | |||
111 | handlePINSubmit: function (event) { | ||
112 | event.preventDefault(); | ||
113 | |||
114 | this.refs['pin'].getDOMNode().blur(); | ||
115 | |||
116 | var credentials = { | ||
117 | pin: this.refs['pin'].getDOMNode().value | ||
118 | } | ||
119 | |||
120 | MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'doLogin', credentials); | ||
121 | }, | ||
122 | |||
123 | pinForm: function () { | ||
124 | returnReact.DOM.div({'className':'loginForm pin'},[ | ||
125 | React.DOM.form({onChange: this.handleChange, onSubmit:this.handlePINSubmit}, [ | ||
126 | React.DOM.div(null,[ | ||
127 | React.DOM.label({'for':'pin'}, "pin"), | ||
128 | React.DOM.input({'type':'text', 'name':'pin', 'ref':'pin', placeholder:"PIN", 'key':'pin', 'autocapitalize':'none'}) | ||
129 | ]), | ||
130 | React.DOM.button({'type':'submit', 'disabled':this.props.disabled, 'className':'button'}, "login") | ||
131 | ]) | ||
132 | ]); | ||
133 | }, | ||
134 | |||
135 | setInitialFocus: function () { | ||
136 | if (this.props.mode == 'PIN') { | ||
137 | this.refs['pin'].getDOMNode().select(); | ||
138 | } else { | ||
139 | if (this.refs['username'].getDOMNode().value == '') { | ||
140 | this.refs['username'].getDOMNode().focus(); | ||
141 | } else{ | ||
142 | this.refs['passphrase'].getDOMNode().select(); | ||
143 | } | ||
144 | } | ||
145 | }, | ||
146 | |||
147 | render: function() { | ||
148 | returnnew this.props.template({'innerComponent': this.props.mode == 'PIN' ? this.pinForm() : this.loginForm()}); | ||
149 | } | ||
150 | }); | ||
diff --git a/frontend/delta/js/Clipperz/PM/UI/Components/Overlay.js b/frontend/delta/js/Clipperz/PM/UI/Components/Overlay.js new file mode 100644 index 0000000..cc4a06c --- a/dev/null +++ b/frontend/delta/js/Clipperz/PM/UI/Components/Overlay.js | |||
@@ -0,0 +1,122 @@ | |||
1 | /* | ||
2 | |||
3 | Copyright 2008-2013 Clipperz Srl | ||
4 | |||
5 | This file is part of Clipperz, the online password manager. | ||
6 | For further information about its features and functionalities please | ||
7 | refer 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 | |||
24 | Clipperz.Base.module('Clipperz.PM.UI.Components'); | ||
25 | |||
26 | Clipperz.PM.UI.Components.Overlay = function(args) { | ||
27 | args = args || {}; | ||
28 | |||
29 | this._defaultDelay = 2; | ||
30 | this._element = MochiKit.DOM.getElement('overlay'); | ||
31 | |||
32 | return this; | ||
33 | } | ||
34 | |||
35 | //============================================================================= | ||
36 | |||
37 | Clipperz.Base.extend(Clipperz.PM.UI.Components.Overlay, Object, { | ||
38 | |||
39 | //------------------------------------------------------------------------- | ||
40 | |||
41 | 'toString': function () { | ||
42 | return "Clipperz.PM.UI.Components.Overlay component"; | ||
43 | }, | ||
44 | |||
45 | 'element': function () { | ||
46 | // return MochiKit.DOM.getElement('overlay'); | ||
47 | return this._element; | ||
48 | }, | ||
49 | |||
50 | 'getElement': function (aClass) { | ||
51 | return MochiKit.Selector.findChildElements(this.element(), ['.'+aClass])[0]; | ||
52 | }, | ||
53 | |||
54 | //------------------------------------------------------------------------- | ||
55 | |||
56 | 'show': function (aMessage) { | ||
57 | this.resetStatus(); | ||
58 | this.setMessage(aMessage); | ||
59 | MochiKit.DOM.removeElementClass(this.element(), 'ios-overlay-hide'); | ||
60 | MochiKit.DOM.addElementClass(this.element(), 'ios-overlay-show'); | ||
61 | }, | ||
62 | |||
63 | 'done': function (aMessage, aDelayBeforeHiding) { | ||
64 | this.completed(this.showDoneIcon, aMessage, aDelayBeforeHiding); | ||
65 | }, | ||
66 | |||
67 | 'failed': function (aMessage, aDelayBeforeHiding) { | ||
68 | this.completed(this.showFailIcon, aMessage, aDelayBeforeHiding); | ||
69 | }, | ||
70 | |||
71 | //------------------------------------------------------------------------- | ||
72 | |||
73 | 'resetStatus': function () { | ||
74 | MochiKit.Style.showElement(this.element()); | ||
75 | MochiKit.Style.showElement(this.getElement('spinner')); | ||
76 | MochiKit.Style.hideElement(this.getElement('done')); | ||
77 | MochiKit.Style.hideElement(this.getElement('failed')); | ||
78 | }, | ||
79 | |||
80 | 'setMessage': function (aMessage) { | ||
81 | if (typeof(aMessage) != 'undefined') { | ||
82 | this.getElement('title').innerHTML = aMessage; | ||
83 | } | ||
84 | }, | ||
85 | |||
86 | 'completed': function (aFunctionToShowResult, aMessage, aDelayBeforeHiding) { | ||
87 | var delay = aDelayBeforeHiding || this.defaultDelay(); | ||
88 | |||
89 | this.hideSpinner(); | ||
90 | MochiKit.Base.bind(aFunctionToShowResult, this)(); | ||
91 | this.setMessage(aMessage); | ||
92 | |||
93 | MochiKit.Async.callLater(delay, MochiKit.Base.bind(this.hide, this)) | ||
94 | }, | ||
95 | |||
96 | 'hide': function () { | ||
97 | MochiKit.DOM.removeElementClass(this.element(), 'ios-overlay-show'); | ||
98 | MochiKit.DOM.addElementClass(this.element(), 'ios-overlay-hide'); | ||
99 | MochiKit.Async.callLater(1, MochiKit.Style.hideElement, this.element()); | ||
100 | }, | ||
101 | |||
102 | 'hideSpinner': function () { | ||
103 | MochiKit.Style.hideElement(this.getElement('spinner')); | ||
104 | }, | ||
105 | |||
106 | 'showDoneIcon': function () { | ||
107 | MochiKit.Style.showElement(this.getElement('done')); | ||
108 | }, | ||
109 | |||
110 | 'showFailIcon': function () { | ||
111 | MochiKit.Style.showElement(this.getElement('failed')); | ||
112 | }, | ||
113 | |||
114 | //------------------------------------------------------------------------- | ||
115 | |||
116 | 'defaultDelay': function () { | ||
117 | return this._defaultDelay; | ||
118 | }, | ||
119 | |||
120 | //------------------------------------------------------------------------- | ||
121 | __syntaxFix__: "syntax fix" | ||
122 | }); | ||
diff --git a/frontend/delta/js/Clipperz/PM/UI/Components/PageTemplate.js b/frontend/delta/js/Clipperz/PM/UI/Components/PageTemplate.js new file mode 100644 index 0000000..9b7c748 --- a/dev/null +++ b/frontend/delta/js/Clipperz/PM/UI/Components/PageTemplate.js | |||
@@ -0,0 +1,33 @@ | |||
1 | /* | ||
2 | |||
3 | Copyright 2008-2013 Clipperz Srl | ||
4 | |||
5 | This file is part of Clipperz, the online password manager. | ||
6 | For further information about its features and functionalities please | ||
7 | refer 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 | |||
24 | Clipperz.PM.UI.Components.PageTemplate = React.createClass({ | ||
25 | render: function() { | ||
26 | returnReact.DOM.div(null, [ | ||
27 | React.DOM.div({'className': 'header'}, [ | ||
28 | React.DOM.h1(null, "clipperz") | ||
29 | ]), | ||
30 | React.DOM.div({'className': 'content'}, this.props.innerComponent) | ||
31 | ]) | ||
32 | } | ||
33 | }); | ||
diff --git a/frontend/delta/js/Clipperz/PM/UI/Components/RegistrationWizard.js b/frontend/delta/js/Clipperz/PM/UI/Components/RegistrationWizard.js new file mode 100644 index 0000000..051dcc5 --- a/dev/null +++ b/frontend/delta/js/Clipperz/PM/UI/Components/RegistrationWizard.js | |||
@@ -0,0 +1,240 @@ | |||
1 | /* | ||
2 | |||
3 | Copyright 2008-2013 Clipperz Srl | ||
4 | |||
5 | This file is part of Clipperz, the online password manager. | ||
6 | For further information about its features and functionalities please | ||
7 | refer 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 | |||
24 | Clipperz.PM.UI.Components.RegistrationWizard = React.createClass({ | ||
25 | |||
26 | getDefaultProps: function () { | ||
27 | return { | ||
28 | steps: [ | ||
29 | {name:'CREDENTIALS', label:'registration', _label:'credentials',description:"Choose your credentails"}, | ||
30 | {name:'PASSWORD_VERIFICATION', label:'registration', _label:'verify', description:"Verify your passphrase"}, | ||
31 | {name:'TERMS_OF_SERVICE', label:'registration', _label:'terms', description:"Check our terms of service"} | ||
32 | ], | ||
33 | disabled: false, | ||
34 | template: Clipperz.PM.UI.Components.PageTemplate | ||
35 | } | ||
36 | }, | ||
37 | |||
38 | getInitialState: function () { | ||
39 | return { | ||
40 | currentStep: this.props['steps'][0]['name'], | ||
41 | username: '', | ||
42 | passphrase: '', | ||
43 | verify_passphrase: '', | ||
44 | no_password_recovery: false, | ||
45 | agree_terms_of_service: false | ||
46 | }; | ||
47 | }, | ||
48 | |||
49 | 'propTypes': { | ||
50 | // steps: React.PropTypes.array, | ||
51 | disabled:React.PropTypes.bool, | ||
52 | template:React.PropTypes.func | ||
53 | }, | ||
54 | |||
55 | //========================================================================= | ||
56 | |||
57 | currentStepIndex: function () { | ||
58 | return this.indexOfStepNamed(this.state['currentStep']); | ||
59 | }, | ||
60 | |||
61 | indexOfStepNamed: function (aStepName) { | ||
62 | var stepConfiguration; | ||
63 | varresult; | ||
64 | |||
65 | stepConfiguration = this.props['steps'].filter(function (aConfig) { return aConfig['name'] == aStepName})[0]; | ||
66 | result = this.props['steps'].indexOf(stepConfiguration); | ||
67 | return result; | ||
68 | }, | ||
69 | |||
70 | //========================================================================= | ||
71 | |||
72 | statusClassForStep: function (aStep) { | ||
73 | varcurrentStepIndex = this.currentStepIndex(); | ||
74 | var stepIndex = this.indexOfStepNamed(aStep['name']); | ||
75 | varresult; | ||
76 | |||
77 | if (stepIndex < currentStepIndex) { | ||
78 | result = 'left'; | ||
79 | } else if (stepIndex == currentStepIndex) { | ||
80 | result = 'center'; | ||
81 | } else { | ||
82 | result = 'right'; | ||
83 | } | ||
84 | |||
85 | return result; | ||
86 | }, | ||
87 | |||
88 | //========================================================================= | ||
89 | |||
90 | handleBackClick: function (anEvent) { | ||
91 | var nextStep; | ||
92 | anEvent.preventDefault(); | ||
93 | |||
94 | if (this.currentStepIndex() > 0) { | ||
95 | nextStep = this.props['steps'][this.currentStepIndex() - 1]; | ||
96 | this.setState({currentStep: nextStep['name']}); | ||
97 | } else { | ||
98 | MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'goBack'); | ||
99 | } | ||
100 | }, | ||
101 | |||
102 | handleForwardClick: function (anEvent) { | ||
103 | var nextStep; | ||
104 | anEvent.preventDefault(); | ||
105 | |||
106 | if (this.canMoveForward()) { | ||
107 | |||
108 | if (this.currentStepIndex() < this.props['steps'].length - 1) { | ||
109 | nextStep = this.props['steps'][this.currentStepIndex() + 1]; | ||
110 | this.setState({currentStep: nextStep['name']}); | ||
111 | } else { | ||
112 | MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'registerNewUser', { | ||
113 | username: this.state['username'], | ||
114 | passphrase: this.state['passphrase'] | ||
115 | }) | ||
116 | } | ||
117 | } | ||
118 | }, | ||
119 | |||
120 | //------------------------------------------------------------------------- | ||
121 | |||
122 | canMoveForward: function () { | ||
123 | var result; | ||
124 | var currentStep; | ||
125 | |||
126 | result = false; | ||
127 | currentStep = this.state['currentStep']; | ||
128 | if (currentStep == 'CREDENTIALS') { | ||
129 | result = ((this.state['username'] != '') && (this.state['passphrase'] != '')); | ||
130 | } else if (currentStep == 'PASSWORD_VERIFICATION') { | ||
131 | result = (this.state['passphrase'] == this.state['verify_passphrase']); | ||
132 | } else if (currentStep == 'TERMS_OF_SERVICE') { | ||
133 | result = (this.state['no_password_recovery'] && this.state['agree_terms_of_service']); | ||
134 | } | ||
135 | |||
136 | return result && !this.props['disabled']; | ||
137 | }, | ||
138 | |||
139 | //========================================================================= | ||
140 | |||
141 | handleChange: function (anEvent) { | ||
142 | varrefs = this.refs; | ||
143 | var refName = MochiKit.Base.filter(function (aRefName) { return refs[aRefName].getDOMNode() == anEvent.target}, MochiKit.Base.keys(this.refs))[0]; | ||
144 | var newState = {}; | ||
145 | |||
146 | if ((event.target.type == 'checkbox') || (event.target.type == 'radio')) { | ||
147 | newState[refName] = event.target.checked; | ||
148 | } else { | ||
149 | newState[refName] = event.target.value; | ||
150 | } | ||
151 | this.setState(newState); | ||
152 | }, | ||
153 | |||
154 | //========================================================================= | ||
155 | |||
156 | renderIndexStep: function (aStep) { | ||
157 | returnReact.DOM.div({'className':'stepIndexItem ' + this.statusClassForStep(aStep)}, '.'); | ||
158 | }, | ||
159 | |||
160 | renderButtons: function () { | ||
161 | return [ | ||
162 | React.DOM.a({className:'back button step_' + (this.currentStepIndex() - 1), onClick:this.handleBackClick}, '<<'), | ||
163 | React.DOM.a({className:'forward button step_' + (this.currentStepIndex() + 1) + ' ' + (this.canMoveForward() ? 'enabled' : 'disabled'), onClick:this.handleForwardClick}, '>>') | ||
164 | ]; | ||
165 | }, | ||
166 | |||
167 | render_CREDENTIALS: function () { | ||
168 | returnReact.DOM.div(null,[ | ||
169 | React.DOM.label({'for':'name'}, "username"), | ||
170 | React.DOM.input({'type':'text', 'name':'name', 'ref':'username', 'placeholder':"username", 'key':'username', 'autoCapitalize':'none'/*, value:this.state.username*/}), | ||
171 | React.DOM.label({'for':'passphrase'}, "passphrase"), | ||
172 | React.DOM.input({'type':'password', 'name':'passphrase', 'ref':'passphrase', 'placeholder':"passphrase", 'key':'passphrase'/*, value:this.state.passphrase*/}) | ||
173 | ]); | ||
174 | }, | ||
175 | |||
176 | render_PASSWORD_VERIFICATION: function () { | ||
177 | returnReact.DOM.div(null,[ | ||
178 | React.DOM.label({'for':'verify_passphrase'}, "passphrase"), | ||
179 | React.DOM.input({'type':'password', 'name':'verify_passphrase', 'ref':'verify_passphrase', 'placeholder':"verify passphrase", 'key':'verify_passphrase'}) | ||
180 | ]); | ||
181 | }, | ||
182 | |||
183 | render_TERMS_OF_SERVICE: function () { | ||
184 | returnReact.DOM.div(null, [ | ||
185 | React.DOM.div({className:'checkboxBlock'}, [ | ||
186 | React.DOM.label({'for':'no_password_recovery'}, "I understand that Clipperz will not be able to recover a lost passphrase."), | ||
187 | React.DOM.input({'type':'checkbox', 'name':'no_password_recovery', 'ref':'no_password_recovery', 'key':'no_password_recovery'}), | ||
188 | React.DOM.p(null, "I understand that Clipperz will not be able to recover a lost passphrase.") | ||
189 | ]), | ||
190 | React.DOM.div({className:'checkboxBlock'}, [ | ||
191 | React.DOM.label({'for':'agree_terms_of_service'}, "I have read and agreed to the Terms of Service."), | ||
192 | React.DOM.input({'type':'checkbox', 'name':'agree_terms_of_service', 'ref':'agree_terms_of_service', 'key':'agree_terms_of_service'}), | ||
193 | React.DOM.p(null, [ | ||
194 | "I have read and agreed to the ", | ||
195 | React.DOM.a({href:'https://clipperz.com/terms_service/', target:'_blank'}, "Terms of Service.") | ||
196 | ]) | ||
197 | ]) | ||
198 | ]); | ||
199 | }, | ||
200 | |||
201 | renderStep: function (aStep) { | ||
202 | returnReact.DOM.div({'className':'step' + ' ' + aStep['name'] + ' ' + this.statusClassForStep(aStep) + ' step_' + this.currentStepIndex()}, [ | ||
203 | React.DOM.h1(null, aStep['label']), | ||
204 | React.DOM.p(null, aStep['description']), | ||
205 | this['render_' + aStep['name']].apply(), | ||
206 | React.DOM.div({'className':'stepIndex'}, MochiKit.Base.map(this.renderIndexStep, this.props['steps'])), | ||
207 | React.DOM.div({'className':'buttons'}, this.renderButtons()) | ||
208 | ]); | ||
209 | }, | ||
210 | |||
211 | _render: function () { | ||
212 | returnReact.DOM.div({'className':'registrationForm'},[ | ||
213 | React.DOM.form({onChange: this.handleChange}, [ | ||
214 | React.DOM.div({'className':'steps'}, MochiKit.Base.map(this.renderStep, this.props['steps'])) | ||
215 | ]) | ||
216 | ]); | ||
217 | }, | ||
218 | |||
219 | render: function () { | ||
220 | returnnew this.props.template({'innerComponent': this._render()}); | ||
221 | }, | ||
222 | |||
223 | //========================================================================= | ||
224 | |||
225 | setInitialFocus: function () { | ||
226 | this.refs['username'].getDOMNode().focus(); | ||
227 | }, | ||
228 | |||
229 | componentDidUpdate: function (prevProps, prevState, rootNode) { | ||
230 | if (prevState['currentStep'] != this.state['currentStep']) { | ||
231 | if (this.state['currentStep'] == 'CREDENTIALS') { | ||
232 | this.refs['passphrase'].getDOMNode().select(); | ||
233 | } else if (this.state['currentStep'] == 'PASSWORD_VERIFICATION') { | ||
234 | this.refs['verify_passphrase'].getDOMNode().select(); | ||
235 | } | ||
236 | } | ||
237 | } | ||
238 | |||
239 | //========================================================================= | ||
240 | }); | ||
diff --git a/frontend/delta/js/Clipperz/PM/UI/DirectLoginController.js b/frontend/delta/js/Clipperz/PM/UI/DirectLoginController.js new file mode 100644 index 0000000..d9dfe6d --- a/dev/null +++ b/frontend/delta/js/Clipperz/PM/UI/DirectLoginController.js | |||
@@ -0,0 +1,256 @@ | |||
1 | /* | ||
2 | |||
3 | Copyright 2008-2013 Clipperz Srl | ||
4 | |||
5 | This file is part of Clipperz, the online password manager. | ||
6 | For further information about its features and functionalities please | ||
7 | refer 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 | |||
24 | Clipperz.Base.module('Clipperz.PM.UI'); | ||
25 | |||
26 | Clipperz.PM.UI.DirectLoginRunner = function(args) { | ||
27 | this._directLogin = args['directLogin'] || Clipperz.Base.exception.raise('MandatoryParameter'); | ||
28 | this._target = Clipperz.PM.Crypto.randomKey(); | ||
29 | |||
30 | return this; | ||
31 | } | ||
32 | |||
33 | MochiKit.Base.update(Clipperz.PM.UI.DirectLoginRunner.prototype, { | ||
34 | |||
35 | 'toString': function() { | ||
36 | return "Clipperz.PM.UI.DirectLoginRunner"; | ||
37 | }, | ||
38 | |||
39 | //----------------------------------------------------------------------------- | ||
40 | |||
41 | 'directLogin': function () { | ||
42 | return this._directLogin; | ||
43 | }, | ||
44 | |||
45 | //----------------------------------------------------------------------------- | ||
46 | |||
47 | 'target': function () { | ||
48 | return this._target; | ||
49 | }, | ||
50 | |||
51 | //============================================================================= | ||
52 | |||
53 | 'setWindowTitle': function (aWindow, aTitle) { | ||
54 | aWindow.document.title = aTitle; | ||
55 | }, | ||
56 | |||
57 | 'setWindowBody': function (aWindow, anHTML) { | ||
58 | aWindow.document.body.innerHTML = anHTML; | ||
59 | }, | ||
60 | |||
61 | //============================================================================= | ||
62 | |||
63 | 'initialWindowSetup': function (aWindow) { | ||
64 | this.setWindowTitle(aWindow, "Loading Clipperz Direct Login"); | ||
65 | this.setWindowBody (aWindow, MochiKit.DOM.toHTML(MochiKit.DOM.H3("Loading Clipperz Direct Login ..."))); | ||
66 | }, | ||
67 | |||
68 | //----------------------------------------------------------------------------- | ||
69 | |||
70 | 'updateWindowWithDirectLoginLabel': function (aWindow, aLabel) { | ||
71 | var titleText; | ||
72 | var bodyText; | ||
73 | |||
74 | titleText = "Loading '__label__' Direct Login".replace(/__label__/, aLabel) | ||
75 | bodyText = "Loading '__label__' Direct Login... ".replace(/__label__/, aLabel) | ||
76 | |||
77 | this.setWindowTitle(aWindow, titleText); | ||
78 | this.setWindowBody (aWindow, MochiKit.DOM.toHTML(MochiKit.DOM.H3(bodyText))); | ||
79 | }, | ||
80 | |||
81 | //----------------------------------------------------------------------------- | ||
82 | |||
83 | 'updateWindowWithHTMLContent': function (aWindow, anHtml) { | ||
84 | this.setWindowBody(aWindow, anHtml); | ||
85 | }, | ||
86 | |||
87 | //============================================================================= | ||
88 | |||
89 | 'submitLoginForm': function(aWindow, aSubmitFunction) { | ||
90 | MochiKit.DOM.withWindow(aWindow, MochiKit.Base.bind(function () { | ||
91 | var formElement; | ||
92 | var submitButtons; | ||
93 | |||
94 | formElement = MochiKit.DOM.getElement('directLoginForm'); | ||
95 | |||
96 | submitButtons = MochiKit.Base.filter(function(anInputElement) { | ||
97 | return ((anInputElement.tagName.toLowerCase() == 'input') && (anInputElement.getAttribute('type').toLowerCase() == 'submit')); | ||
98 | }, formElement.elements); | ||
99 | |||
100 | if (submitButtons.length == 0) { | ||
101 | if (typeof(formElement.submit) == 'function') { | ||
102 | formElement.submit(); | ||
103 | } else { | ||
104 | aSubmitFunction.apply(formElement); | ||
105 | } | ||
106 | /* | ||
107 | varformSubmitFunction; | ||
108 | |||
109 | formSubmitFunction = MochiKit.Base.method(formElement, 'submit'); | ||
110 | if (Clipperz_IEisBroken == true) { | ||
111 | formElement.submit(); | ||
112 | } else { | ||
113 | formSubmitFunction(); | ||
114 | } | ||
115 | */ | ||
116 | } else { | ||
117 | submitButtons[0].click(); | ||
118 | } | ||
119 | }, this)); | ||
120 | }, | ||
121 | |||
122 | //------------------------------------------------------------------------- | ||
123 | |||
124 | 'runSubmitFormDirectLogin': function (aWindow, someAttributes) { | ||
125 | var html; | ||
126 | var formElement; | ||
127 | var submitFunction; | ||
128 | |||
129 | formElement = MochiKit.DOM.FORM({ | ||
130 | 'id':'directLoginForm', | ||
131 | 'method':someAttributes['formAttributes']['method'], | ||
132 | 'action':someAttributes['formAttributes']['action'] | ||
133 | }); | ||
134 | |||
135 | submitFunction = formElement.submit; | ||
136 | |||
137 | MochiKit.DOM.appendChildNodes(formElement, MochiKit.Base.map(function (anInputAttributes) { | ||
138 | return MochiKit.DOM.INPUT({'type':'hidden', 'name':anInputAttributes[0], 'value':anInputAttributes[1]}); | ||
139 | }, MochiKit.Base.items(someAttributes['inputValues']))); | ||
140 | |||
141 | html =''; | ||
142 | html += '<h3>Loading ' + someAttributes['label'] + ' ...</h3>'; | ||
143 | html +=MochiKit.DOM.appendChildNodes(MochiKit.DOM.DIV(), MochiKit.DOM.appendChildNodes(MochiKit.DOM.DIV({style:'display:none; visibility:hidden;'}), formElement)).innerHTML; | ||
144 | |||
145 | this.updateWindowWithHTMLContent(aWindow, html); | ||
146 | this.submitLoginForm(aWindow, submitFunction); | ||
147 | }, | ||
148 | |||
149 | //------------------------------------------------------------------------- | ||
150 | |||
151 | 'runHttpAuthDirectLogin': function(aWindow, someAttributes) { | ||
152 | var completeUrl; | ||
153 | var url; | ||
154 | |||
155 | url = someAttributes['inputValues']['url']; | ||
156 | |||
157 | if (/^https?\:\/\//.test(url) == false) { | ||
158 | url = 'http://' + url; | ||
159 | } | ||
160 | |||
161 | if (Clipperz_IEisBroken === true) { | ||
162 | completeUrl = url; | ||
163 | } else { | ||
164 | var username; | ||
165 | var password; | ||
166 | |||
167 | username = someAttributes['inputValues']['username']; | ||
168 | password = someAttributes['inputValues']['password']; | ||
169 | /(^https?\:\/\/)?(.*)/.test(url); | ||
170 | |||
171 | completeUrl = RegExp.$1 + username + ':' + password + '@' + RegExp.$2; | ||
172 | } | ||
173 | |||
174 | window.open(completeUrl, this.target()); | ||
175 | }, | ||
176 | |||
177 | //============================================================================= | ||
178 | |||
179 | 'runDirectLogin': function (aWindow) { | ||
180 | var deferredResult; | ||
181 | |||
182 | deferredResult = new Clipperz.Async.Deferred("DirectLoginRunner.openDirectLogin", {trace:false}); | ||
183 | deferredResult.addMethod(this, 'initialWindowSetup', aWindow); | ||
184 | deferredResult.addMethod(this.directLogin(), 'label'); | ||
185 | deferredResult.addMethod(this, 'updateWindowWithDirectLoginLabel', aWindow); | ||
186 | deferredResult.collectResults({ | ||
187 | 'type': MochiKit.Base.method(this.directLogin(), 'type'), | ||
188 | 'label': MochiKit.Base.method(this.directLogin(), 'label'), | ||
189 | 'formAttributes':MochiKit.Base.method(this.directLogin(), 'formAttributes'), | ||
190 | 'inputValues': MochiKit.Base.method(this.directLogin(), 'inputValues') | ||
191 | }); | ||
192 | deferredResult.addCallback(MochiKit.Base.bind(function (someAttributes) { | ||
193 | switch (someAttributes['type']) { | ||
194 | case 'http_auth': | ||
195 | this.runHttpAuthDirectLogin(aWindow, someAttributes); | ||
196 | break; | ||
197 | case 'simple_url': | ||
198 | this.runSimpleUrlDirectLogin(aWindow, someAttributes); | ||
199 | break; | ||
200 | default: | ||
201 | this.runSubmitFormDirectLogin(aWindow, someAttributes); | ||
202 | break; | ||
203 | } | ||
204 | }, this)); | ||
205 | deferredResult.callback(); | ||
206 | |||
207 | return deferredResult; | ||
208 | }, | ||
209 | |||
210 | //============================================================================= | ||
211 | |||
212 | 'run': function () { | ||
213 | var newWindow; | ||
214 | |||
215 | newWindow = window.open(Clipperz.PM.Strings.getValue('directLoginJumpPageUrl'), this.target()); | ||
216 | |||
217 | return this.runDirectLogin(newWindow); | ||
218 | }, | ||
219 | |||
220 | //============================================================================= | ||
221 | |||
222 | 'test': function () { | ||
223 | var iFrame; | ||
224 | var newWindow; | ||
225 | |||
226 | iFrame = MochiKit.DOM.createDOM('iframe'); | ||
227 | MochiKit.DOM.appendChildNodes(MochiKit.DOM.currentDocument().body, iFrame); | ||
228 | |||
229 | newWindow = iFrame.contentWindow; | ||
230 | |||
231 | return this.runDirectLogin(newWindow); | ||
232 | }, | ||
233 | |||
234 | //============================================================================= | ||
235 | __syntaxFix__: "syntax fix" | ||
236 | }); | ||
237 | |||
238 | //----------------------------------------------------------------------------- | ||
239 | |||
240 | Clipperz.PM.UI.DirectLoginRunner.openDirectLogin = function (aDirectLogin) { | ||
241 | varrunner; | ||
242 | |||
243 | runner = new Clipperz.PM.UI.DirectLoginRunner({directLogin:aDirectLogin}); | ||
244 | return runner.run(); | ||
245 | }; | ||
246 | |||
247 | //----------------------------------------------------------------------------- | ||
248 | |||
249 | Clipperz.PM.UI.DirectLoginRunner.testDirectLogin = function (aDirectLogin) { | ||
250 | varrunner; | ||
251 | |||
252 | runner = new Clipperz.PM.UI.DirectLoginRunner({directLogin:aDirectLogin}); | ||
253 | return runner.test(); | ||
254 | }; | ||
255 | |||
256 | //----------------------------------------------------------------------------- | ||
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 | |||
3 | Copyright 2008-2013 Clipperz Srl | ||
4 | |||
5 | This file is part of Clipperz, the online password manager. | ||
6 | For further information about its features and functionalities please | ||
7 | refer 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 | |||
24 | Clipperz.Base.module('Clipperz.PM.UI'); | ||
25 | |||
26 | Clipperz.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 | |||
52 | MochiKit.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) { | ||
351 | console.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) { | ||
366 | console.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 | }); | ||