diff --git a/frontend/delta/js/Clipperz/PM/UI/Components/AccountStatus.js b/frontend/delta/js/Clipperz/PM/UI/Components/AccountStatus.js index 6ada2b8..96db0bd 100644 --- a/frontend/delta/js/Clipperz/PM/UI/Components/AccountStatus.js +++ b/frontend/delta/js/Clipperz/PM/UI/Components/AccountStatus.js @@ -26,12 +26,12 @@ Clipperz.Base.module('Clipperz.PM.UI.Components'); Clipperz.PM.UI.Components.AccountStatus = React.createClass({ propTypes: { - 'currentSubscriptionType': React.PropTypes.oneOf(['EARLY_ADOPTER', 'FRIEND', 'FAN', 'DEVOTEE', 'PATRON', 'TRIAL', 'TRIAL_EXPIRED', 'PAYMENT_FAILED_2', 'EXPIRED', 'PAYMENT_FAILED', 'VERIFYING_PAYMENT', 'VERIFYING_PAYMENT_2']).isRequired, - 'expirationDate': React.PropTypes.string.isRequired, - 'featureSet': React.PropTypes.oneOf(['TRIAL', 'EXPIRED', 'FULL']).isRequired, - 'isExpired': React.PropTypes.bool.isRequired, - 'isExpiring': React.PropTypes.bool.isRequired, - 'paymentVerificationPending': React.PropTypes.bool.isRequired, +// 'currentSubscriptionType': React.PropTypes.oneOf(['EARLY_ADOPTER', 'FRIEND', 'FAN', 'DEVOTEE', 'PATRON', 'TRIAL', 'TRIAL_EXPIRED', 'PAYMENT_FAILED_2', 'EXPIRED', 'PAYMENT_FAILED', 'VERIFYING_PAYMENT', 'VERIFYING_PAYMENT_2']).isRequired, + 'expirationDate': React.PropTypes.string /* .isRequired */, + 'featureSet': React.PropTypes.oneOf(['TRIAL', 'EXPIRED', 'FULL']) /* .isRequired */ , + 'isExpired': React.PropTypes.bool /* .isRequired */ , + 'isExpiring': React.PropTypes.bool /* .isRequired */ , + 'paymentVerificationPending': React.PropTypes.bool /* .isRequired */ , }, //========================================================================= diff --git a/frontend/delta/js/Clipperz/PM/UI/Components/CardToolbar.js b/frontend/delta/js/Clipperz/PM/UI/Components/CardToolbar.js index 36d8746..5503666 100644 --- a/frontend/delta/js/Clipperz/PM/UI/Components/CardToolbar.js +++ b/frontend/delta/js/Clipperz/PM/UI/Components/CardToolbar.js @@ -31,7 +31,7 @@ Clipperz.PM.UI.Components.CardToolbar = React.createClass({ 'enableSidePanels': React.PropTypes.bool.isRequired, 'accountStatus': React.PropTypes.object.isRequired, 'messageBox': React.PropTypes.object.isRequired, - 'filter': React.PropTypes.object.isRequired + 'filter': React.PropTypes.object /*.isRequired */ }, //---------------------------------------------------------------------------- diff --git a/frontend/delta/js/Clipperz/PM/UI/Components/Cards/Toolbar.js b/frontend/delta/js/Clipperz/PM/UI/Components/Cards/CommandToolbar.js similarity index 97% rename from frontend/delta/js/Clipperz/PM/UI/Components/Cards/Toolbar.js rename to frontend/delta/js/Clipperz/PM/UI/Components/Cards/CommandToolbar.js index 5ee4895..f03d24f 100644 --- a/frontend/delta/js/Clipperz/PM/UI/Components/Cards/Toolbar.js +++ b/frontend/delta/js/Clipperz/PM/UI/Components/Cards/CommandToolbar.js @@ -24,7 +24,7 @@ refer to http://www.clipperz.com. 'use strict'; Clipperz.Base.module('Clipperz.PM.UI.Components.Cards'); -Clipperz.PM.UI.Components.Cards.Toolbar = React.createClass({ +Clipperz.PM.UI.Components.Cards.CommandToolbar = React.createClass({ //============================================================================ @@ -124,6 +124,7 @@ Clipperz.PM.UI.Components.Cards.Toolbar = React.createClass({ var style = this.props['style']; var classes = { 'cardDetailToolbar': true, + 'commands': true, }; classes[style] = true; diff --git a/frontend/delta/js/Clipperz/PM/UI/Components/Cards/Detail.js b/frontend/delta/js/Clipperz/PM/UI/Components/Cards/Detail.js new file mode 100644 index 0000000..788f03e --- /dev/null +++ b/frontend/delta/js/Clipperz/PM/UI/Components/Cards/Detail.js @@ -0,0 +1,49 @@ +/* + +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.Cards'); + +Clipperz.PM.UI.Components.Cards.Detail = React.createClass({ + + viewComponentProps: function () { + var result; + + result = this.props['selectedCard']; + if (result) { + result['style'] = this.props['style']; + } + + return result; + }, + + render: function () { + var result; + if (this.props['mode'] == 'edit') { + result = Clipperz.PM.UI.Components.Cards.Edit(this.viewComponentProps()); + } else { + result = Clipperz.PM.UI.Components.Cards.View(this.viewComponentProps()); + } + + return result; + }, +}); diff --git a/frontend/delta/js/Clipperz/PM/UI/Components/Cards/Edit.js b/frontend/delta/js/Clipperz/PM/UI/Components/Cards/Edit.js new file mode 100644 index 0000000..14f04ab --- /dev/null +++ b/frontend/delta/js/Clipperz/PM/UI/Components/Cards/Edit.js @@ -0,0 +1,165 @@ +/* + +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/. + +*/ + +'use strict'; +Clipperz.Base.module('Clipperz.PM.UI.Components.Cards'); + +Clipperz.PM.UI.Components.Cards.Edit = React.createClass({ + + //============================================================================ + + propTypes: { +// 'label': React.PropTypes.string /*.isRequired */ , +// 'loading': React.PropTypes.bool, + }, + + //---------------------------------------------------------------------------- + + record: function () { + return this.props['_record']; + }, + + //============================================================================ + + handleChange: function (anObject , aMethodName) { + var reference = this.props['_reference']; + var method = MochiKit.Base.method(anObject, aMethodName); + + return function (anEvent) { + method(anEvent.target.value); + MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'refreshCardEditDetail', reference); +// MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'refreshCardEditToolbar', reference); + }; + }, + + removeField: function (aField) { + var reference = this.props['_reference']; + var record = this.record(); + + return function (anEvent) { + record.removeField(aField); + MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'refreshCardEditDetail', reference); + }; + }, + + addNewField: function (anEvent) { + var reference = this.props['_reference']; + + this.record().addField({'label':"", 'value':"", 'isHidden':false}); + MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'refreshCardEditDetail', reference); + }, + + //============================================================================ + + renderLabel: function (aLabel) { + return React.DOM.input({'className':'cardLabel', 'onChange':this.handleChange(this.record(), 'setLabel'), 'defaultValue':aLabel}); + }, + + renderNotes: function (someNotes) { + return React.DOM.textarea({'className':'cardNotes', 'onChange':this.handleChange(this.record(), 'setNotes'), 'defaultValue':someNotes}); + }, + + //............................................................................ + + renderTag: function (aTag) { + return React.DOM.div({'className':'cardTag'}, aTag); + }, + + renderTags: function (someTags) { + var tags; + + tags = MochiKit.Base.filter(Clipperz.PM.DataModel.Record.isRegularTag, someTags).sort(Clipperz.Base.caseInsensitiveCompare); + return React.DOM.div({'className':'cardTags'}, MochiKit.Base.map(this.renderTag, tags)); + }, + + //............................................................................ + + renderField: function (aField) { + var ref = aField['_reference']; + var cardFieldClasses = {}; + var cardFieldValueClasses = {}; + var field = aField['_field']; + +//console.log("RENDER FIELD", aField); + cardFieldClasses['cardField'] = true; + cardFieldClasses[aField['actionType']] = true; + cardFieldClasses['hidden'] = aField['isHidden']; + + cardFieldValueClasses['fieldValue'] = true; + cardFieldValueClasses[aField['actionType']] = true; + cardFieldValueClasses['hidden'] = aField['isHidden']; + + return React.DOM.div({'className':React.addons.classSet(cardFieldClasses), 'key':ref}, [ + React.DOM.div({'className':'fieldValues'}, [ + React.DOM.span({'className':'removeField', 'onClick':this.removeField(field)}, "delete"), + React.DOM.input({'className':'fieldLabel', 'onChange':this.handleChange(field, 'setLabel'), 'defaultValue':aField['label']}), + React.DOM.textarea({'className':React.addons.classSet(cardFieldValueClasses), 'onChange':this.handleChange(field, 'setValue'), 'defaultValue':aField['value']}), + ]), + React.DOM.div({'className':'fieldAction action'}, aField['actionType'].toLowerCase()) + ]); + }, + + renderFields: function (someFields) { + return React.DOM.div({'className':'cardFields'}, MochiKit.Base.map(this.renderField, someFields)); + }, + + renderAddNewField: function () { + return React.DOM.div({'className':'newCardField', 'onClick':this.addNewField}, "Add new field"); + }, + + //............................................................................ + + renderDirectLogin: function (aDirectLogin) { + return React.DOM.div({'className':'cardDirectLogin'}, [ + React.DOM.span({'className':'directLoginLabel'}, aDirectLogin['label']), + React.DOM.div({'className':'directLoginAction action'}, 'DIRECT LOGIN') + ]); + }, + + renderDirectLogins: function (someDirectLogins) { + return React.DOM.div({'className':'cardDirectLogins'}, MochiKit.Base.map(this.renderDirectLogin, someDirectLogins)); + }, + + //............................................................................ + + render: function () { + var classes = { + 'edit': true + } + +console.log("RENDER CARD EDIT"); + return React.DOM.div({'className':React.addons.classSet(classes)},[ + Clipperz.PM.UI.Components.Cards.EditToolbar(this.props), + React.DOM.div({'className':'content'}, [ + this.renderLabel(this.props['label']), + this.renderTags(this.props['tags']), + this.renderNotes(this.props['notes']), + this.renderFields(this.props['fields']), + this.renderAddNewField(), + this.renderDirectLogins(this.props['directLogins']) + ]) + ]); + }, + + //========================================================================= +}); diff --git a/frontend/delta/js/Clipperz/PM/UI/Components/Cards/EditToolbar.js b/frontend/delta/js/Clipperz/PM/UI/Components/Cards/EditToolbar.js new file mode 100644 index 0000000..a735ad1 --- /dev/null +++ b/frontend/delta/js/Clipperz/PM/UI/Components/Cards/EditToolbar.js @@ -0,0 +1,72 @@ +/* + +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/. + +*/ + +'use strict'; +Clipperz.Base.module('Clipperz.PM.UI.Components.Cards'); + +Clipperz.PM.UI.Components.Cards.EditToolbar = React.createClass({ + + //============================================================================ + + propTypes: { + 'hasPendingChanges': React.PropTypes.bool.isRequired, + }, + + //---------------------------------------------------------------------------- + + hasPendingChanges: function () { + return this.props['hasPendingChanges']; + }, + + //---------------------------------------------------------------------------- + + cancel: function () { + MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'cancelCardEdits', this.props['_reference']); + }, + + save: function () { + MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'saveCardEdits', this.props['_reference']); + }, + + //---------------------------------------------------------------------------- + + render: function () { + var style = this.props['style']; + var classes = { + 'cardDetailToolbar': true, + 'edit': true, + 'hasPendingChanges': this.hasPendingChanges(), + }; + classes[style] = true; + +console.log("EDIT TOOLBAR", this.props); + return React.DOM.div({'className':React.addons.classSet(classes)}, [ + React.DOM.ul({}, [ + React.DOM.li({'onClick':this.cancel, 'className':'cancel'}, [React.DOM.span({}, "cancel")]), + React.DOM.li({'onClick':this.save, 'className':'save'}, [React.DOM.span({}, "save")]), + ]) + ]); + }, + + //========================================================================= +}); diff --git a/frontend/delta/js/Clipperz/PM/UI/Components/Cards/List.js b/frontend/delta/js/Clipperz/PM/UI/Components/Cards/List.js index b030fba..2fdd2ca 100644 --- a/frontend/delta/js/Clipperz/PM/UI/Components/Cards/List.js +++ b/frontend/delta/js/Clipperz/PM/UI/Components/Cards/List.js @@ -30,7 +30,7 @@ Clipperz.PM.UI.Components.Cards.List = React.createClass({ propTypes: { 'cards': React.PropTypes.array, - 'selectedCard': React.PropTypes.string + 'selectedCard': React.PropTypes.object }, handleClick: function (anEvent) { diff --git a/frontend/delta/js/Clipperz/PM/UI/Components/Cards/View.js b/frontend/delta/js/Clipperz/PM/UI/Components/Cards/View.js index 18e078a..2852ed3 100644 --- a/frontend/delta/js/Clipperz/PM/UI/Components/Cards/View.js +++ b/frontend/delta/js/Clipperz/PM/UI/Components/Cards/View.js @@ -29,7 +29,7 @@ Clipperz.PM.UI.Components.Cards.View = React.createClass({ //============================================================================ propTypes: { - 'label': React.PropTypes.string.isRequired, + 'label': React.PropTypes.string /*.isRequired */ , 'loading': React.PropTypes.bool, }, @@ -138,7 +138,7 @@ Clipperz.PM.UI.Components.Cards.View = React.createClass({ } return React.DOM.div({'className':React.addons.classSet(classes)},[ - Clipperz.PM.UI.Components.Cards.Toolbar(this.props), + Clipperz.PM.UI.Components.Cards.CommandToolbar(this.props), React.DOM.div({'className':'content'}, [ this.renderLabel(this.props['label']), this.renderTags(this.props['tags']), diff --git a/frontend/delta/js/Clipperz/PM/UI/Components/DialogBox.js b/frontend/delta/js/Clipperz/PM/UI/Components/DialogBox.js index 61cc069..0fbd3de 100644 --- a/frontend/delta/js/Clipperz/PM/UI/Components/DialogBox.js +++ b/frontend/delta/js/Clipperz/PM/UI/Components/DialogBox.js @@ -29,21 +29,9 @@ Clipperz.PM.UI.Components.DialogBox = React.createClass({ 'info': React.PropTypes.object.isRequired, 'deferred': React.PropTypes.object.isRequired }, -/* - ask: function (someInfo) { - var deferredResult; - - deferredResult = new Clipperz.Async.Deferred('DialogBox.ask', {trace:false}); - deferredResult.addCallback(someInfo['possibleAnswers']['cancel']['answer']); - deferredResult.callback(); -// deferredResult.cancel(); - - return deferredResult; - }, -*/ //------------------------------------------------------------------------- - +/* handleKeyDown: function (anEvent) { console.log("DIALOG BOX - key DOWN", anEvent); }, @@ -55,13 +43,10 @@ console.log("DIALOG BOX - key PRESS", anEvent); handleKeyUp: function (anEvent) { console.log("DIALOG BOX - key UP", anEvent); }, - +*/ //------------------------------------------------------------------------- handleAnswerButton: function (anEvent) { -//console.log("HANDLE ANSWER BUTTON", anEvent.currentTarget.dataset['answerKey']); -//console.log("ANSWER INFO", this.props['info']['possibleAnswers'][anEvent.currentTarget.dataset['answerKey']]); -//console.log("<-- DEFERRED", this.props['deferred']); this.props['info']['possibleAnswers'][anEvent.currentTarget.dataset['answerKey']]['answer'](this.props['deferred']); }, @@ -78,9 +63,7 @@ console.log("DIALOG BOX - key UP", anEvent); //========================================================================= render: function () { -//console.log("DIALOG BOX", this.props); -//console.log("--> DEFERRED", this.props['deferred']); - return React.DOM.div({'className':'dialogBox', 'onKeyDown':this.handleKeyDown, 'onKeyPress':this.handleKeyPress, 'onKeyUp':this.handleKeyUp}, [ + return React.DOM.div({'className':'dialogBox' /*, 'onKeyDown':this.handleKeyDown, 'onKeyPress':this.handleKeyPress, 'onKeyUp':this.handleKeyUp */ }, [ React.DOM.div({'className':'mask'}), React.DOM.div({'className':'dialog'}, [ React.DOM.h3({'className': 'message'}, this.props['info']['question']), diff --git a/frontend/delta/js/Clipperz/PM/UI/Components/Pages/CardDetailPage.js b/frontend/delta/js/Clipperz/PM/UI/Components/Pages/CardDetailPage.js index 0334c2f..2cc2a78 100644 --- a/frontend/delta/js/Clipperz/PM/UI/Components/Pages/CardDetailPage.js +++ b/frontend/delta/js/Clipperz/PM/UI/Components/Pages/CardDetailPage.js @@ -24,10 +24,30 @@ refer to http://www.clipperz.com. Clipperz.Base.module('Clipperz.PM.UI.Components.Pages'); Clipperz.PM.UI.Components.Pages.CardDetailPage = React.createClass({ - - render: function () { -// return React.DOM.header({'className':''}) - return Clipperz.PM.UI.Components.Cards.View(this.props['selectedCard']); - +/* + viewComponentProps: function () { + var result; + + result = this.props['selectedCard']; + if (result) { + result['style'] = this.props['style']; + } + + return result; }, + + render: function () { + var result; + if (this.props['mode'] == 'edit') { + result = Clipperz.PM.UI.Components.Cards.Edit(this.viewComponentProps()); + } else { + result = Clipperz.PM.UI.Components.Cards.View(this.viewComponentProps()); + } + + return result; + }, +*/ + render: function () { + return Clipperz.PM.UI.Components.Cards.Detail(this.props); + } }); diff --git a/frontend/delta/js/Clipperz/PM/UI/Components/Pages/LoginPage.js b/frontend/delta/js/Clipperz/PM/UI/Components/Pages/LoginPage.js index 4c6ff95..20ebb81 100644 --- a/frontend/delta/js/Clipperz/PM/UI/Components/Pages/LoginPage.js +++ b/frontend/delta/js/Clipperz/PM/UI/Components/Pages/LoginPage.js @@ -95,14 +95,14 @@ Clipperz.PM.UI.Components.Pages.LoginPage = React.createClass({ loginForm: function () { - return React.DOM.form({'className':'loginForm credentials', 'onChange':this.handleChange, 'onSubmit':this.handleCredentialSubmit}, [ - React.DOM.div(null,[ - React.DOM.label({'htmlFor' :'name'}, "username"), - React.DOM.input({'type':'text', 'name':'name', 'ref':'username', 'placeholder':"username", 'key':'username', 'autoCapitalize':'none'}), - React.DOM.label({'htmlFor' :'passphrase'}, "passphrase"), - React.DOM.input({'type':'password', 'name':'passphrase', 'ref':'passphrase', 'placeholder':"passphrase", 'key':'passphrase'}) + return React.DOM.form({'key':'form', 'className':'loginForm credentials', 'onChange':this.handleChange, 'onSubmit':this.handleCredentialSubmit}, [ + React.DOM.div({'key':'fields'},[ + React.DOM.label({'key':'username-label', 'htmlFor' :'name'}, "username"), + React.DOM.input({'key':'username', 'type':'text', 'name':'name', 'ref':'username', 'placeholder':"username", 'autoCapitalize':'none'}), + React.DOM.label({'key':'passphrase-label', 'htmlFor' :'passphrase'}, "passphrase"), + React.DOM.input({'key':'passphrase', 'type':'password', 'name':'passphrase', 'ref':'passphrase', 'placeholder':"passphrase"}) ]), - React.DOM.button({'type':'submit', 'disabled':!this.shouldEnableLoginButton(), 'className':'button'}, "login") + React.DOM.button({'key':'button', 'type':'submit', 'disabled':!this.shouldEnableLoginButton(), 'className':'button'}, "login") ]); }, @@ -141,13 +141,13 @@ Clipperz.PM.UI.Components.Pages.LoginPage = React.createClass({ }, render: function() { - var registrationLink = React.DOM.div({'className':'registrationLink'}, [ - React.DOM.a({'onClick':this.handleRegistrationLinkClick}, "Sign up") + var registrationLink = React.DOM.div({'key':'registrationLink', 'className':'registrationLink'}, [ + React.DOM.a({'key':'signup', 'onClick':this.handleRegistrationLinkClick}, "Sign up") ]); return React.DOM.div({'className':'loginForm ' + this.props['style']}, [ - React.DOM.header({}, 'clipperz'), - React.DOM.div({'className':'form'}, [ + React.DOM.header({'key':'header'}, 'clipperz'), + React.DOM.div({'key':'form-wrapper', 'className':'form'}, [ this.props.mode == 'PIN' ? this.pinForm() : this.loginForm(), ]), this.props.isNewUserRegistrationAvailable ? registrationLink : null diff --git a/frontend/delta/js/Clipperz/PM/UI/Components/Panels/MainPanel.js b/frontend/delta/js/Clipperz/PM/UI/Components/Panels/MainPanel.js index e0deb98..4962092 100644 --- a/frontend/delta/js/Clipperz/PM/UI/Components/Panels/MainPanel.js +++ b/frontend/delta/js/Clipperz/PM/UI/Components/Panels/MainPanel.js @@ -93,7 +93,7 @@ Clipperz.PM.UI.Components.Panels.MainPanel = React.createClass({ }, //---------------------------------------------------------------------------- - +/* viewComponentProps: function () { var result; @@ -105,6 +105,25 @@ Clipperz.PM.UI.Components.Panels.MainPanel = React.createClass({ return result; }, + renderCardDetail: function () { + var result; +//console.log("PROPS", this.props); + if (this.props['mode'] == 'edit') { + result = Clipperz.PM.UI.Components.Cards.Edit(this.viewComponentProps()); + } else { + result = Clipperz.PM.UI.Components.Cards.View(this.viewComponentProps()); + } + + return result; + }, +*/ + + renderCardDetail: function () { + return Clipperz.PM.UI.Components.Cards.Detail(this.props); + }, + + //---------------------------------------------------------------------------- + renderExtraWide: function () { return [ React.DOM.div({'className':'selection subpanel'}, [Clipperz.PM.UI.Components.Selections(this.props)]), @@ -114,7 +133,7 @@ Clipperz.PM.UI.Components.Panels.MainPanel = React.createClass({ [Clipperz.PM.UI.Components.Cards.List(this.props)], [ this.renderExpiredPanel(), - Clipperz.PM.UI.Components.Cards.View(this.viewComponentProps()) + this.renderCardDetail() ] ) ) @@ -131,7 +150,7 @@ Clipperz.PM.UI.Components.Panels.MainPanel = React.createClass({ [Clipperz.PM.UI.Components.Cards.List(this.props)], [ this.renderExpiredPanel(), - Clipperz.PM.UI.Components.Cards.View(this.viewComponentProps()) + this.renderCardDetail() ] ) ) @@ -146,7 +165,7 @@ Clipperz.PM.UI.Components.Panels.MainPanel = React.createClass({ this.renderExpiredPanel(), Clipperz.PM.UI.Components.Cards.List(this.props), ]), - [Clipperz.PM.UI.Components.Cards.View(this.viewComponentProps())] + this.renderCardDetail() ); }, diff --git a/frontend/delta/js/Clipperz/PM/UI/MainController.js b/frontend/delta/js/Clipperz/PM/UI/MainController.js index 75042bd..9067c13 100644 --- a/frontend/delta/js/Clipperz/PM/UI/MainController.js +++ b/frontend/delta/js/Clipperz/PM/UI/MainController.js @@ -71,7 +71,12 @@ Clipperz.PM.UI.MainController = function() { 'selectRecentCards', 'tagSelected', 'selectUntaggedCards', - + + 'refreshCardEditDetail', +// 'refreshCardEditToolbar', + 'saveCardEdits', + 'cancelCardEdits', + 'cardSelected', 'addCardClick', @@ -387,6 +392,7 @@ console.log("SET USER", aUser); var deferredResult; deferredResult = new Clipperz.Async.Deferred('MainController.collectFieldInfo', {trace:false}); + deferredResult.setValue('_field'); deferredResult.addMethod(aField, 'reference'); deferredResult.setValue('_reference'); deferredResult.addMethod(aField, 'label'); @@ -399,7 +405,7 @@ console.log("SET USER", aUser); deferredResult.setValue('isHidden'); deferredResult.values(); - deferredResult.callback(); + deferredResult.callback(aField); return deferredResult; }, @@ -425,18 +431,21 @@ console.log("SET USER", aUser); var deferredResult; deferredResult = new Clipperz.Async.Deferred('MainController.collectRecordInfo', {trace:false}); + deferredResult.setValue('_record'); deferredResult.addMethod(aRecord, 'reference'); deferredResult.setValue('_reference'); deferredResult.addMethod(aRecord, 'isArchived'); deferredResult.setValue('_isArchived'); + deferredResult.addMethod(aRecord, 'hasPendingChanges'); + deferredResult.setValue('hasPendingChanges'); deferredResult.addMethod(aRecord, 'label'); deferredResult.setValue('label'); deferredResult.addMethod(aRecord, 'notes'); deferredResult.setValue('notes'); deferredResult.addMethod(aRecord, 'tags'); deferredResult.setValue('tags'); - deferredResult.addMethod(aRecord, 'isArchived'); - deferredResult.setValue('isArchived'); +// deferredResult.addMethod(aRecord, 'isArchived'); +// deferredResult.setValue('isArchived'); deferredResult.addMethod(aRecord, 'fields'); deferredResult.addCallback(MochiKit.Base.values); @@ -452,19 +461,22 @@ console.log("SET USER", aUser); deferredResult.values(); - deferredResult.callback(); + deferredResult.callback(aRecord); return deferredResult; }, - updateSelectedCard: function (someInfo) { + updateSelectedCard: function (someInfo, shouldShowLoading) { var deferredResult; + var showLoading = typeof shouldShowLoading !== 'undefined' ? shouldShowLoading : true; if (someInfo == null) { this.setPageProperties('mainPage', 'selectedCard', {}); deferredResult = MochiKit.Async.succeed(); } else { - this.setPageProperties('mainPage', 'selectedCard', {'loading':true, 'label':someInfo['label'], '_reference':someInfo['reference']}); + if (showLoading) { + this.setPageProperties('mainPage', 'selectedCard', {'loading':true, 'label':someInfo['label'], '_reference':someInfo['reference']}); + } deferredResult = new Clipperz.Async.Deferred('MainController.updateSelectedCard', {trace:false}); deferredResult.addMethod(this.user(), 'getRecord', someInfo['reference']); @@ -764,22 +776,26 @@ console.log("SET USER", aUser); }, moveInPage: function (fromPage, toPage, addToHistory) { - var shouldAddItemToHistory; + if (fromPage != toPage) { + var shouldAddItemToHistory; - shouldAddItemToHistory = typeof(addToHistory) == 'undefined' ? false : addToHistory; + shouldAddItemToHistory = typeof(addToHistory) == 'undefined' ? false : addToHistory; - this.slidePage(MochiKit.DOM.getElement(fromPage), MochiKit.DOM.getElement(toPage), 'LEFT'); - this.setCurrentPage(toPage); + this.slidePage(MochiKit.DOM.getElement(fromPage), MochiKit.DOM.getElement(toPage), 'LEFT'); + this.setCurrentPage(toPage); - if (shouldAddItemToHistory) { + 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(); + window.history.pushState({'fromPage': fromPage, 'toPage': toPage}); +//# window.history.pushState(); //console.log("ADDED ITEM TO HISTORY"); - } else { + } else { //console.log("Skip HISTORY"); + } + } else { +//console.log("No need to move in the same page"); } }, @@ -938,6 +954,49 @@ console.log("SET USER", aUser); this.updateSelectedCard(someInfo); }, + refreshCardEditDetail_handler: function (aRecordReference) { + this.updateSelectedCard({'reference':aRecordReference}, false); + }, +// refreshCardEditToolbar_handler: function (aRecordReference) { +// +// }, + + saveCardEdits_handler: function (aRecordReference) { + var currentPage = this.pages()[this.currentPage()]; + var self = this; + + return Clipperz.Async.callbacks("MainController.saveCardEdits_handler", [ + MochiKit.Base.method(this.user(), 'saveChanges'), + MochiKit.Base.method(currentPage, 'setProps', {'mode':'view'}), +// MochiKit.Base.method(self, 'updateSelectedCard', {'reference':aRecordReference}, false), +// MochiKit.Base.method(self, 'refreshUI'), + MochiKit.Base.method(this, 'refreshUI', aRecordReference) + ], {trace:true}); + }, + + cancelCardEdits_handler: function (aRecordReference) { + var currentPage = this.pages()[this.currentPage()]; + var self = this; + + return Clipperz.Async.callbacks("MainController.cancelCardEdits_handler", [ + MochiKit.Base.method(this.user(), 'hasPendingChanges'), + Clipperz.Async.deferredIf('HasPendingChanges',[ + MochiKit.Base.method(self, 'ask', { + 'question': "Lose pending changes?", + 'possibleAnswers':{ + 'cancel': {'label':"No", 'isDefault':true, 'answer':MochiKit.Base.methodcaller('cancel', new MochiKit.Async.CancelledError())}, + 'revert': {'label':"Yes", 'isDefault':false, 'answer':MochiKit.Base.methodcaller('callback')} + } + }) + ], [ +// MochiKit.Async.succeed + ]), + MochiKit.Base.method(currentPage, 'setProps', {'mode':'view'}), + MochiKit.Base.method(this.user(), 'revertChanges'), + MochiKit.Base.method(self, 'updateSelectedCard', {'reference':aRecordReference}, false), + ], {trace:true}); + }, + //---------------------------------------------------------------------------- /* askConfirmation: function (aMessage) { @@ -975,7 +1034,6 @@ console.log("ADD CARD CLICK"); var self = this; return Clipperz.Async.callbacks("MainController.deleteCard_handler", [ -// MochiKit.Base.method(this, 'askConfirmation', {'message':"Delete card?"}), MochiKit.Base.method(self, 'ask', { 'question': "Delete card?", 'possibleAnswers':{ @@ -983,7 +1041,6 @@ console.log("ADD CARD CLICK"); 'delete': {'label':"Yes", 'isDefault':false, 'answer':MochiKit.Base.methodcaller('callback')} } }), -//function (aValue) { console.log("<-- ASK", aValue); return aValue; }, MochiKit.Base.method(this.user(), 'getRecord', anEvent['reference']), MochiKit.Base.method(this.user(), 'deleteRecord'), MochiKit.Base.method(this.user(), 'saveChanges'), @@ -1001,7 +1058,8 @@ console.log("ADD CARD CLICK"); }, editCard_handler: function (anEvent) { -console.log("EDIT CARD", anEvent['reference']); +//console.log("EDIT CARD", anEvent['reference']); + this.pages()[this.currentPage()].setProps({'mode': 'edit'}); }, goBackToMainPage_handler: function (anEvent) { diff --git a/frontend/delta/properties/delta.properties.json b/frontend/delta/properties/delta.properties.json index fe3af51..4cf5250 100644 --- a/frontend/delta/properties/delta.properties.json +++ b/frontend/delta/properties/delta.properties.json @@ -154,8 +154,11 @@ "Clipperz/PM/UI/Components/Panels/ExtraFeaturesPanel.js", "Clipperz/PM/UI/Components/Cards/List.js", + "Clipperz/PM/UI/Components/Cards/Detail.js", "Clipperz/PM/UI/Components/Cards/View.js", - "Clipperz/PM/UI/Components/Cards/Toolbar.js", + "Clipperz/PM/UI/Components/Cards/Edit.js", + "Clipperz/PM/UI/Components/Cards/CommandToolbar.js", + "Clipperz/PM/UI/Components/Cards/EditToolbar.js", "Clipperz/PM/UI/Components/AccountStatus.js", diff --git a/frontend/delta/scss/core/layout.scss b/frontend/delta/scss/core/layout.scss index 851f99b..cf8a3b9 100644 --- a/frontend/delta/scss/core/layout.scss +++ b/frontend/delta/scss/core/layout.scss @@ -265,17 +265,17 @@ div.cardContent { @include flexbox(); - div.view { + & > div.view, & > div.edit { @include flex(auto); @include flexbox; @include flex-direction(column); - .cardDetailToolbar { - @include flex(none); - height: $mainCardToolbarHeight; - line-height: $mainCardToolbarHeight; - } +// .cardDetailToolbar { +// @include flex(none); +// height: $mainCardToolbarHeight; +// line-height: $mainCardToolbarHeight; +// } .content { @include flex(auto); @@ -287,20 +287,20 @@ div.cardContent { #cardDetailPage { - .view { + & > .view, & > .edit { @include flexbox(); @include flex-direction(column); height: 100%; - +/* .cardDetailToolbar { @include flex(none); height: $mainCardToolbarHeight; line-height: $mainCardToolbarHeight; - & > div { + &.commands > div { @include flexbox(); @include flex-direction(row); - font-size: 24pt; +// font-size: 24pt; .back { @include flex(auto); @@ -312,8 +312,20 @@ div.cardContent { cursor: pointer; } } + + &.edit { + ul { + @include flexbox(); + @include flex-direction(row); + + li { + @include flex(auto); + cursor: pointer; + } + } + } } - +*/ .content { @include flex(auto); overflow-y: scroll; @@ -321,6 +333,66 @@ div.cardContent { } } +.cardDetailToolbar { + @include flex(none); + height: $mainCardToolbarHeight; + line-height: $mainCardToolbarHeight; + + &.edit { + li.save { + cursor: default; + } + + &.hasPendingChanges { + li.save { + cursor: pointer; + } + } + } + + &.commands > div { + @include flexbox(); + @include flex-direction(row); +// font-size: 24pt; + + .back { + @include flex(auto); + cursor: pointer; + } + + .cardMenuOptions { + @include flex(auto); + cursor: pointer; + } + } + +// &.edit { +// ul { +// @include flexbox(); +// @include flex-direction(row); +// +// li { +// @include flex(auto); +// cursor: pointer; +// } +// } +// } + + ul { + @include flexbox(); + @include flex-direction(row); + + li { + @include flex(auto); + cursor: pointer; + + span { + } + } + } +} + + .button { cursor: pointer; } diff --git a/frontend/delta/scss/core/palette.scss b/frontend/delta/scss/core/palette.scss index d32b2df..99f821e 100644 --- a/frontend/delta/scss/core/palette.scss +++ b/frontend/delta/scss/core/palette.scss @@ -22,14 +22,44 @@ $solarize-Accent-Blue: #268bd2; $solarize-Accent-Cyan: #2aa198; $solarize-Accent-Green: #859900; -// $yellow: $solarize-Accent-Yellow; -// $orange: $solarize-Accent-Orange; -// $red: $solarize-Accent-Red; -// $magenta: $solarize-Accent-Magenta; -// $violete: $solarize-Accent-Violet; -// $blue: $solarize-Accent-Blue; -// $cyan: $solarize-Accent-Cyan; -// $green: $solarize-Accent-Green; + +// +// Flat UI +// http://designmodo.github.io/Flat-UI/ +// + +$turquoise: #1abc9c; +$green-sea: #16a085; + +$emerald: #2ecc71; +$nephritis: #27ae60; + +$peter-river: #3498db; +$belize-hole: #2980b9; + +$amethyst: #9b59b6; +$wisteria: #8e44ad; + +$wet-asphalt: #34495e; +$midnight-blue: #2c3e50; + +$sun-flower: #f1c40f; +$orange: #f39c12; + +$carrot: #e67e22; +$pumpkin: #d35400; + +$alizarin: #e74c3c; +$pomegranate: #c0392b; + +$clouds: #ecf0f1; +$silver: #bdc3c7; + +$concrete: #95a5a6; +$asbestos: #7f8c8d; + + +//------------------------------------------------- $clipperz-orange: #ff9900; $clipperz-blue: #1863a1; diff --git a/frontend/delta/scss/style/card.scss b/frontend/delta/scss/style/card.scss index a600df6..60c38c9 100644 --- a/frontend/delta/scss/style/card.scss +++ b/frontend/delta/scss/style/card.scss @@ -104,22 +104,12 @@ $cardViewBasePadding: 10px; } .cardDetailToolbar { - - ul { - @include flexbox(); - @include flex-direction(row); - - li { - @include flex(auto); - text-align: center; - - span { - cursor: pointer; - } - } - } - + background-color: $cardToolbarBackgroundColor; + color: white; + &.narrow { + font-size: 24pt; + .back { @include icon-font(); } @@ -183,6 +173,13 @@ $cardViewBasePadding: 10px; } } } + + .edit { + .cardDetailToolbar { + background-color: purple; + color: white; + } + } } @@ -190,11 +187,31 @@ $cardViewBasePadding: 10px; .cardDetailToolbar { - background-color: $cardToolbarBackgroundColor; - color: white; + &.edit { + li { + font-weight: 100; + } + li.save { + color: yellow; + } + + &.hasPendingChanges { + li { + font-weight: 500; + } + li.save { + color: white; + } + } + } + + ul { + li { + text-align: center; + } + } &.narrow { - .cardMenuOptions { margin-right: 5px; } @@ -276,3 +293,4 @@ $cardViewBasePadding: 10px; cursor: pointer; } } + diff --git a/properties/license.txt b/properties/license.txt index 60d64b3..5e96cab 100644 --- a/properties/license.txt +++ b/properties/license.txt @@ -1,6 +1,6 @@ GNU AFFERO GENERAL PUBLIC LICENSE -Copyright 2008-2013 Clipperz Srl +Copyright 2008-2014 Clipperz Srl This file is part of Clipperz's Password Manager web application. diff --git a/scripts/builder/frontendBuilder.py b/scripts/builder/frontendBuilder.py index dedd08f..96eaaf9 100755 --- a/scripts/builder/frontendBuilder.py +++ b/scripts/builder/frontendBuilder.py @@ -373,7 +373,8 @@ class FrontendBuilder(object): pageTitle = "Clipperz - " + self.module + " [" + versionType + " - " + assemblyMode +"]" for cssFile in self.settings['css']: - self.preprocessCSS(self.absolutePathForSourceFile('css', cssFile)) +# self.preprocessCSS(self.absolutePathForSourceFile('css', cssFile)) + pass if assemblyMode == 'INSTALL': copyright = self.assembleCopyrightHeader()