From edeb859746e2581c80d397c5ac333fc84f13a45a Mon Sep 17 00:00:00 2001 From: Giulio Cesare Solaroli Date: Tue, 14 Apr 2015 11:07:10 +0200 Subject: [PATCH] Merged and cleaned-up features implemented by Dario - delete account - change passphrase --- frontend/delta/css/clipperz.css | 180 +++++++++++++----- .../delta/js/Clipperz/PM/DataModel/User.js | 10 - .../Components/ExtraFeatures/DeleteAccount.js | 41 +--- .../UI/Components/ExtraFeatures/Passphrase.js | 115 +++++------ .../js/Clipperz/PM/UI/Components/Overlay.js | 4 +- .../Components/Panels/ExtraFeaturesPanel.js | 31 ++- .../delta/js/Clipperz/PM/UI/MainController.js | 19 +- frontend/delta/scss/core/layout.scss | 2 +- frontend/delta/scss/style/dialogBox.scss | 4 + frontend/delta/scss/style/settingsPanel.scss | 120 +++++++++--- 10 files changed, 330 insertions(+), 196 deletions(-) diff --git a/frontend/delta/css/clipperz.css b/frontend/delta/css/clipperz.css index ddd4ad0..2c6fab1 100644 --- a/frontend/delta/css/clipperz.css +++ b/frontend/delta/css/clipperz.css @@ -128,6 +128,7 @@ http://jonibologna.com/flexbox-cheatsheet/ -ms-transform: rotate(0deg) translate(0, 0); -o-transform: rotate(0deg) translate(0, 0); transform: rotate(0deg) translate(0, 0); } + 100% { -webkit-transform: rotate(359deg) translate(0, 0); -moz-transform: rotate(359deg) translate(0, 0); @@ -141,6 +142,7 @@ http://jonibologna.com/flexbox-cheatsheet/ -ms-transform: rotate(0deg) translate(0, 0); -o-transform: rotate(0deg) translate(0, 0); transform: rotate(0deg) translate(0, 0); } + 100% { -webkit-transform: rotate(359deg) translate(0, 0); -moz-transform: rotate(359deg) translate(0, 0); @@ -154,6 +156,7 @@ http://jonibologna.com/flexbox-cheatsheet/ -ms-transform: rotate(0deg) translate(0, 0); -o-transform: rotate(0deg) translate(0, 0); transform: rotate(0deg) translate(0, 0); } + 100% { -webkit-transform: rotate(359deg) translate(0, 0); -moz-transform: rotate(359deg) translate(0, 0); @@ -167,6 +170,7 @@ http://jonibologna.com/flexbox-cheatsheet/ -ms-transform: rotate(0deg) translate(0, 0); -o-transform: rotate(0deg) translate(0, 0); transform: rotate(0deg) translate(0, 0); } + 100% { -webkit-transform: rotate(359deg) translate(0, 0); -moz-transform: rotate(359deg) translate(0, 0); @@ -469,61 +473,73 @@ div.overlay { @-webkit-keyframes overlay-spin { from { opacity: 1; } + to { opacity: 0.25; } } @-moz-keyframes overlay-spin { from { opacity: 1; } + to { opacity: 0.25; } } @-ms-keyframes overlay-spin { from { opacity: 1; } + to { opacity: 0.25; } } @keyframes overlay-spin { from { opacity: 1; } + to { opacity: 0.25; } } @-webkit-keyframes ios-overlay-show { 0% { opacity: 0; } + 100% { opacity: 1; } } @-moz-keyframes ios-overlay-show { 0% { opacity: 0; } + 100% { opacity: 1; } } @-ms-keyframes ios-overlay-show { 0% { opacity: 0; } + 100% { opacity: 1; } } @keyframes ios-overlay-show { 0% { opacity: 0; } + 100% { opacity: 1; } } @-webkit-keyframes ios-overlay-hide { 0% { opacity: 1; } + 100% { opacity: 0; } } @-moz-keyframes ios-overlay-hide { 0% { opacity: 1; } + 100% { opacity: 0; } } @-ms-keyframes ios-overlay-hide { 0% { opacity: 1; } + 100% { opacity: 0; } } @keyframes ios-overlay-hide { 0% { opacity: 1; } + 100% { opacity: 0; } } /* @@ -1206,7 +1222,7 @@ div.dialogBox { z-index: 10; background-color: rgba(0, 0, 0, 0.5); } div.dialogBox .mask { - z-index: 12; } + z-index: 25; } div.dialogBox div.dialog { -webkit-box-flex: none; -webkit-flex: none; @@ -1494,11 +1510,11 @@ div.dialogBox { flex: 1; font-size: 8pt; } #loginPage div.loginForm footer .applicationVersion span { - color: #999; } + color: #999999; } #loginPage div.loginForm footer .applicationVersion span:after { content: ":"; } #loginPage div.loginForm footer .applicationVersion a { - color: #999; + color: #999999; text-decoration: none; padding-left: 5px; font-weight: bold; } @@ -1983,20 +1999,22 @@ span.count { border-top: 1px solid white; } #extraFeaturesPanel .extraFeatureIndex > div > ul > li { border-bottom: 1px solid white; } - #extraFeaturesPanel .extraFeatureIndex > div > ul > li > ul { - padding-left: 10px; } + #extraFeaturesPanel .extraFeatureIndex > div > ul > li > h1 { + cursor: pointer; + font-size: 16pt; + padding: 10px; } #extraFeaturesPanel .extraFeatureIndex > div > ul > li.closed > ul { display: none; visibility: hidden; } #extraFeaturesPanel .extraFeatureIndex > div ul li > ul > li { padding: 10px; - padding-right: 0px; } + padding-left: 20px; + padding-right: 0px; + cursor: pointer; } + #extraFeaturesPanel .extraFeatureIndex > div ul li > ul > li.selected { + background-color: #333; } #extraFeaturesPanel .extraFeatureIndex > div ul li > ul > li > div { padding: 4px; } - #extraFeaturesPanel .extraFeatureIndex > div ul li h1 { - cursor: pointer; - font-size: 16pt; - padding: 10px; } #extraFeaturesPanel .extraFeatureIndex > div ul li h2 { font-weight: 300; font-size: 14pt; } @@ -2024,46 +2042,114 @@ span.count { #extraFeaturesPanel .extraFeatureIndex footer { font-size: 8pt; padding: 5px 5px 5px 5px; - border-top: 1px solid #999; } + border-top: 1px solid #999999; } #extraFeaturesPanel .extraFeatureIndex footer span { - color: #999; } + color: #999999; } #extraFeaturesPanel .extraFeatureIndex footer span:after { content: ":"; } #extraFeaturesPanel .extraFeatureIndex footer a { - color: #999; + color: #999999; text-decoration: none; padding-left: 5px; font-weight: bold; } #extraFeaturesPanel .extraFeatureContent { border-right: 1px solid #222; - color: white; } + color: white; + /* + .changePassphraseForm { + label { + display: block; + } + + input { + display: block; + } + } + + .deleteAccountForm { + margin-top: 1em; + + label { + display: block; + } + + input { + display: inline-block; + margin-right: 1em; + margin-bottom: 1em; + } + + .confirmCheckbox { + display: inline-block; + } + } + */ } #extraFeaturesPanel .extraFeatureContent header { display: none; } - #extraFeaturesPanel .extraFeatureContent .changePassphraseForm label { - display: block; } - #extraFeaturesPanel .extraFeatureContent .changePassphraseForm input { - display: block; } - #extraFeaturesPanel .extraFeatureContent .deleteAccountForm { - margin-top: 1em; } - #extraFeaturesPanel .extraFeatureContent .deleteAccountForm label { - display: block; } - #extraFeaturesPanel .extraFeatureContent .deleteAccountForm input { - display: inline-block; - margin-right: 1em; - margin-bottom: 1em; } - #extraFeaturesPanel .extraFeatureContent .deleteAccountForm .confirmCheckbox { - display: inline-block; } - #extraFeaturesPanel .extraFeatureContent form input.valid + .invalidMsg, #extraFeaturesPanel .extraFeatureContent form input.empty + .invalidMsg, #extraFeaturesPanel .extraFeatureContent form input:focus + .invalidMsg, #extraFeaturesPanel .extraFeatureContent form input.invalid:focus + .invalidMsg { - visibility: hidden; } - #extraFeaturesPanel .extraFeatureContent form input:focus { - border: 2px solid #ff9900; } - #extraFeaturesPanel .extraFeatureContent form input.valid:focus { - border: 2px solid #1863a1; } - #extraFeaturesPanel .extraFeatureContent form input.invalid + .invalidMsg { - visibility: visible; } - #extraFeaturesPanel .extraFeatureContent form .invalidMsg::before { - font-family: serif; - content: "\26A0 \0000a0"; } + #extraFeaturesPanel .extraFeatureContent .extraFeature { + padding: 20px; } + #extraFeaturesPanel .extraFeatureContent .extraFeature h1 { + font-size: 20pt; + padding-bottom: 20px; } + #extraFeaturesPanel .extraFeatureContent form label { + display: none; } + #extraFeaturesPanel .extraFeatureContent form input { + display: block; + font-size: 18pt; + margin-bottom: 8px; + padding: 6px 10px; + border: 0px solid white; + width: 350px; + color: black; } + #extraFeaturesPanel .extraFeatureContent form input.invalid { + border: 0px solid #ff9900; + color: gray; } + #extraFeaturesPanel .extraFeatureContent form p { + display: -webkit-box; + display: -webkit-flex; + display: -moz-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-direction: normal; + -webkit-box-orient: horizontal; + -webkit-flex-direction: row; + -moz-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; } + #extraFeaturesPanel .extraFeatureContent form p input { + width: 30px; + -webkit-box-flex: auto; + -webkit-flex: auto; + -moz-box-flex: auto; + -moz-flex: auto; + -ms-flex: auto; + flex: auto; } + #extraFeaturesPanel .extraFeatureContent form p span { + -webkit-box-flex: auto; + -webkit-flex: auto; + -moz-box-flex: auto; + -moz-flex: auto; + -ms-flex: auto; + flex: auto; + font-size: 12pt; } + #extraFeaturesPanel .extraFeatureContent form button { + font-family: "clipperz-font"; + color: white; + font-size: 14pt; + border: 0px; + margin-top: 20px; + padding: 6px 10px; + border: 1px solid white; + background-color: #ff9900; + -webkit-transition: background-color font-weight 0.2s linear; + -moz-transition: background-color font-weight 0.2s linear; + -o-transition: background-color font-weight 0.2s linear; + -ms-transition: background-color font-weight 0.2s linear; + transition: background-color font-weight 0.2s linear; } + #extraFeaturesPanel .extraFeatureContent form button:disabled { + font-weight: 100; + background-color: #c0c0c0; + cursor: default; } .mainPage.narrow #extraFeaturesPanel .extraFeatureContent header { display: block; @@ -2145,7 +2231,7 @@ div.cardList ul { padding-right: 0px; box-shadow: -4px 0px 3px -1px rgba(0, 0, 0, 0.2); } div.cardList ul li.archived { - background-color: #eee; + background-color: #eeeeee; color: #999; } div.cardList ul li .favicon { width: 48px; @@ -2231,7 +2317,7 @@ div.cardList.narrow { content: ""; } #cardDetailPage .view.archived, .cardDetail .view.archived { - background-color: #eee; } + background-color: #eeeeee; } #cardDetailPage .view .cardDetailToolbar, .cardDetail .view .cardDetailToolbar { background-color: #1863a1; color: white; } @@ -2425,7 +2511,7 @@ div.cardList.narrow { cursor: grab; cursor: -moz-grab; cursor: -webkit-grab; - background: repeating-linear-gradient(0deg, white, white 2px, #ddd 2px, #ddd 3px); + background: repeating-linear-gradient(0deg, white, white 2px, #dddddd 2px, #dddddd 3px); width: 28px; height: 20px; margin-left: 6px; @@ -2580,12 +2666,16 @@ div.dialog { -webkit-border-radius: 8px; -moz-border-radius: 8px; border-radius: 8px; + max-width: 70%; background-color: white; - padding: 30px; } + padding: 30px; + box-shadow: 4px 4px 6px 5px rgba(0, 0, 0, 0.3); } div.dialog h3.message { font-size: 18pt; font-weight: bold; - padding-bottom: 20px; } + padding-bottom: 20px; + white-space: pre-wrap; + word-wrap: break-word; } div.dialog div.answers div.button { -webkit-border-radius: 4; -moz-border-radius: 4; @@ -2656,5 +2746,3 @@ This configuration is now located in the first script included in the index_temp } } */ - -/*# sourceMappingURL=clipperz.css.map */ diff --git a/frontend/delta/js/Clipperz/PM/DataModel/User.js b/frontend/delta/js/Clipperz/PM/DataModel/User.js index 365dccf..7b10a2e 100644 --- a/frontend/delta/js/Clipperz/PM/DataModel/User.js +++ b/frontend/delta/js/Clipperz/PM/DataModel/User.js @@ -244,11 +244,7 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User, Object, { return deferredResult; }, - // TODO: test (taken straight from /beta) 'deleteAccount': function() { - -console.log("deleting account from user"); - var deferredResult; deferredResult = new MochiKit.Async.Deferred("User.deleteAccount", {trace: true}); @@ -257,15 +253,9 @@ console.log("deleting account from user"); deferredResult.callback(); return deferredResult; - - }, - // TODO: check (I have half of an idea what i'm doing) 'resetAllLocalData': function() { - -console.log("resetting all local data..."); - var deferredResult; deferredResult = new MochiKit.Async.Deferred("User.resetAllLocalData", {trace: true}); diff --git a/frontend/delta/js/Clipperz/PM/UI/Components/ExtraFeatures/DeleteAccount.js b/frontend/delta/js/Clipperz/PM/UI/Components/ExtraFeatures/DeleteAccount.js index a38c17d..3c71f0d 100644 --- a/frontend/delta/js/Clipperz/PM/UI/Components/ExtraFeatures/DeleteAccount.js +++ b/frontend/delta/js/Clipperz/PM/UI/Components/ExtraFeatures/DeleteAccount.js @@ -36,7 +36,6 @@ Clipperz.PM.UI.Components.ExtraFeatures.DeleteAccountClass = React.createClass({ 'username': 'empty', 'passphrase': 'empty', 'confirm': '', - //~ 'error': '' }; }, @@ -44,36 +43,10 @@ Clipperz.PM.UI.Components.ExtraFeatures.DeleteAccountClass = React.createClass({ handleDeleteAccount: function(event) { event.preventDefault(); - - //~ if (this.refs['username'].getDOMNode().value != this.props.userInfo['username']) { - //~ this.setState({error: "Invalid username"}); - //~ return; - //~ } - //~ - //~ var deferredResult; - //~ - //~ deferredResult = new Clipperz.Async.Deferred("DeleteAccount.handleDeleteAccount", {trace: false}); - //~ deferredResult.addCallback(this.props.userInfo['checkPassphraseCallback'], this.refs['passphrase'].getDOMNode().value); - //~ deferredResult.addIf( - //~ [MochiKit.Base.partial(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'deleteAccount')], - //~ [MochiKit.Base.bind(this.setState, this, {error: "Invalid password"})] - //~ ); - //~ - //~ deferredResult.callback(); - //~ - //~ return deferredResult; - MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'deleteAccount'); }, handleFormChange: function() { - - - //~ if (this.refs['username'].getDOMNode().value != this.props.userInfo['username']) { - //~ this.setState({error: "Invalid username"}); - //~ return; - //~ } - var deferredResult; deferredResult = new Clipperz.Async.Deferred("DeleteAccount.handleDeleteAccount", {trace: false}); @@ -92,14 +65,6 @@ Clipperz.PM.UI.Components.ExtraFeatures.DeleteAccountClass = React.createClass({ deferredResult.callback(); return deferredResult; - - - - //~ this.setState({ - //~ 'username': this.refs['username'].getDOMNode().value, - //~ 'passphrase': this.refs['passphrase'].getDOMNode().value, - //~ 'confirm': this.refs['confirm'].getDOMNode().checked, - //~ }); }, shouldEnableDeleteAccountButton: function() { @@ -116,11 +81,9 @@ Clipperz.PM.UI.Components.ExtraFeatures.DeleteAccountClass = React.createClass({ React.DOM.form({'key':'form', 'className':'deleteAccountForm', 'onChange': this.handleFormChange, 'onSubmit':this.handleDeleteAccount}, [ React.DOM.div({'key':'fields'},[ React.DOM.label({'key':'username-label', 'htmlFor' :'name'}, "username"), - React.DOM.input({'key':'username', 'className': this.state['username'], 'type':'text', 'name':'name', 'ref':'username', 'placeholder':"username", 'autoCapitalize':'none'}), - React.DOM.span({'className': 'invalidMsg'},'Invalid username!'), + React.DOM.input({'key':'username', 'className':this.state['username'], 'type':'text', 'name':'name', 'ref':'username', 'placeholder':"username", 'autoCapitalize':'none'}), React.DOM.label({'key':'passphrase-label', 'autoFocus': 'true', 'htmlFor' :'passphrase'}, "passphrase"), - React.DOM.input({'key':'passphrase', 'className': this.state['passphrase'], 'type':'password', 'name':'passphrase', 'ref':'passphrase', 'placeholder':"passphrase"}), - React.DOM.span({'className': 'invalidMsg'},'Invalid passphrase!'), + React.DOM.input({'key':'passphrase', 'className':this.state['passphrase'], 'type':'password', 'name':'passphrase', 'ref':'passphrase', 'placeholder':"passphrase"}), React.DOM.p({}, [ React.DOM.input({'key':'confirm', 'className':'confirmCheckbox', 'type':'checkbox', 'name':'confirm', 'ref':'confirm'}), React.DOM.span({}, "I understand that all my data will be deleted and that this action is irreversible.") diff --git a/frontend/delta/js/Clipperz/PM/UI/Components/ExtraFeatures/Passphrase.js b/frontend/delta/js/Clipperz/PM/UI/Components/ExtraFeatures/Passphrase.js index aaa0512..a286d3a 100644 --- a/frontend/delta/js/Clipperz/PM/UI/Components/ExtraFeatures/Passphrase.js +++ b/frontend/delta/js/Clipperz/PM/UI/Components/ExtraFeatures/Passphrase.js @@ -27,95 +27,100 @@ Clipperz.Base.module('Clipperz.PM.UI.Components.ExtraFeatures'); Clipperz.PM.UI.Components.ExtraFeatures.PassphraseClass = React.createClass({ propTypes: { -// featureSet: React.PropTypes.oneOf(['FULL', 'EXPIRED', 'TRIAL']).isRequired, -// 'level': React.PropTypes.oneOf(['hide', 'info', 'warning', 'error']).isRequired }, getInitialState: function() { return { - 'username': '', - 'old-passphrase': '', - 'new-passphrase': '', - 'confirm-new-passphrase': '', - 'error': '' + 'username': 'empty', + 'old-passphrase': 'empty', + 'new-passphrase': 'empty', + 'confirm-new-passphrase': 'empty', + 'confirm': '', }; }, //========================================================================= - shouldEnableChangePassphraseButton: function() { - return ( - this.state['username'] && - this.state['old-passphrase'] && - this.state['new-passphrase'] && - this.state['confirm-new-passphrase'] && - (this.state['new-passphrase'] == this.state['confirm-new-passphrase']) - ); - }, - - handleFormChange: function() { - this.setState({ - 'username': this.refs['username'].getDOMNode().value, - 'old-passphrase': this.refs['old-passphrase'].getDOMNode().value, - 'new-passphrase': this.refs['new-passphrase'].getDOMNode().value, - 'confirm-new-passphrase': this.refs['confirm-new-passphrase'].getDOMNode().value - }); + resetForm: function () { + this.setState(this.getInitialState()); + + this.refs['username'].getDOMNode().value = ''; + this.refs['old-passphrase'].getDOMNode().value = ''; + this.refs['new-passphrase'].getDOMNode().value = ''; + this.refs['confirm-new-passphrase'].getDOMNode().value = ''; + this.refs['confirm'].getDOMNode().checked = false; }, handleChangePassphrase: function(event) { - event.preventDefault(); - - if (this.refs['username'].getDOMNode().value != this.props.userInfo['username']) { - this.setState({error: "Invalid username"}); - return; - } + var newPassphrase; + event.preventDefault(); + newPassphrase = this.refs['new-passphrase'].getDOMNode().value; + this.resetForm(); + + MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'changePassphrase', newPassphrase); + }, + + handleFormChange: function() { var deferredResult; - deferredResult = new Clipperz.Async.Deferred("Passphrase.handleChangePassphrase", {trace: false}); + deferredResult = new Clipperz.Async.Deferred("Passphrase.handleFormChange", {trace: false}); deferredResult.addCallback(this.props.userInfo['checkPassphraseCallback'], this.refs['old-passphrase'].getDOMNode().value); - deferredResult.addIf( - [ - MochiKit.Base.partial(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'changePassphrase', this.refs['new-passphrase'].getDOMNode().value), - MochiKit.Base.method(this, function() { - this.refs['username'].getDOMNode().value = ''; - this.refs['old-passphrase'].getDOMNode().value = ''; - this.refs['new-passphrase'].getDOMNode().value = ''; - this.refs['confirm-new-passphrase'].getDOMNode().value = ''; - this.setState({'error': ''}); - }) - ], - [MochiKit.Base.bind(this.setState, this, {error: "Invalid password"})] - ); + deferredResult.addMethod(this, function(passCheck){ + var username = this.refs['username'].getDOMNode().value; + var oldPassphrase = this.refs['old-passphrase'].getDOMNode().value; + var newPassphrase = this.refs['new-passphrase'].getDOMNode().value; + var confirmNewPassphrase = this.refs['confirm-new-passphrase'].getDOMNode().value; + + this.setState({ + 'username': (username != '') ? [(username == this.props.userInfo['username']) ? 'valid' : 'invalid'] : 'empty', + 'old-passphrase': (oldPassphrase != '') ? [(passCheck) ? 'valid' : 'invalid'] : 'empty', + 'new-passphrase': (newPassphrase != '') ? 'valid' : 'empty', + 'confirm-new-passphrase': (confirmNewPassphrase != '') ? [(confirmNewPassphrase == newPassphrase) ? 'valid' : 'invalid'] : 'empty', + 'confirm': this.refs['confirm'].getDOMNode().checked, + }); + }); deferredResult.callback(); return deferredResult; - -// MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'changePassphrase', this.refs['new-passphrase'].getDOMNode().value); - + }, + + shouldEnableChangePassphraseButton: function() { + return ( + this.state['username'] == 'valid' && + this.state['old-passphrase'] == 'valid' && + this.state['new-passphrase'] == 'valid' && + this.state['confirm-new-passphrase'] == 'valid' && + this.state['confirm'] + ); }, //========================================================================= render: function () { - var errorVisibility = (this.state.error) ? 'visible' : 'hidden'; - return React.DOM.div({className:'extraFeature passphrase'}, [ React.DOM.h1({}, "Change Passphrase"), React.DOM.form({'key':'form', 'className':'changePassphraseForm', 'onChange': this.handleFormChange, 'onSubmit':this.handleChangePassphrase}, [ 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.input({'key':'username', 'className':this.state['username'], 'type':'text', 'name':'name', 'ref':'username', 'placeholder':"username", 'autoCapitalize':'none'}), + React.DOM.label({'key':'old-passphrase-label', 'htmlFor' :'old-passphrase'}, "old passphrase"), - React.DOM.input({'key':'old-passphrase', 'type':'password', 'name':'old-passphrase', 'ref':'old-passphrase', 'placeholder':"old passphrase"}), + React.DOM.input({'key':'old-passphrase', 'className':this.state['old-passphrase'], 'type':'password', 'name':'old-passphrase', 'ref':'old-passphrase', 'placeholder':"old passphrase"}), + React.DOM.label({'key':'new-passphrase-label', 'autoFocus': 'true', 'htmlFor' :'new-passphrase'}, "new passphrase"), - React.DOM.input({'key':'new-passphrase', 'type':'password', 'name':'new-passphrase', 'ref':'new-passphrase', 'placeholder':"new passphrase"}), + React.DOM.input({'key':'new-passphrase', 'className':this.state['new-passphrase'], 'type':'password', 'name':'new-passphrase', 'ref':'new-passphrase', 'placeholder':"new passphrase"}), + React.DOM.label({'key':'confirm-new-passphrase-label', 'htmlFor' :'confirm-new-passphrase'}, "confirm new passphrase"), - React.DOM.input({'key':'confirm-new-passphrase', 'type':'password', 'name':'confirm-new-passphrase', 'ref':'confirm-new-passphrase', 'placeholder':"confirm new passphrase"}) + React.DOM.input({'key':'confirm-new-passphrase', 'className':this.state['confirm-new-passphrase'], 'type':'password', 'name':'confirm-new-passphrase', 'ref':'confirm-new-passphrase', 'placeholder':"confirm new passphrase"}), + + React.DOM.p({}, [ + React.DOM.input({'key':'confirm', 'className':'confirmCheckbox', 'type':'checkbox', 'name':'confirm', 'ref':'confirm'}), + React.DOM.span({}, "I understand that Clipperz will not be able to recover a lost passphrase.") + ]), ]), - React.DOM.button({'key':'button', 'type':'submit', 'disabled':!this.shouldEnableChangePassphraseButton(), 'className':'button'}, "Change"), - React.DOM.div({ref: 'errorMessage', className: 'errorMessage', style: {visibility: errorVisibility} }, this.state.error) + React.DOM.button({'key':'button', 'type':'submit', 'disabled':!this.shouldEnableChangePassphraseButton(), 'className':'button'}, "Change passphrase"), ]), ]); }, diff --git a/frontend/delta/js/Clipperz/PM/UI/Components/Overlay.js b/frontend/delta/js/Clipperz/PM/UI/Components/Overlay.js index 1595da5..f9f6bcd 100644 --- a/frontend/delta/js/Clipperz/PM/UI/Components/Overlay.js +++ b/frontend/delta/js/Clipperz/PM/UI/Components/Overlay.js @@ -109,14 +109,14 @@ Clipperz.Base.extend(Clipperz.PM.UI.Components.Overlay, Object, { MochiKit.Base.bind(aFunctionToShowResult, this)(); this.setMessage(aMessage); - MochiKit.Async.callLater(delay, MochiKit.Base.bind(this.hide, this)) + return MochiKit.Async.callLater(delay, MochiKit.Base.bind(this.hide, this)) }, 'hide': function () { var element = this.element(); MochiKit.DOM.removeElementClass(element, 'ios-overlay-show'); MochiKit.DOM.addElementClass(element, 'ios-overlay-hide'); - MochiKit.Async.callLater(1, MochiKit.Style.hideElement, element); + return MochiKit.Async.callLater(1, MochiKit.Style.hideElement, element); }, 'hideSpinner': function () { diff --git a/frontend/delta/js/Clipperz/PM/UI/Components/Panels/ExtraFeaturesPanel.js b/frontend/delta/js/Clipperz/PM/UI/Components/Panels/ExtraFeaturesPanel.js index ad88c98..9e9bd7b 100644 --- a/frontend/delta/js/Clipperz/PM/UI/Components/Panels/ExtraFeaturesPanel.js +++ b/frontend/delta/js/Clipperz/PM/UI/Components/Panels/ExtraFeaturesPanel.js @@ -49,7 +49,9 @@ Clipperz.PM.UI.Components.Panels.ExtraFeaturesPanelClass = React.createClass({ 'subscription': false, 'data': false, }, - 'isFullyOpen': false + 'isFullyOpen': false, + 'extraFeatureComponentName': null, + 'extraFeatureContent': null }; }, @@ -68,13 +70,9 @@ Clipperz.PM.UI.Components.Panels.ExtraFeaturesPanelClass = React.createClass({ //========================================================================= -// showDevicePin: function () { -// this.showExtraFeatureContent(Clipperz.PM.UI.Components.ExtraFeatures.DevicePIN()); -// }, - showExtraFeatureComponent: function (aComponentName) { return MochiKit.Base.bind(function () { - this.showExtraFeatureContent(Clipperz.PM.UI.Components.ExtraFeatures[aComponentName]); + this.showExtraFeatureContent(Clipperz.PM.UI.Components.ExtraFeatures[aComponentName], aComponentName); }, this); }, @@ -85,20 +83,21 @@ Clipperz.PM.UI.Components.Panels.ExtraFeaturesPanelClass = React.createClass({ //------------------------------------------------------------------------- hideExtraFeatureContent: function () { - this.setState({'isFullyOpen':false}); + this.setState({ + 'isFullyOpen': false, + 'extraFeatureComponentName': null, + 'extraFeatureContent': null + }); }, - showExtraFeatureContent: function (aComponent) { + showExtraFeatureContent: function (aComponent, aComponentName) { this.setState({ 'isFullyOpen':true, + 'extraFeatureComponentName': aComponentName, 'extraFeatureContent': aComponent(this.extraFeaturesProps()) }); }, - toggleExtraFeatureContent: function () { - this.setState({'isFullyOpen':!this.state['isFullyOpen']}); - }, - //========================================================================= renderIndex: function () { @@ -119,10 +118,10 @@ Clipperz.PM.UI.Components.Panels.ExtraFeaturesPanelClass = React.createClass({ React.DOM.li({'key':'account', 'className':this.state['index']['account'] ? 'open' : 'closed'}, [ React.DOM.h1({'key':'accountH1', 'onClick':this.toggleIndexState('account')}, "Account"), React.DOM.ul({'key':'accountUL'}, [ - React.DOM.li({'key':'account_1', 'onClick':this.showExtraFeatureComponent('Passphrase')}, [ + React.DOM.li({'key':'account_1', 'onClick':this.showExtraFeatureComponent('Passphrase'), 'className':(this.state['extraFeatureComponentName'] == 'Passphrase') ? 'selected' : ''}, [ React.DOM.h2({'key':'account_1_h2'}, "Passphrase"), React.DOM.div({'key':'account_1_div'}, [ - React.DOM.p({'key':'account_1_p'}, "") + React.DOM.p({'key':'account_1_p'}, "Change your account passphrase.") ]) ]), React.DOM.li({'key':'account_2'}, [ @@ -143,10 +142,10 @@ Clipperz.PM.UI.Components.Panels.ExtraFeaturesPanelClass = React.createClass({ React.DOM.p({}, "") ]) ]), - React.DOM.li({'key':'account_5', 'onClick':this.showExtraFeatureComponent('DeleteAccount')}, [ + React.DOM.li({'key':'account_5', 'onClick':this.showExtraFeatureComponent('DeleteAccount'), 'className':(this.state['extraFeatureComponentName'] == 'DeleteAccount') ? 'selected' : ''}, [ React.DOM.h2({}, "Delete account"), React.DOM.div({}, [ - React.DOM.p({}, "") + React.DOM.p({}, "Delete your account for good.") ]) ]) ]) diff --git a/frontend/delta/js/Clipperz/PM/UI/MainController.js b/frontend/delta/js/Clipperz/PM/UI/MainController.js index f85a2ea..255a149 100644 --- a/frontend/delta/js/Clipperz/PM/UI/MainController.js +++ b/frontend/delta/js/Clipperz/PM/UI/MainController.js @@ -254,10 +254,10 @@ console.log("THE BROWSER IS OFFLINE"); //------------------------------------------------------------------------- - checkPassphrase: function( passphraseIn ) { + checkPassphrase: function (passphraseIn) { var deferredResult; - deferredResult = new Clipperz.Async.Deferred("MainController.deleteAccount_handler", {trace: false}); + deferredResult = new Clipperz.Async.Deferred("MainController.checkPassphrase", {trace: false}); deferredResult.addMethod(this.user(), 'getPassphrase'); deferredResult.addCallback(function (candidatePassphrase, realPassphrase) { return candidatePassphrase == realPassphrase; }, passphraseIn ); @@ -1241,7 +1241,7 @@ console.log("THE BROWSER IS OFFLINE"); var deferredResult; var getPassphraseDelegate; var user; - + getPassphraseDelegate = MochiKit.Base.partial(MochiKit.Async.succeed, newPassphrase); user = new Clipperz.PM.DataModel.User({'username':this.user().username(), 'getPassphraseFunction':getPassphraseDelegate}); @@ -1261,11 +1261,20 @@ console.log("THE BROWSER IS OFFLINE"); deleteAccount_handler: function() { var deferredResult; - + var doneMessageDelay = 2; + deferredResult = new Clipperz.Async.Deferred("MainController.deleteAccount_handler", {trace: false}); + deferredResult.addCallback(MochiKit.Base.method(this, 'ask', { + 'question': "Do you really want to permanently delete your account?", + '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')} + } + })), deferredResult.addMethod(this.overlay(), 'show', "deleting …", true); deferredResult.addMethod(this.user(), 'deleteAccount'); - deferredResult.addCallback(function() { window.location.href = '/'; }); + deferredResult.addMethod(this.overlay(), 'done', "deleted", doneMessageDelay); + deferredResult.addCallback(MochiKit.Async.callLater, doneMessageDelay, function() { window.location.href = '/'; }); deferredResult.callback(); diff --git a/frontend/delta/scss/core/layout.scss b/frontend/delta/scss/core/layout.scss index a648b8f..ce969d3 100644 --- a/frontend/delta/scss/core/layout.scss +++ b/frontend/delta/scss/core/layout.scss @@ -529,7 +529,7 @@ div.dialogBox { height: 100%; .mask { - z-index: 12; + z-index: 25; } div.dialog { @include flex(none); diff --git a/frontend/delta/scss/style/dialogBox.scss b/frontend/delta/scss/style/dialogBox.scss index 84f4cf7..140d3f4 100644 --- a/frontend/delta/scss/style/dialogBox.scss +++ b/frontend/delta/scss/style/dialogBox.scss @@ -25,13 +25,17 @@ div.dialog { @include box-shadow(0px, 2px, 5px, rgba(50, 50, 50, 0.75)); @include border-radius(8px); + max-width: 70%; background-color: white; padding: 30px; + box-shadow: 4px 4px 6px 5px rgba(0,0,0, 0.3); h3.message { font-size: 18pt; font-weight: bold; padding-bottom: 20px; + white-space: pre-wrap; + word-wrap: break-word; } div.answers { diff --git a/frontend/delta/scss/style/settingsPanel.scss b/frontend/delta/scss/style/settingsPanel.scss index ccbe5f3..a5126e9 100644 --- a/frontend/delta/scss/style/settingsPanel.scss +++ b/frontend/delta/scss/style/settingsPanel.scss @@ -49,8 +49,14 @@ refer to http://www.clipperz.com. // padding-right: 0px; border-bottom: 1px solid white; + & > h1 { + cursor: pointer; + font-size: 16pt; + padding: 10px; + } + & > ul { - padding-left: 10px; +// padding-left: 10px; } // &:last-child { @@ -68,8 +74,15 @@ refer to http://www.clipperz.com. li { & > ul > li { padding: 10px; + padding-left: 20px; padding-right: 0px; + cursor: pointer; + &.selected { + background-color: #333; +// color: black; + } + & > div { padding: 4px; } @@ -83,13 +96,14 @@ refer to http://www.clipperz.com. } - h1 { - cursor: pointer; - font-size: 16pt; - padding: 10px; - } +// h1 { +// cursor: pointer; +// font-size: 16pt; +// padding: 10px; +// } h2 { +// cursor: pointer; font-weight: 300; font-size: 14pt; } @@ -157,6 +171,17 @@ refer to http://www.clipperz.com. display: none; } + .extraFeature { + padding: 20px; + + h1 { + font-size: 20pt; + padding-bottom: 20px; + } + } + + +/* .changePassphraseForm { label { display: block; @@ -184,28 +209,79 @@ refer to http://www.clipperz.com. display: inline-block; } } +*/ form { - input.valid + .invalidMsg, input.empty + .invalidMsg, input:focus + .invalidMsg, input.invalid:focus + .invalidMsg { - visibility: hidden; + + label { + display: none; + } + + input { + $border-size: 0px; // 2px; + + display: block; + font-size: 18pt; + margin-bottom: 8px; + padding: (6px - $border-size) (10px - $border-size); + border: $border-size solid white; + width: 350px; + color: black; + + &.invalid { + border: $border-size solid $clipperz-orange; + color: gray; + } } - input:focus { - border: 2px solid $clipperz-orange; + p { + @include flexbox; + @include flex-direction(row); + + input { + width: 30px; + @include flex(auto); + } + + span { + @include flex(auto); + font-size: 12pt; + } } - - input.valid:focus { - border: 2px solid $clipperz-blue; - } - - input.invalid + .invalidMsg { - visibility: visible; - } - - .invalidMsg::before { - font-family: serif; - content: "\26A0 \0000a0"; + + button { + font-family: "clipperz-font"; +// min-height: 48px; +// min-width: 48px; + + color: white; +// font-size: 24pt; + font-size: 14pt; +// font-weight: 500; + border: 0px; + + margin-top: 20px; + padding: 6px 10px; + + border: 1px solid white; + background-color: $main-color; + @include transition(background-color font-weight, 0.2s, linear); + + &:hover { + }; + + &:disabled { + font-weight: 100; + background-color: #c0c0c0; + cursor: default; + + &:hover { + }; + } } +// input.valid:focus { +// border: 2px solid $clipperz-blue; +// } } }