mirror of
http://git.whoc.org.uk/git/password-manager.git
synced 2025-10-30 02:47:36 +01:00
First release of /delta version
This commit is contained in:
142
frontend/delta/js/Clipperz/PM/UI/Components/CardDetail.js
Normal file
142
frontend/delta/js/Clipperz/PM/UI/Components/CardDetail.js
Normal file
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
|
||||
Copyright 2008-2013 Clipperz Srl
|
||||
|
||||
This file is part of Clipperz, the online password manager.
|
||||
For further information about its features and functionalities please
|
||||
refer to http://www.clipperz.com.
|
||||
|
||||
* Clipperz is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
* Clipperz is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU Affero General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
License along with Clipperz. If not, see http://www.gnu.org/licenses/.
|
||||
|
||||
*/
|
||||
|
||||
Clipperz.PM.UI.Components.CardDetail = React.createClass({
|
||||
|
||||
getDefaultProps: function () {
|
||||
return {
|
||||
// searchDelay: 0.3
|
||||
}
|
||||
},
|
||||
|
||||
propTypes: {
|
||||
card: React.PropTypes.object.isRequired
|
||||
},
|
||||
|
||||
getInitialState: function () {
|
||||
return {
|
||||
// showSearch: false,
|
||||
// searchTimer: null,
|
||||
starred: false
|
||||
};
|
||||
},
|
||||
|
||||
handleDirectLoginClick: function (aDirectLoginReference, anEvent) {
|
||||
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'runDirectLogin', {record:this.props.card['reference'], directLogin:aDirectLoginReference});
|
||||
},
|
||||
|
||||
//=========================================================================
|
||||
|
||||
normalizeFieldValue: function (aValue) {
|
||||
var result = [];
|
||||
var rows = aValue.split('\n');
|
||||
|
||||
for (var i = 0; i < rows.length; i++) {
|
||||
if (i > 0) {
|
||||
result.push(React.DOM.br());
|
||||
}
|
||||
result.push(rows[i].replace(/[\s]/g, '\u00A0'));
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
renderField: function (aField) {
|
||||
//console.log("FIELD", aField);
|
||||
var actionLabel;
|
||||
|
||||
if (aField['actionType'] == 'URL') {
|
||||
actionLabel = "go";
|
||||
} else if (aField['actionType'] == 'PASSWORD') {
|
||||
actionLabel = "locked";
|
||||
} else if (aField['actionType'] == 'EMAIL') {
|
||||
actionLabel = "email";
|
||||
} else {
|
||||
actionLabel = "";
|
||||
}
|
||||
|
||||
return React.DOM.div({className:'listItem ' + aField['actionType']}, [
|
||||
React.DOM.div({className:'fieldWrapper'}, [
|
||||
React.DOM.div({className:'fieldInnerWrapper'}, [
|
||||
React.DOM.div({className:'labelWrapper'}, React.DOM.span({className:'label'}, aField['label'])),
|
||||
React.DOM.div({className:'valueWrapper'}, React.DOM.span({className:'value ' + aField['actionType']}, this.normalizeFieldValue(aField['value'])))
|
||||
])
|
||||
]),
|
||||
React.DOM.div({className:'actionWrapper'}, [
|
||||
React.DOM.div({className:aField['actionType']}, actionLabel)
|
||||
])
|
||||
]);
|
||||
},
|
||||
|
||||
renderDirectLogin: function (aDirectLogin) {
|
||||
//console.log("DIRECT LOGIN", aDirectLogin);
|
||||
return React.DOM.div({className:'listItem', onClick:MochiKit.Base.method(this, 'handleDirectLoginClick', aDirectLogin['reference'])}, [
|
||||
React.DOM.div({className:'labelWrapper'}, React.DOM.span({className:'label'}, aDirectLogin['label'])),
|
||||
React.DOM.div({className:'faviconWrapper'}, React.DOM.img({className:'favicon', src:aDirectLogin['favicon']})),
|
||||
React.DOM.div({className:'directLoginLinkWrapper'}, React.DOM.span({className:'directLoginLink'}, "go"))
|
||||
]);
|
||||
},
|
||||
|
||||
handleBackClick: function (anEvent) {
|
||||
window.history.back();
|
||||
},
|
||||
|
||||
handleStarClick: function (anEvent) {
|
||||
this.setState({starred: !this.state['starred']});
|
||||
},
|
||||
|
||||
//=========================================================================
|
||||
|
||||
render: function () {
|
||||
var card = this.props.card;
|
||||
var starredStatus = (this.state['starred'] ? "starred" : "unstarred");
|
||||
|
||||
if ((typeof(card['fields']) != 'undefined') && (card['notes'] != '')) {
|
||||
card['fields'].push({ 'actionType': 'NOTES', 'isHidden': false, 'label': "notes", 'reference': "notes", 'value': card['notes'] })
|
||||
}
|
||||
|
||||
return React.DOM.div({className:'cardDetail'}, [
|
||||
React.DOM.div({className:'header'}, [
|
||||
React.DOM.div({className:'titleWrapper'}, React.DOM.div({className:'title'}, card.title)),
|
||||
// React.DOM.div({className:'titleWrapper'}, React.DOM.div({className:'title'}, card.title + ' ' + card.title + ' ' + card.title + ' ' + card.title)),
|
||||
React.DOM.div({className:'backWrapper'}, React.DOM.a({className:'button back', onClick:this.handleBackClick}, "back")),
|
||||
React.DOM.div({className:'starWrapper'}, React.DOM.a({className:'star', onClick:this.handleStarClick}, starredStatus))
|
||||
]),
|
||||
React.DOM.div({className:'content'}, [
|
||||
card.fields ? React.DOM.div({className:'fields'}, MochiKit.Base.map(this.renderField, card.fields)) : null,
|
||||
card.directLogins ? React.DOM.div({className:'directLogins'}, MochiKit.Base.map(this.renderDirectLogin, card.directLogins)): null
|
||||
]),
|
||||
React.DOM.div({className:'footer'}, [
|
||||
/*
|
||||
// React.DOM.a({className:'cancel'}, "cancel"),
|
||||
// React.DOM.a({className:'save'}, "save")
|
||||
|
||||
React.DOM.a({className:'cancel button'}, "failed"),
|
||||
React.DOM.a({className:'save button'}, "done")
|
||||
*/
|
||||
])
|
||||
]);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
});
|
||||
161
frontend/delta/js/Clipperz/PM/UI/Components/CardList.js
Normal file
161
frontend/delta/js/Clipperz/PM/UI/Components/CardList.js
Normal file
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
|
||||
Copyright 2008-2013 Clipperz Srl
|
||||
|
||||
This file is part of Clipperz, the online password manager.
|
||||
For further information about its features and functionalities please
|
||||
refer to http://www.clipperz.com.
|
||||
|
||||
* Clipperz is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
* Clipperz is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU Affero General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
License along with Clipperz. If not, see http://www.gnu.org/licenses/.
|
||||
|
||||
*/
|
||||
|
||||
Clipperz.PM.UI.Components.CardList = React.createClass({
|
||||
|
||||
getDefaultProps: function () {
|
||||
return {
|
||||
selectedCard: null,
|
||||
searchDelay: 0.3
|
||||
}
|
||||
},
|
||||
|
||||
propTypes: {
|
||||
searchDelay: React.PropTypes.number
|
||||
},
|
||||
|
||||
getInitialState: function () {
|
||||
return {
|
||||
showSearch: false,
|
||||
searchTimer: null,
|
||||
searchText: '',
|
||||
// passphrase: '',
|
||||
// pin: ''
|
||||
};
|
||||
},
|
||||
|
||||
//=========================================================================
|
||||
|
||||
toggleSearch: function (anEvent) {
|
||||
var showSearchBox;
|
||||
|
||||
showSearchBox = !this.state.showSearch;
|
||||
|
||||
this.setState({showSearch: showSearchBox});
|
||||
|
||||
if (showSearchBox) {
|
||||
MochiKit.Async.callLater(0.1, MochiKit.Base.method(this, 'focusOnSearchField'));
|
||||
}
|
||||
},
|
||||
|
||||
updateSearchText: function (anEvent) {
|
||||
var searchText;
|
||||
|
||||
searchText = anEvent.target.value;
|
||||
//console.log(">>> updateSearchText", searchText);
|
||||
|
||||
if ((this.state['searchTimer'] != null) && (searchText != this.state['searchText'])) {
|
||||
this.state['searchTimer'].cancel();
|
||||
}
|
||||
|
||||
if (searchText != this.state['searchText']) {
|
||||
this.state['searchText'] = searchText;
|
||||
this.state['searchTimer'] = MochiKit.Async.callLater(this.props['searchDelay'], MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'searchCards', searchText);
|
||||
}
|
||||
},
|
||||
|
||||
focusOnSearchField: function () {
|
||||
console.log("focusOnSearchField", this.refs['searchField']);
|
||||
this.refs['searchField'].getDOMNode.focus();
|
||||
},
|
||||
|
||||
searchBox: function () {
|
||||
var result;
|
||||
|
||||
if (this.state.showSearch) {
|
||||
result = React.DOM.div({className:'searchBox'}, [
|
||||
React.DOM.div(null, [
|
||||
React.DOM.input({type:'search', placeholder:"search", ref:'searchField', onChange:this.updateSearchText})
|
||||
])
|
||||
]);
|
||||
} else {
|
||||
result = null;
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
//=========================================================================
|
||||
|
||||
cardItem: function (aRecordReference) {
|
||||
var reference = aRecordReference['_reference'];
|
||||
var selectedCard = (reference == this.props.selectedCard);
|
||||
|
||||
return React.DOM.div({className:'listItem', onClick:MochiKit.Base.method(this, 'handleClickOnCardDetail', reference)}, [
|
||||
React.DOM.div({className:'labelWrapper'}, React.DOM.span({className:'label'}, aRecordReference.label)),
|
||||
// React.DOM.div({className:'labelWrapper'}, React.DOM.span({className:'label'}, aRecordReference.label + ' ' + aRecordReference.label + ' ' + aRecordReference.label + ' ' + aRecordReference.label + ' ' + aRecordReference.label)),
|
||||
React.DOM.div({className:'faviconWrapper'}, aRecordReference.favicon ? React.DOM.img({className:'favicon', src:aRecordReference.favicon}) : React.DOM.div({className:'favicon'}, '\u00A0')),
|
||||
React.DOM.div({className:'detailLinkWrapper'}, React.DOM.span({className:'detailLink ' + (selectedCard ? 'icon-spin' : '')}, (selectedCard ? "loading" : "detail")))
|
||||
]);
|
||||
},
|
||||
|
||||
handleClickOnCardDetail: function (aRecordReference, anEvent) {
|
||||
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'showRecord', aRecordReference);
|
||||
},
|
||||
|
||||
cardListItems: function () {
|
||||
var list;
|
||||
var result;
|
||||
|
||||
list = this.props['cardList'];
|
||||
|
||||
if (typeof(list) != 'undefined') {
|
||||
result = MochiKit.Base.map(MochiKit.Base.method(this, 'cardItem'), list);
|
||||
} else {
|
||||
result = null;
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
//=========================================================================
|
||||
|
||||
handleChange: function (anEvent) {
|
||||
// var refs = this.refs;
|
||||
// var refName = MochiKit.Base.filter(function (aRefName) { return refs[aRefName].getDOMNode() == anEvent.target}, MochiKit.Base.keys(this.refs))[0];
|
||||
// var newState = {};
|
||||
//
|
||||
// newState[refName] = event.target.value;
|
||||
// this.setState(newState);
|
||||
},
|
||||
|
||||
//=========================================================================
|
||||
|
||||
render: function() {
|
||||
return React.DOM.div(null, [
|
||||
React.DOM.div({className:'header'}, [
|
||||
React.DOM.a({className:'account'}, 'clipperz'),
|
||||
React.DOM.div({className:'features'}, [
|
||||
React.DOM.a({className:'addCard'}, 'add'),
|
||||
React.DOM.a({className:'search ' + (this.state.showSearch ? 'selected' : ''), onClick:this.toggleSearch}, 'search'),
|
||||
React.DOM.a({className:'settings'}, 'settings')
|
||||
]),
|
||||
// this.searchBox()
|
||||
]),
|
||||
this.searchBox(),
|
||||
React.DOM.div({className:'content cardList'}, this.cardListItems()),
|
||||
]);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
});
|
||||
46
frontend/delta/js/Clipperz/PM/UI/Components/ErrorPage.js
Normal file
46
frontend/delta/js/Clipperz/PM/UI/Components/ErrorPage.js
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
|
||||
Copyright 2008-2013 Clipperz Srl
|
||||
|
||||
This file is part of Clipperz, the online password manager.
|
||||
For further information about its features and functionalities please
|
||||
refer to http://www.clipperz.com.
|
||||
|
||||
* Clipperz is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
* Clipperz is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU Affero General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
License along with Clipperz. If not, see http://www.gnu.org/licenses/.
|
||||
|
||||
*/
|
||||
|
||||
Clipperz.PM.UI.Components.ErrorPage = React.createClass({
|
||||
|
||||
getDefaultProps: function () {
|
||||
return {
|
||||
template: Clipperz.PM.UI.Components.PageTemplate
|
||||
}
|
||||
},
|
||||
|
||||
'propTypes': {
|
||||
// type: React.PropTypes.oneOf(['PERMANENT', 'TEMPORARY']),
|
||||
message: React.PropTypes.string.isRequired,
|
||||
template: React.PropTypes.func
|
||||
},
|
||||
|
||||
|
||||
_render: function () {
|
||||
return React.DOM.div({className:'error-message'}, this.props.message);
|
||||
},
|
||||
|
||||
render: function () {
|
||||
return new this.props.template({'innerComponent': this._render()});
|
||||
}
|
||||
});
|
||||
150
frontend/delta/js/Clipperz/PM/UI/Components/LoginForm.js
Normal file
150
frontend/delta/js/Clipperz/PM/UI/Components/LoginForm.js
Normal file
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
|
||||
Copyright 2008-2013 Clipperz Srl
|
||||
|
||||
This file is part of Clipperz, the online password manager.
|
||||
For further information about its features and functionalities please
|
||||
refer to http://www.clipperz.com.
|
||||
|
||||
* Clipperz is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
* Clipperz is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU Affero General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
License along with Clipperz. If not, see http://www.gnu.org/licenses/.
|
||||
|
||||
*/
|
||||
|
||||
Clipperz.PM.UI.Components.LoginForm = React.createClass({
|
||||
|
||||
getDefaultProps: function () {
|
||||
return {
|
||||
mode: 'CREDENTIALS',
|
||||
isNewUserRegistrationAvailable: false,
|
||||
disabled: false,
|
||||
template: Clipperz.PM.UI.Components.PageTemplate
|
||||
}
|
||||
},
|
||||
|
||||
propTypes: {
|
||||
mode: React.PropTypes.oneOf(['CREDENTIALS','PIN']),
|
||||
isNewUserRegistrationAvailable: React.PropTypes.bool,
|
||||
disabled: React.PropTypes.bool,
|
||||
template: React.PropTypes.func
|
||||
},
|
||||
|
||||
getInitialState: function () {
|
||||
return {
|
||||
username: '',
|
||||
passphrase: '',
|
||||
pin: ''
|
||||
};
|
||||
},
|
||||
|
||||
//=========================================================================
|
||||
|
||||
handleChange: function (anEvent) {
|
||||
var refs = this.refs;
|
||||
var refName = MochiKit.Base.filter(function (aRefName) { return refs[aRefName].getDOMNode() == anEvent.target}, MochiKit.Base.keys(this.refs))[0];
|
||||
var newState = {};
|
||||
|
||||
newState[refName] = event.target.value;
|
||||
this.setState(newState);
|
||||
},
|
||||
|
||||
//=========================================================================
|
||||
|
||||
handleCredentialSubmit: function (event) {
|
||||
event.preventDefault();
|
||||
|
||||
this.refs['passphrase'].getDOMNode().blur();
|
||||
|
||||
var credentials = {
|
||||
'username': this.refs['username'].getDOMNode().value,
|
||||
'passphrase': this.refs['passphrase'].getDOMNode().value
|
||||
}
|
||||
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'doLogin', credentials);
|
||||
},
|
||||
|
||||
handleRegistrationLinkClick: function (event) {
|
||||
event.preventDefault();
|
||||
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'showRegistrationForm');
|
||||
},
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
shouldEnableLoginButton: function () {
|
||||
var result;
|
||||
|
||||
return (
|
||||
((this.state['username'] != '') && (this.state['passphrase'] != ''))
|
||||
||
|
||||
(this.state['pin'] != '')
|
||||
) && !this.props['disabled'];
|
||||
},
|
||||
|
||||
|
||||
loginForm: function () {
|
||||
registrationLink = React.DOM.div({'className':'registrationLink'}, [
|
||||
React.DOM.a({'onClick':this.handleRegistrationLinkClick}, "Need an account")
|
||||
]);
|
||||
return React.DOM.div({'className':'loginForm credentials'},[
|
||||
React.DOM.form({onChange: this.handleChange, onSubmit:this.handleCredentialSubmit}, [
|
||||
React.DOM.div(null,[
|
||||
React.DOM.label({'for':'name'}, "username"),
|
||||
React.DOM.input({'type':'text', 'name':'name', 'ref':'username', 'placeholder':"username", 'key':'username', 'autoCapitalize':'none'}),
|
||||
React.DOM.label({'for':'passphrase'}, "passphrase"),
|
||||
React.DOM.input({'type':'password', 'name':'passphrase', 'ref':'passphrase', 'placeholder':"passphrase", 'key':'passphrase'})
|
||||
]),
|
||||
React.DOM.button({'type':'submit', 'disabled':!this.shouldEnableLoginButton(), 'className':'button'}, "login")
|
||||
]),
|
||||
this.props.isNewUserRegistrationAvailable ? registrationLink : null
|
||||
]);
|
||||
},
|
||||
|
||||
handlePINSubmit: function (event) {
|
||||
event.preventDefault();
|
||||
|
||||
this.refs['pin'].getDOMNode().blur();
|
||||
|
||||
var credentials = {
|
||||
pin: this.refs['pin'].getDOMNode().value
|
||||
}
|
||||
|
||||
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'doLogin', credentials);
|
||||
},
|
||||
|
||||
pinForm: function () {
|
||||
return React.DOM.div({'className':'loginForm pin'},[
|
||||
React.DOM.form({onChange: this.handleChange, onSubmit:this.handlePINSubmit}, [
|
||||
React.DOM.div(null,[
|
||||
React.DOM.label({'for':'pin'}, "pin"),
|
||||
React.DOM.input({'type':'text', 'name':'pin', 'ref':'pin', placeholder:"PIN", 'key':'pin', 'autocapitalize':'none'})
|
||||
]),
|
||||
React.DOM.button({'type':'submit', 'disabled':this.props.disabled, 'className':'button'}, "login")
|
||||
])
|
||||
]);
|
||||
},
|
||||
|
||||
setInitialFocus: function () {
|
||||
if (this.props.mode == 'PIN') {
|
||||
this.refs['pin'].getDOMNode().select();
|
||||
} else {
|
||||
if (this.refs['username'].getDOMNode().value == '') {
|
||||
this.refs['username'].getDOMNode().focus();
|
||||
} else{
|
||||
this.refs['passphrase'].getDOMNode().select();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return new this.props.template({'innerComponent': this.props.mode == 'PIN' ? this.pinForm() : this.loginForm()});
|
||||
}
|
||||
});
|
||||
122
frontend/delta/js/Clipperz/PM/UI/Components/Overlay.js
Normal file
122
frontend/delta/js/Clipperz/PM/UI/Components/Overlay.js
Normal file
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
|
||||
Copyright 2008-2013 Clipperz Srl
|
||||
|
||||
This file is part of Clipperz, the online password manager.
|
||||
For further information about its features and functionalities please
|
||||
refer to http://www.clipperz.com.
|
||||
|
||||
* Clipperz is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
* Clipperz is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU Affero General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
License along with Clipperz. If not, see http://www.gnu.org/licenses/.
|
||||
|
||||
*/
|
||||
|
||||
Clipperz.Base.module('Clipperz.PM.UI.Components');
|
||||
|
||||
Clipperz.PM.UI.Components.Overlay = function(args) {
|
||||
args = args || {};
|
||||
|
||||
this._defaultDelay = 2;
|
||||
this._element = MochiKit.DOM.getElement('overlay');
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
Clipperz.Base.extend(Clipperz.PM.UI.Components.Overlay, Object, {
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
'toString': function () {
|
||||
return "Clipperz.PM.UI.Components.Overlay component";
|
||||
},
|
||||
|
||||
'element': function () {
|
||||
// return MochiKit.DOM.getElement('overlay');
|
||||
return this._element;
|
||||
},
|
||||
|
||||
'getElement': function (aClass) {
|
||||
return MochiKit.Selector.findChildElements(this.element(), ['.'+aClass])[0];
|
||||
},
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
'show': function (aMessage) {
|
||||
this.resetStatus();
|
||||
this.setMessage(aMessage);
|
||||
MochiKit.DOM.removeElementClass(this.element(), 'ios-overlay-hide');
|
||||
MochiKit.DOM.addElementClass(this.element(), 'ios-overlay-show');
|
||||
},
|
||||
|
||||
'done': function (aMessage, aDelayBeforeHiding) {
|
||||
this.completed(this.showDoneIcon, aMessage, aDelayBeforeHiding);
|
||||
},
|
||||
|
||||
'failed': function (aMessage, aDelayBeforeHiding) {
|
||||
this.completed(this.showFailIcon, aMessage, aDelayBeforeHiding);
|
||||
},
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
'resetStatus': function () {
|
||||
MochiKit.Style.showElement(this.element());
|
||||
MochiKit.Style.showElement(this.getElement('spinner'));
|
||||
MochiKit.Style.hideElement(this.getElement('done'));
|
||||
MochiKit.Style.hideElement(this.getElement('failed'));
|
||||
},
|
||||
|
||||
'setMessage': function (aMessage) {
|
||||
if (typeof(aMessage) != 'undefined') {
|
||||
this.getElement('title').innerHTML = aMessage;
|
||||
}
|
||||
},
|
||||
|
||||
'completed': function (aFunctionToShowResult, aMessage, aDelayBeforeHiding) {
|
||||
var delay = aDelayBeforeHiding || this.defaultDelay();
|
||||
|
||||
this.hideSpinner();
|
||||
MochiKit.Base.bind(aFunctionToShowResult, this)();
|
||||
this.setMessage(aMessage);
|
||||
|
||||
MochiKit.Async.callLater(delay, MochiKit.Base.bind(this.hide, this))
|
||||
},
|
||||
|
||||
'hide': function () {
|
||||
MochiKit.DOM.removeElementClass(this.element(), 'ios-overlay-show');
|
||||
MochiKit.DOM.addElementClass(this.element(), 'ios-overlay-hide');
|
||||
MochiKit.Async.callLater(1, MochiKit.Style.hideElement, this.element());
|
||||
},
|
||||
|
||||
'hideSpinner': function () {
|
||||
MochiKit.Style.hideElement(this.getElement('spinner'));
|
||||
},
|
||||
|
||||
'showDoneIcon': function () {
|
||||
MochiKit.Style.showElement(this.getElement('done'));
|
||||
},
|
||||
|
||||
'showFailIcon': function () {
|
||||
MochiKit.Style.showElement(this.getElement('failed'));
|
||||
},
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
'defaultDelay': function () {
|
||||
return this._defaultDelay;
|
||||
},
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
__syntaxFix__: "syntax fix"
|
||||
});
|
||||
33
frontend/delta/js/Clipperz/PM/UI/Components/PageTemplate.js
Normal file
33
frontend/delta/js/Clipperz/PM/UI/Components/PageTemplate.js
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
|
||||
Copyright 2008-2013 Clipperz Srl
|
||||
|
||||
This file is part of Clipperz, the online password manager.
|
||||
For further information about its features and functionalities please
|
||||
refer to http://www.clipperz.com.
|
||||
|
||||
* Clipperz is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
* Clipperz is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU Affero General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
License along with Clipperz. If not, see http://www.gnu.org/licenses/.
|
||||
|
||||
*/
|
||||
|
||||
Clipperz.PM.UI.Components.PageTemplate = React.createClass({
|
||||
render: function() {
|
||||
return React.DOM.div(null, [
|
||||
React.DOM.div({'className': 'header'}, [
|
||||
React.DOM.h1(null, "clipperz")
|
||||
]),
|
||||
React.DOM.div({'className': 'content'}, this.props.innerComponent)
|
||||
])
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,240 @@
|
||||
/*
|
||||
|
||||
Copyright 2008-2013 Clipperz Srl
|
||||
|
||||
This file is part of Clipperz, the online password manager.
|
||||
For further information about its features and functionalities please
|
||||
refer to http://www.clipperz.com.
|
||||
|
||||
* Clipperz is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
* Clipperz is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU Affero General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
License along with Clipperz. If not, see http://www.gnu.org/licenses/.
|
||||
|
||||
*/
|
||||
|
||||
Clipperz.PM.UI.Components.RegistrationWizard = React.createClass({
|
||||
|
||||
getDefaultProps: function () {
|
||||
return {
|
||||
steps: [
|
||||
{name:'CREDENTIALS', label:'registration', _label:'credentials', description:"Choose your credentails"},
|
||||
{name:'PASSWORD_VERIFICATION', label:'registration', _label:'verify', description:"Verify your passphrase"},
|
||||
{name:'TERMS_OF_SERVICE', label:'registration', _label:'terms', description:"Check our terms of service"}
|
||||
],
|
||||
disabled: false,
|
||||
template: Clipperz.PM.UI.Components.PageTemplate
|
||||
}
|
||||
},
|
||||
|
||||
getInitialState: function () {
|
||||
return {
|
||||
currentStep: this.props['steps'][0]['name'],
|
||||
username: '',
|
||||
passphrase: '',
|
||||
verify_passphrase: '',
|
||||
no_password_recovery: false,
|
||||
agree_terms_of_service: false
|
||||
};
|
||||
},
|
||||
|
||||
'propTypes': {
|
||||
// steps: React.PropTypes.array,
|
||||
disabled: React.PropTypes.bool,
|
||||
template: React.PropTypes.func
|
||||
},
|
||||
|
||||
//=========================================================================
|
||||
|
||||
currentStepIndex: function () {
|
||||
return this.indexOfStepNamed(this.state['currentStep']);
|
||||
},
|
||||
|
||||
indexOfStepNamed: function (aStepName) {
|
||||
var stepConfiguration;
|
||||
var result;
|
||||
|
||||
stepConfiguration = this.props['steps'].filter(function (aConfig) { return aConfig['name'] == aStepName})[0];
|
||||
result = this.props['steps'].indexOf(stepConfiguration);
|
||||
return result;
|
||||
},
|
||||
|
||||
//=========================================================================
|
||||
|
||||
statusClassForStep: function (aStep) {
|
||||
var currentStepIndex = this.currentStepIndex();
|
||||
var stepIndex = this.indexOfStepNamed(aStep['name']);
|
||||
var result;
|
||||
|
||||
if (stepIndex < currentStepIndex) {
|
||||
result = 'left';
|
||||
} else if (stepIndex == currentStepIndex) {
|
||||
result = 'center';
|
||||
} else {
|
||||
result = 'right';
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
//=========================================================================
|
||||
|
||||
handleBackClick: function (anEvent) {
|
||||
var nextStep;
|
||||
anEvent.preventDefault();
|
||||
|
||||
if (this.currentStepIndex() > 0) {
|
||||
nextStep = this.props['steps'][this.currentStepIndex() - 1];
|
||||
this.setState({currentStep: nextStep['name']});
|
||||
} else {
|
||||
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'goBack');
|
||||
}
|
||||
},
|
||||
|
||||
handleForwardClick: function (anEvent) {
|
||||
var nextStep;
|
||||
anEvent.preventDefault();
|
||||
|
||||
if (this.canMoveForward()) {
|
||||
|
||||
if (this.currentStepIndex() < this.props['steps'].length - 1) {
|
||||
nextStep = this.props['steps'][this.currentStepIndex() + 1];
|
||||
this.setState({currentStep: nextStep['name']});
|
||||
} else {
|
||||
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'registerNewUser', {
|
||||
username: this.state['username'],
|
||||
passphrase: this.state['passphrase']
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
canMoveForward: function () {
|
||||
var result;
|
||||
var currentStep;
|
||||
|
||||
result = false;
|
||||
currentStep = this.state['currentStep'];
|
||||
if (currentStep == 'CREDENTIALS') {
|
||||
result = ((this.state['username'] != '') && (this.state['passphrase'] != ''));
|
||||
} else if (currentStep == 'PASSWORD_VERIFICATION') {
|
||||
result = (this.state['passphrase'] == this.state['verify_passphrase']);
|
||||
} else if (currentStep == 'TERMS_OF_SERVICE') {
|
||||
result = (this.state['no_password_recovery'] && this.state['agree_terms_of_service']);
|
||||
}
|
||||
|
||||
return result && !this.props['disabled'];
|
||||
},
|
||||
|
||||
//=========================================================================
|
||||
|
||||
handleChange: function (anEvent) {
|
||||
var refs = this.refs;
|
||||
var refName = MochiKit.Base.filter(function (aRefName) { return refs[aRefName].getDOMNode() == anEvent.target}, MochiKit.Base.keys(this.refs))[0];
|
||||
var newState = {};
|
||||
|
||||
if ((event.target.type == 'checkbox') || (event.target.type == 'radio')) {
|
||||
newState[refName] = event.target.checked;
|
||||
} else {
|
||||
newState[refName] = event.target.value;
|
||||
}
|
||||
this.setState(newState);
|
||||
},
|
||||
|
||||
//=========================================================================
|
||||
|
||||
renderIndexStep: function (aStep) {
|
||||
return React.DOM.div({'className':'stepIndexItem ' + this.statusClassForStep(aStep)}, '.');
|
||||
},
|
||||
|
||||
renderButtons: function () {
|
||||
return [
|
||||
React.DOM.a({className:'back button step_' + (this.currentStepIndex() - 1), onClick:this.handleBackClick}, '<<'),
|
||||
React.DOM.a({className:'forward button step_' + (this.currentStepIndex() + 1) + ' ' + (this.canMoveForward() ? 'enabled' : 'disabled'), onClick:this.handleForwardClick}, '>>')
|
||||
];
|
||||
},
|
||||
|
||||
render_CREDENTIALS: function () {
|
||||
return React.DOM.div(null,[
|
||||
React.DOM.label({'for':'name'}, "username"),
|
||||
React.DOM.input({'type':'text', 'name':'name', 'ref':'username', 'placeholder':"username", 'key':'username', 'autoCapitalize':'none'/*, value:this.state.username*/}),
|
||||
React.DOM.label({'for':'passphrase'}, "passphrase"),
|
||||
React.DOM.input({'type':'password', 'name':'passphrase', 'ref':'passphrase', 'placeholder':"passphrase", 'key':'passphrase'/*, value:this.state.passphrase*/})
|
||||
]);
|
||||
},
|
||||
|
||||
render_PASSWORD_VERIFICATION: function () {
|
||||
return React.DOM.div(null,[
|
||||
React.DOM.label({'for':'verify_passphrase'}, "passphrase"),
|
||||
React.DOM.input({'type':'password', 'name':'verify_passphrase', 'ref':'verify_passphrase', 'placeholder':"verify passphrase", 'key':'verify_passphrase'})
|
||||
]);
|
||||
},
|
||||
|
||||
render_TERMS_OF_SERVICE: function () {
|
||||
return React.DOM.div(null, [
|
||||
React.DOM.div({className:'checkboxBlock'}, [
|
||||
React.DOM.label({'for':'no_password_recovery'}, "I understand that Clipperz will not be able to recover a lost passphrase."),
|
||||
React.DOM.input({'type':'checkbox', 'name':'no_password_recovery', 'ref':'no_password_recovery', 'key':'no_password_recovery'}),
|
||||
React.DOM.p(null, "I understand that Clipperz will not be able to recover a lost passphrase.")
|
||||
]),
|
||||
React.DOM.div({className:'checkboxBlock'}, [
|
||||
React.DOM.label({'for':'agree_terms_of_service'}, "I have read and agreed to the Terms of Service."),
|
||||
React.DOM.input({'type':'checkbox', 'name':'agree_terms_of_service', 'ref':'agree_terms_of_service', 'key':'agree_terms_of_service'}),
|
||||
React.DOM.p(null, [
|
||||
"I have read and agreed to the ",
|
||||
React.DOM.a({href:'https://clipperz.com/terms_service/', target:'_blank'}, "Terms of Service.")
|
||||
])
|
||||
])
|
||||
]);
|
||||
},
|
||||
|
||||
renderStep: function (aStep) {
|
||||
return React.DOM.div({'className':'step' + ' ' + aStep['name'] + ' ' + this.statusClassForStep(aStep) + ' step_' + this.currentStepIndex()}, [
|
||||
React.DOM.h1(null, aStep['label']),
|
||||
React.DOM.p(null, aStep['description']),
|
||||
this['render_' + aStep['name']].apply(),
|
||||
React.DOM.div({'className':'stepIndex'}, MochiKit.Base.map(this.renderIndexStep, this.props['steps'])),
|
||||
React.DOM.div({'className':'buttons'}, this.renderButtons())
|
||||
]);
|
||||
},
|
||||
|
||||
_render: function () {
|
||||
return React.DOM.div({'className':'registrationForm'},[
|
||||
React.DOM.form({onChange: this.handleChange}, [
|
||||
React.DOM.div({'className':'steps'}, MochiKit.Base.map(this.renderStep, this.props['steps']))
|
||||
])
|
||||
]);
|
||||
},
|
||||
|
||||
render: function () {
|
||||
return new this.props.template({'innerComponent': this._render()});
|
||||
},
|
||||
|
||||
//=========================================================================
|
||||
|
||||
setInitialFocus: function () {
|
||||
this.refs['username'].getDOMNode().focus();
|
||||
},
|
||||
|
||||
componentDidUpdate: function (prevProps, prevState, rootNode) {
|
||||
if (prevState['currentStep'] != this.state['currentStep']) {
|
||||
if (this.state['currentStep'] == 'CREDENTIALS') {
|
||||
this.refs['passphrase'].getDOMNode().select();
|
||||
} else if (this.state['currentStep'] == 'PASSWORD_VERIFICATION') {
|
||||
this.refs['verify_passphrase'].getDOMNode().select();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
});
|
||||
256
frontend/delta/js/Clipperz/PM/UI/DirectLoginController.js
Normal file
256
frontend/delta/js/Clipperz/PM/UI/DirectLoginController.js
Normal file
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
|
||||
Copyright 2008-2013 Clipperz Srl
|
||||
|
||||
This file is part of Clipperz, the online password manager.
|
||||
For further information about its features and functionalities please
|
||||
refer to http://www.clipperz.com.
|
||||
|
||||
* Clipperz is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
* Clipperz is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU Affero General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
License along with Clipperz. If not, see http://www.gnu.org/licenses/.
|
||||
|
||||
*/
|
||||
|
||||
Clipperz.Base.module('Clipperz.PM.UI');
|
||||
|
||||
Clipperz.PM.UI.DirectLoginRunner = function(args) {
|
||||
this._directLogin = args['directLogin'] || Clipperz.Base.exception.raise('MandatoryParameter');
|
||||
this._target = Clipperz.PM.Crypto.randomKey();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
MochiKit.Base.update(Clipperz.PM.UI.DirectLoginRunner.prototype, {
|
||||
|
||||
'toString': function() {
|
||||
return "Clipperz.PM.UI.DirectLoginRunner";
|
||||
},
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
'directLogin': function () {
|
||||
return this._directLogin;
|
||||
},
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
'target': function () {
|
||||
return this._target;
|
||||
},
|
||||
|
||||
//=============================================================================
|
||||
|
||||
'setWindowTitle': function (aWindow, aTitle) {
|
||||
aWindow.document.title = aTitle;
|
||||
},
|
||||
|
||||
'setWindowBody': function (aWindow, anHTML) {
|
||||
aWindow.document.body.innerHTML = anHTML;
|
||||
},
|
||||
|
||||
//=============================================================================
|
||||
|
||||
'initialWindowSetup': function (aWindow) {
|
||||
this.setWindowTitle(aWindow, "Loading Clipperz Direct Login");
|
||||
this.setWindowBody (aWindow, MochiKit.DOM.toHTML(MochiKit.DOM.H3("Loading Clipperz Direct Login ...")));
|
||||
},
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
'updateWindowWithDirectLoginLabel': function (aWindow, aLabel) {
|
||||
var titleText;
|
||||
var bodyText;
|
||||
|
||||
titleText = "Loading '__label__' Direct Login".replace(/__label__/, aLabel)
|
||||
bodyText = "Loading '__label__' Direct Login... ".replace(/__label__/, aLabel)
|
||||
|
||||
this.setWindowTitle(aWindow, titleText);
|
||||
this.setWindowBody (aWindow, MochiKit.DOM.toHTML(MochiKit.DOM.H3(bodyText)));
|
||||
},
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
'updateWindowWithHTMLContent': function (aWindow, anHtml) {
|
||||
this.setWindowBody(aWindow, anHtml);
|
||||
},
|
||||
|
||||
//=============================================================================
|
||||
|
||||
'submitLoginForm': function(aWindow, aSubmitFunction) {
|
||||
MochiKit.DOM.withWindow(aWindow, MochiKit.Base.bind(function () {
|
||||
var formElement;
|
||||
var submitButtons;
|
||||
|
||||
formElement = MochiKit.DOM.getElement('directLoginForm');
|
||||
|
||||
submitButtons = MochiKit.Base.filter(function(anInputElement) {
|
||||
return ((anInputElement.tagName.toLowerCase() == 'input') && (anInputElement.getAttribute('type').toLowerCase() == 'submit'));
|
||||
}, formElement.elements);
|
||||
|
||||
if (submitButtons.length == 0) {
|
||||
if (typeof(formElement.submit) == 'function') {
|
||||
formElement.submit();
|
||||
} else {
|
||||
aSubmitFunction.apply(formElement);
|
||||
}
|
||||
/*
|
||||
var formSubmitFunction;
|
||||
|
||||
formSubmitFunction = MochiKit.Base.method(formElement, 'submit');
|
||||
if (Clipperz_IEisBroken == true) {
|
||||
formElement.submit();
|
||||
} else {
|
||||
formSubmitFunction();
|
||||
}
|
||||
*/
|
||||
} else {
|
||||
submitButtons[0].click();
|
||||
}
|
||||
}, this));
|
||||
},
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
'runSubmitFormDirectLogin': function (aWindow, someAttributes) {
|
||||
var html;
|
||||
var formElement;
|
||||
var submitFunction;
|
||||
|
||||
formElement = MochiKit.DOM.FORM({
|
||||
'id':'directLoginForm',
|
||||
'method':someAttributes['formAttributes']['method'],
|
||||
'action':someAttributes['formAttributes']['action']
|
||||
});
|
||||
|
||||
submitFunction = formElement.submit;
|
||||
|
||||
MochiKit.DOM.appendChildNodes(formElement, MochiKit.Base.map(function (anInputAttributes) {
|
||||
return MochiKit.DOM.INPUT({'type':'hidden', 'name':anInputAttributes[0], 'value':anInputAttributes[1]});
|
||||
}, MochiKit.Base.items(someAttributes['inputValues'])));
|
||||
|
||||
html = '';
|
||||
html += '<h3>Loading ' + someAttributes['label'] + ' ...</h3>';
|
||||
html += MochiKit.DOM.appendChildNodes(MochiKit.DOM.DIV(), MochiKit.DOM.appendChildNodes(MochiKit.DOM.DIV({style:'display:none; visibility:hidden;'}), formElement)).innerHTML;
|
||||
|
||||
this.updateWindowWithHTMLContent(aWindow, html);
|
||||
this.submitLoginForm(aWindow, submitFunction);
|
||||
},
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
'runHttpAuthDirectLogin': function(aWindow, someAttributes) {
|
||||
var completeUrl;
|
||||
var url;
|
||||
|
||||
url = someAttributes['inputValues']['url'];
|
||||
|
||||
if (/^https?\:\/\//.test(url) == false) {
|
||||
url = 'http://' + url;
|
||||
}
|
||||
|
||||
if (Clipperz_IEisBroken === true) {
|
||||
completeUrl = url;
|
||||
} else {
|
||||
var username;
|
||||
var password;
|
||||
|
||||
username = someAttributes['inputValues']['username'];
|
||||
password = someAttributes['inputValues']['password'];
|
||||
/(^https?\:\/\/)?(.*)/.test(url);
|
||||
|
||||
completeUrl = RegExp.$1 + username + ':' + password + '@' + RegExp.$2;
|
||||
}
|
||||
|
||||
window.open(completeUrl, this.target());
|
||||
},
|
||||
|
||||
//=============================================================================
|
||||
|
||||
'runDirectLogin': function (aWindow) {
|
||||
var deferredResult;
|
||||
|
||||
deferredResult = new Clipperz.Async.Deferred("DirectLoginRunner.openDirectLogin", {trace:false});
|
||||
deferredResult.addMethod(this, 'initialWindowSetup', aWindow);
|
||||
deferredResult.addMethod(this.directLogin(), 'label');
|
||||
deferredResult.addMethod(this, 'updateWindowWithDirectLoginLabel', aWindow);
|
||||
deferredResult.collectResults({
|
||||
'type': MochiKit.Base.method(this.directLogin(), 'type'),
|
||||
'label': MochiKit.Base.method(this.directLogin(), 'label'),
|
||||
'formAttributes': MochiKit.Base.method(this.directLogin(), 'formAttributes'),
|
||||
'inputValues': MochiKit.Base.method(this.directLogin(), 'inputValues')
|
||||
});
|
||||
deferredResult.addCallback(MochiKit.Base.bind(function (someAttributes) {
|
||||
switch (someAttributes['type']) {
|
||||
case 'http_auth':
|
||||
this.runHttpAuthDirectLogin(aWindow, someAttributes);
|
||||
break;
|
||||
case 'simple_url':
|
||||
this.runSimpleUrlDirectLogin(aWindow, someAttributes);
|
||||
break;
|
||||
default:
|
||||
this.runSubmitFormDirectLogin(aWindow, someAttributes);
|
||||
break;
|
||||
}
|
||||
}, this));
|
||||
deferredResult.callback();
|
||||
|
||||
return deferredResult;
|
||||
},
|
||||
|
||||
//=============================================================================
|
||||
|
||||
'run': function () {
|
||||
var newWindow;
|
||||
|
||||
newWindow = window.open(Clipperz.PM.Strings.getValue('directLoginJumpPageUrl'), this.target());
|
||||
|
||||
return this.runDirectLogin(newWindow);
|
||||
},
|
||||
|
||||
//=============================================================================
|
||||
|
||||
'test': function () {
|
||||
var iFrame;
|
||||
var newWindow;
|
||||
|
||||
iFrame = MochiKit.DOM.createDOM('iframe');
|
||||
MochiKit.DOM.appendChildNodes(MochiKit.DOM.currentDocument().body, iFrame);
|
||||
|
||||
newWindow = iFrame.contentWindow;
|
||||
|
||||
return this.runDirectLogin(newWindow);
|
||||
},
|
||||
|
||||
//=============================================================================
|
||||
__syntaxFix__: "syntax fix"
|
||||
});
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
Clipperz.PM.UI.DirectLoginRunner.openDirectLogin = function (aDirectLogin) {
|
||||
var runner;
|
||||
|
||||
runner = new Clipperz.PM.UI.DirectLoginRunner({directLogin:aDirectLogin});
|
||||
return runner.run();
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
Clipperz.PM.UI.DirectLoginRunner.testDirectLogin = function (aDirectLogin) {
|
||||
var runner;
|
||||
|
||||
runner = new Clipperz.PM.UI.DirectLoginRunner({directLogin:aDirectLogin});
|
||||
return runner.test();
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
491
frontend/delta/js/Clipperz/PM/UI/MainController.js
Normal file
491
frontend/delta/js/Clipperz/PM/UI/MainController.js
Normal file
@@ -0,0 +1,491 @@
|
||||
/*
|
||||
|
||||
Copyright 2008-2013 Clipperz Srl
|
||||
|
||||
This file is part of Clipperz, the online password manager.
|
||||
For further information about its features and functionalities please
|
||||
refer to http://www.clipperz.com.
|
||||
|
||||
* Clipperz is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
* Clipperz is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU Affero General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
License along with Clipperz. If not, see http://www.gnu.org/licenses/.
|
||||
|
||||
*/
|
||||
|
||||
Clipperz.Base.module('Clipperz.PM.UI');
|
||||
|
||||
Clipperz.PM.UI.MainController = function() {
|
||||
var pages;
|
||||
|
||||
this._proxy = null;
|
||||
this._user = null;
|
||||
this._filter = '';
|
||||
|
||||
// this._currentPage = 'loadingPage';
|
||||
|
||||
this._pageStack = ['loadingPage'];
|
||||
this._overlay = new Clipperz.PM.UI.Components.Overlay();
|
||||
pages = {
|
||||
'loginPage': new Clipperz.PM.UI.Components.LoginForm(),
|
||||
'registrationPage': new Clipperz.PM.UI.Components.RegistrationWizard(),
|
||||
'cardListPage': new Clipperz.PM.UI.Components.CardList(),
|
||||
'cardDetailPage': new Clipperz.PM.UI.Components.CardDetail({card: {}}),
|
||||
'errorPage': new Clipperz.PM.UI.Components.ErrorPage({message:''})
|
||||
};
|
||||
|
||||
MochiKit.Base.map(function (anId) {React.renderComponent(pages[anId], MochiKit.DOM.getElement(anId))}, MochiKit.Base.keys(pages));
|
||||
this._pages = pages;
|
||||
this.registerForNotificationCenterEvents();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
MochiKit.Base.update(Clipperz.PM.UI.MainController.prototype, {
|
||||
|
||||
toString: function () {
|
||||
return "Clipperz.PM.UI.MainController";
|
||||
},
|
||||
|
||||
//=========================================================================
|
||||
|
||||
overlay: function () {
|
||||
return this._overlay;
|
||||
},
|
||||
|
||||
loginForm: function () {
|
||||
return this._loginForm;
|
||||
},
|
||||
|
||||
registrationWizard: function () {
|
||||
return this._registrationWizard;
|
||||
},
|
||||
|
||||
//=========================================================================
|
||||
|
||||
isOnline: function() {
|
||||
return navigator.onLine;
|
||||
},
|
||||
|
||||
hasLocalData: function() {
|
||||
return false;
|
||||
},
|
||||
|
||||
loginMode: function () {
|
||||
// PIN is set using this command:
|
||||
// Clipperz.PM.PIN.setCredentialsWithPIN('1234', {'username':'joe', 'passphrase':'clipperz'});
|
||||
|
||||
return Clipperz.PM.PIN.isSet() ? 'PIN' : 'CREDENTIALS';
|
||||
},
|
||||
|
||||
//=========================================================================
|
||||
|
||||
pages: function () {
|
||||
return this._pages;
|
||||
},
|
||||
|
||||
pageStack: function () {
|
||||
return this._pageStack;
|
||||
},
|
||||
|
||||
//=========================================================================
|
||||
|
||||
selectInitialProxy: function () {
|
||||
if (this.isOnline()) {
|
||||
this._proxy = Clipperz.PM.Proxy.defaultProxy;
|
||||
} else {
|
||||
if (this.hasLocalData()) {
|
||||
this._proxy = new Clipperz.PM.Proxy.Offline({dataStore: new Clipperz.PM.Proxy.Offline.LocalStorageDataStore(), shouldPayTolls:false});
|
||||
} else {
|
||||
this.showOfflineError();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
proxy: function () {
|
||||
return this._proxy;
|
||||
},
|
||||
|
||||
//=========================================================================
|
||||
|
||||
registerForNotificationCenterEvents: function () {
|
||||
var events = ['doLogin', 'registerNewUser', 'showRegistrationForm', 'goBack', 'showRecord', 'searchCards', 'runDirectLogin'];
|
||||
var self = this;
|
||||
|
||||
MochiKit.Base.map(function (anEvent) {
|
||||
MochiKit.Signal.connect(Clipperz.Signal.NotificationCenter, anEvent, MochiKit.Base.method(self, anEvent));
|
||||
}, events);
|
||||
|
||||
// MochiKit.Signal.connect(window, 'onpopstate', MochiKit.Base.method(this, 'historyGoBack'));
|
||||
MochiKit.Signal.connect(window, 'onbeforeunload', MochiKit.Base.method(this, 'shouldExitApp'));
|
||||
},
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
run: function (parameters) {
|
||||
var shouldShowRegistrationForm;
|
||||
|
||||
this.selectInitialProxy();
|
||||
shouldShowRegistrationForm = parameters['shouldShowRegistrationForm'] && this.proxy().canRegisterNewUsers();
|
||||
this.pages()['loginPage'].setProps({'mode':this.loginMode(), 'isNewUserRegistrationAvailable': this.proxy().canRegisterNewUsers()});
|
||||
|
||||
if (shouldShowRegistrationForm) {
|
||||
this.showRegistrationForm();
|
||||
} else {
|
||||
this.showLoginForm();
|
||||
}
|
||||
this.overlay().done("", 0.5);
|
||||
},
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
showLoginForm: function () {
|
||||
var loginFormPage;
|
||||
|
||||
loginFormPage = this.pages()['loginPage'];
|
||||
loginFormPage.setProps({'mode':this.loginMode(), 'isNewUserRegistrationAvailable': this.proxy().canRegisterNewUsers()});
|
||||
this.moveInPage(this.currentPage(), 'loginPage');
|
||||
MochiKit.Async.callLater(0.5, MochiKit.Base.method(loginFormPage, 'setInitialFocus'));
|
||||
},
|
||||
|
||||
showRegistrationForm: function () {
|
||||
var currentPage;
|
||||
var registrationPage;
|
||||
|
||||
currentPage = this.currentPage();
|
||||
registrationPage = this.pages()['registrationPage'];
|
||||
this.setCurrentPage('loginPage');
|
||||
registrationPage.setProps({});
|
||||
this.moveInPage(currentPage, 'registrationPage');
|
||||
MochiKit.Async.callLater(0.5, MochiKit.Base.method(registrationPage, 'setInitialFocus'));
|
||||
},
|
||||
|
||||
//=========================================================================
|
||||
|
||||
doLogin: function (event) {
|
||||
var credentials;
|
||||
var getPassphraseDelegate;
|
||||
var user;
|
||||
|
||||
user = null;
|
||||
|
||||
this.overlay().show("logging in");
|
||||
this.pages()['loginPage'].setProps({disabled:true});
|
||||
|
||||
if ('pin' in event) {
|
||||
credentials = Clipperz.PM.PIN.credentialsWithPIN(event['pin']);
|
||||
} else {
|
||||
credentials = event;
|
||||
}
|
||||
getPassphraseDelegate = MochiKit.Base.partial(MochiKit.Async.succeed, credentials.passphrase);
|
||||
user = new Clipperz.PM.DataModel.User({'username':credentials.username, 'getPassphraseFunction':getPassphraseDelegate});
|
||||
|
||||
deferredResult = new Clipperz.Async.Deferred('MainController.doLogin', {trace:false});
|
||||
deferredResult.addCallback(MochiKit.Async.wait, 0.1);
|
||||
deferredResult.addMethod(Clipperz.Crypto.PRNG.defaultRandomGenerator(), 'deferredEntropyCollection');
|
||||
deferredResult.addMethod(user, 'login');
|
||||
deferredResult.addMethod(Clipperz.PM.PIN, 'resetFailedAttemptCount');
|
||||
deferredResult.addMethod(this, 'setUser', user);
|
||||
|
||||
// deferredResult.addMethod(this, 'setupApplication');
|
||||
deferredResult.addMethod(this, 'runApplication');
|
||||
deferredResult.addMethod(this.overlay(), 'done', "", 1);
|
||||
deferredResult.addErrback(MochiKit.Base.method(this, 'genericErrorHandler', event));
|
||||
deferredResult.addErrback(MochiKit.Base.bind(function (anEvent, anError) {
|
||||
if (anError['isPermanent'] != true) {
|
||||
this.pages()['loginPage'].setProps({disabled:false, 'mode':this.loginMode()});
|
||||
this.pages()['loginPage'].setInitialFocus();
|
||||
}
|
||||
return anError;
|
||||
}, this, event))
|
||||
deferredResult.callback();
|
||||
|
||||
return deferredResult;
|
||||
},
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
registerNewUser: function (credentials) {
|
||||
var deferredResult;
|
||||
|
||||
this.overlay().show("creating user");
|
||||
|
||||
this.pages()['registrationPage'].setProps({disabled:true});
|
||||
deferredResult = new Clipperz.Async.Deferred('MainController.registerNewUser', {trace:false});
|
||||
deferredResult.addCallback(Clipperz.PM.DataModel.User.registerNewAccount,
|
||||
credentials['username'],
|
||||
MochiKit.Base.partial(MochiKit.Async.succeed, credentials['passphrase'])
|
||||
);
|
||||
deferredResult.addMethod(this, 'doLogin', credentials);
|
||||
deferredResult.addErrback(MochiKit.Base.method(this, 'genericErrorHandler', event));
|
||||
deferredResult.addErrback(MochiKit.Base.bind(function (anError) {
|
||||
if (anError['isPermanent'] != true) {
|
||||
this.pages()['registrationPage'].setProps({disabled:false});
|
||||
this.pages()['registrationPage'].setInitialFocus();
|
||||
}
|
||||
return anError;
|
||||
}, this));
|
||||
|
||||
deferredResult.callback();
|
||||
|
||||
return deferredResult;
|
||||
|
||||
},
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
user: function () {
|
||||
return this._user;
|
||||
},
|
||||
|
||||
setUser: function (aUser) {
|
||||
this._user = aUser;
|
||||
return this._user;
|
||||
},
|
||||
|
||||
//=========================================================================
|
||||
|
||||
allCardInfo: function () {
|
||||
var deferredResult;
|
||||
var cardInfo;
|
||||
|
||||
cardInfo = {
|
||||
'_rowObject': MochiKit.Async.succeed,
|
||||
'_reference': MochiKit.Base.methodcaller('reference'),
|
||||
'_searchableContent': MochiKit.Base.methodcaller('searchableContent'),
|
||||
'label': MochiKit.Base.methodcaller('label'),
|
||||
'favicon': MochiKit.Base.methodcaller('favicon')
|
||||
};
|
||||
|
||||
deferredResult = new Clipperz.Async.Deferred('MainController.allCardInfo', {trace:false});
|
||||
deferredResult.addMethod(this.user(), 'getRecords');
|
||||
deferredResult.addCallback(MochiKit.Base.map, Clipperz.Async.collectResults("CardList.value - collectResults", cardInfo, {trace:false}));
|
||||
deferredResult.addCallback(Clipperz.Async.collectAll);
|
||||
deferredResult.callback();
|
||||
|
||||
return deferredResult;
|
||||
},
|
||||
|
||||
filterCards: function (someCardInfo) {
|
||||
var filter;
|
||||
var filterRegExp;
|
||||
var result;
|
||||
|
||||
filter = this.filter().replace(/[^A-Za-z0-9]/g, "\\$&");
|
||||
filterRegExp = new RegExp(filter, "i");
|
||||
result = MochiKit.Base.filter(function (aCardInfo) { return filterRegExp.test(aCardInfo['_searchableContent'])}, someCardInfo);
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
sortCards: function (someCardInfo) {
|
||||
return someCardInfo.sort(Clipperz.Base.caseInsensitiveKeyComparator('label'));
|
||||
},
|
||||
|
||||
showRecordList: function () {
|
||||
var deferredResult;
|
||||
|
||||
deferredResult = new Clipperz.Async.Deferred('MainController.showRecordList', {trace:false});
|
||||
deferredResult.addMethod(this, 'allCardInfo');
|
||||
deferredResult.addMethod(this, 'filterCards');
|
||||
deferredResult.addMethod(this, 'sortCards');
|
||||
deferredResult.addCallback(MochiKit.Base.bind(function (someRecordInfo) {
|
||||
this.pages()['cardListPage'].setProps({cardList: someRecordInfo});
|
||||
}, this));
|
||||
deferredResult.callback();
|
||||
|
||||
return deferredResult;
|
||||
},
|
||||
|
||||
filter: function () {
|
||||
return this._filter;
|
||||
},
|
||||
|
||||
setFilter: function (aValue) {
|
||||
this._filter = aValue;
|
||||
},
|
||||
|
||||
searchCards: function (someParameters) {
|
||||
//console.log("SEARCH CARDS", someParameters);
|
||||
this.setFilter(someParameters);
|
||||
this.showRecordList();
|
||||
},
|
||||
|
||||
//=========================================================================
|
||||
|
||||
runApplication: function () {
|
||||
MochiKit.Signal.connect(window, 'onpopstate', MochiKit.Base.method(this, 'historyGoBack'));
|
||||
this.moveInPage(this.currentPage(), 'cardListPage');
|
||||
return this.showRecordList();
|
||||
},
|
||||
|
||||
showRecord: function (aRecordReference) {
|
||||
//console.log("Show Record", aRecordReference);
|
||||
var deferredResult;
|
||||
|
||||
this.pages()['cardListPage'].setProps({selectedCard:aRecordReference});
|
||||
deferredResult = new Clipperz.Async.Deferred('MainController.runApplication', {trace:false});
|
||||
// deferredResult.addMethod(this.user(), 'getRecord', aRecordReference['_reference']);
|
||||
deferredResult.addMethod(this.user(), 'getRecord', aRecordReference);
|
||||
deferredResult.addMethodcaller('content');
|
||||
deferredResult.addCallback(MochiKit.Base.bind(function (aCard) {
|
||||
//console.log("CARD DETAILS", aCard);
|
||||
this.pages()['cardDetailPage'].setProps({card: aCard});
|
||||
this.pages()['cardListPage'].setProps({selectedCard: null});
|
||||
}, this));
|
||||
deferredResult.addMethod(this, 'moveInPage', this.currentPage(), 'cardDetailPage', true);
|
||||
deferredResult.callback();
|
||||
|
||||
return deferredResult;
|
||||
},
|
||||
|
||||
runDirectLogin: function (someParameters) {
|
||||
console.log("RUN DIRECT LOGIN", someParameters);
|
||||
var deferredResult;
|
||||
|
||||
// this.pages()['cardListPage'].setProps({selectedCard:aRecordReference});
|
||||
deferredResult = new Clipperz.Async.Deferred('MainController.runDirectLogin', {trace:false});
|
||||
// deferredResult.addMethod(this.user(), 'getRecord', aRecordReference['_reference']);
|
||||
deferredResult.addMethod(this.user(), 'getRecord', someParameters['record']);
|
||||
deferredResult.addMethodcaller('directLoginWithReference', someParameters['directLogin']);
|
||||
deferredResult.addCallback(Clipperz.PM.UI.DirectLoginRunner.openDirectLogin);
|
||||
deferredResult.callback();
|
||||
|
||||
return deferredResult;
|
||||
},
|
||||
|
||||
shouldExitApp: function (anEvent) {
|
||||
console.log("SHOULD EXIT APP");
|
||||
anEvent.preventDefault();
|
||||
anEvent.stopPropagation();
|
||||
},
|
||||
|
||||
//=========================================================================
|
||||
|
||||
genericErrorHandler: function (anEvent, anError) {
|
||||
var errorMessage;
|
||||
var result;
|
||||
|
||||
result = anError;
|
||||
errorMessage = "login failed";
|
||||
|
||||
if (anError['isPermanent'] === true) {
|
||||
this.pages()['errorPage'].setProps({message:anError.message});
|
||||
this.moveInPage(this.currentPage(), 'errorPage');
|
||||
errorMessage = "failure";
|
||||
} else {
|
||||
if ('pin' in anEvent) {
|
||||
errorCount = Clipperz.PM.PIN.recordFailedAttempt();
|
||||
if (errorCount == -1) {
|
||||
errorMessage = "PIN resetted";
|
||||
}
|
||||
}
|
||||
}
|
||||
this.overlay().failed(errorMessage, 1);
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
//=========================================================================
|
||||
|
||||
slidePage: function (fromPage, toPage, direction) {
|
||||
var fromPosition;
|
||||
var toPosition;
|
||||
|
||||
if (direction == "LEFT") {
|
||||
fromPosition = 'right';
|
||||
toPosition = 'left'
|
||||
} else {
|
||||
fromPosition = 'left';
|
||||
toPosition = 'right'
|
||||
}
|
||||
|
||||
MochiKit.DOM.addElementClass(fromPage, toPosition + ' transition');
|
||||
|
||||
MochiKit.DOM.addElementClass(toPage, fromPosition);
|
||||
MochiKit.DOM.removeElementClass(toPage, toPosition);
|
||||
MochiKit.DOM.addElementClass(toPage, 'transition');
|
||||
MochiKit.Async.callLater(0.1, function () {
|
||||
MochiKit.DOM.removeElementClass(toPage, fromPosition);
|
||||
})
|
||||
|
||||
MochiKit.Async.callLater(0.5, function () {
|
||||
MochiKit.DOM.removeElementClass(fromPage, 'transition');
|
||||
MochiKit.DOM.removeElementClass(toPage, 'transition');
|
||||
})
|
||||
},
|
||||
|
||||
rotateInPage: function (fromPage, toPage) {
|
||||
// Broken! :(
|
||||
MochiKit.DOM.addElementClass(MochiKit.DOM.getElement('mainDiv'), 'show-right');
|
||||
},
|
||||
|
||||
//.........................................................................
|
||||
|
||||
goBack: function () {
|
||||
var fromPage;
|
||||
var toPage;
|
||||
|
||||
fromPage = this.pageStack().shift();
|
||||
toPage = this.currentPage();
|
||||
this.pages()[toPage].setProps({});
|
||||
this.moveOutPage(fromPage, toPage);
|
||||
},
|
||||
|
||||
historyGoBack: function (anEvent) {
|
||||
anEvent.preventDefault();
|
||||
anEvent.stopPropagation();
|
||||
this.goBack();
|
||||
},
|
||||
|
||||
currentPage: function () {
|
||||
return this.pageStack()[0];
|
||||
},
|
||||
|
||||
setCurrentPage: function (aPage) {
|
||||
this.pageStack().unshift(aPage);
|
||||
},
|
||||
|
||||
moveInPage: function (fromPage, toPage, addToHistory) {
|
||||
var shouldAddItemToHistory;
|
||||
|
||||
shouldAddItemToHistory = typeof(addToHistory) == 'undefined' ? false : addToHistory;
|
||||
|
||||
this.slidePage(MochiKit.DOM.getElement(fromPage), MochiKit.DOM.getElement(toPage), 'LEFT');
|
||||
this.setCurrentPage(toPage);
|
||||
|
||||
if (shouldAddItemToHistory) {
|
||||
//console.log("ADD ITEM TO HISTORY");
|
||||
//console.log("ADD ITEM TO HISTORY - window", window);
|
||||
//console.log("ADD ITEM TO HISTORY - window.history", window.history);
|
||||
window.history.pushState({'fromPage': fromPage, 'toPage': toPage});
|
||||
//# window.history.pushState();
|
||||
//console.log("ADDED ITEM TO HISTORY");
|
||||
} else {
|
||||
//console.log("Skip HISTORY");
|
||||
}
|
||||
},
|
||||
|
||||
moveOutPage: function (fromPage, toPage) {
|
||||
this.slidePage(MochiKit.DOM.getElement(fromPage), MochiKit.DOM.getElement(toPage), 'RIGHT');
|
||||
this.setCurrentPage(toPage);
|
||||
},
|
||||
|
||||
//=========================================================================
|
||||
/*
|
||||
wrongAppVersion: function (anError) {
|
||||
// this.pages()['errorPage'].setProps({message:anError.message});
|
||||
// this.moveInPage('errorPage', this.currentPage());
|
||||
},
|
||||
*/
|
||||
//=========================================================================
|
||||
__syntaxFix__: "syntax fix"
|
||||
});
|
||||
Reference in New Issue
Block a user