From b4391ac87ad60249e8fb3431ac187f98df3059f3 Mon Sep 17 00:00:00 2001 From: Luka Skukan Date: Tue, 14 Feb 2017 13:42:35 +0100 Subject: [PATCH 1/5] Add reset functionality to all forms --- src/components/LoginForm.js | 18 +++++++++++++++++- src/components/RegistrationForm.js | 19 ++++++++++++++++++- src/components/ResetPasswordForm.js | 14 +++++++++++++- src/components/UserProfileForm.js | 12 +++++++++++- 4 files changed, 59 insertions(+), 4 deletions(-) diff --git a/src/components/LoginForm.js b/src/components/LoginForm.js index 1627865..da0f602 100644 --- a/src/components/LoginForm.js +++ b/src/components/LoginForm.js @@ -155,6 +155,16 @@ export default class LoginForm extends React.Component { isFormProcessing: false }; + reset() { + this.setState({ + fields: { + username: '', + password: '', + }, + errorMessage: null, + }); + } + onFormSubmit(e) { e.preventDefault(); e.persist(); @@ -289,7 +299,13 @@ export default class LoginForm extends React.Component { render() { if (this.props.children) { - let selectedProps = utils.excludeProps(['redirectTo', 'hideSocial', 'onSubmit', 'onSubmitError', 'onSubmitSuccess', 'children'], this.props); + let selectedProps = utils.excludeProps( + ['redirectTo', 'hideSocial', 'onSubmit', 'onSubmitError', 'onSubmitSuccess', 'children'], + { + ...this.props, + reset: this.reset.bind(this), + } + ); return (
diff --git a/src/components/RegistrationForm.js b/src/components/RegistrationForm.js index 524831b..deff1c1 100644 --- a/src/components/RegistrationForm.js +++ b/src/components/RegistrationForm.js @@ -187,6 +187,18 @@ export default class RegistrationForm extends React.Component { isAccountEnabled: false }; + reset() { + this.setState({ + fields: { + givenName: '', + surname: '', + email: '', + password: '' + }, + errorMessage: null, + }); + } + onFormSubmit(e) { e.preventDefault(); e.persist(); @@ -376,7 +388,12 @@ export default class RegistrationForm extends React.Component { render() { if (this.props.children) { - var selectedProps = utils.excludeProps(['redirectTo', 'hideSocial', 'onSubmit', 'onSubmitError', 'onSubmitSuccess', 'children'], this.props); + var selectedProps = utils.excludeProps( + ['redirectTo', 'hideSocial', 'onSubmit', 'onSubmitError', 'onSubmitSuccess', 'children'], + { + ...this.props, + reset: this.reset.bind(this), + }); return ( diff --git a/src/components/ResetPasswordForm.js b/src/components/ResetPasswordForm.js index dc98c6d..0dff64a 100644 --- a/src/components/ResetPasswordForm.js +++ b/src/components/ResetPasswordForm.js @@ -53,6 +53,15 @@ export default class ResetPasswordForm extends React.Component { isFormSent: false }; + reset() { + this.setState({ + fields: { + email: '', + }, + errorMessage: null, + }); + } + onFormSubmit(e) { e.preventDefault(); e.persist(); @@ -150,7 +159,10 @@ export default class ResetPasswordForm extends React.Component { render() { if (this.props.children) { - var selectedProps = utils.excludeProps(['onSubmit', 'children'], this.props); + var selectedProps = utils.excludeProps(['onSubmit', 'children'], { + ...this.props, + reset: this.reset.bind(this) + }); return ( diff --git a/src/components/UserProfileForm.js b/src/components/UserProfileForm.js index 4cb2822..70f2da2 100644 --- a/src/components/UserProfileForm.js +++ b/src/components/UserProfileForm.js @@ -91,6 +91,13 @@ export default class UserProfileForm extends React.Component { isFormSuccessful: false }; + reset() { + this.setState({ + fields: {}, + errorMessage: null, + }); + } + _updateSessionData = (data, callback) => { var sessionStore = context.sessionStore; @@ -214,7 +221,10 @@ export default class UserProfileForm extends React.Component { render() { if (this.props.children) { - let selectedProps = utils.excludeProps(['onSubmit', 'children'], this.props); + let selectedProps = utils.excludeProps(['onSubmit', 'children'], { + ...this.props, + reset: this.reset.bind(this), + }); return ( From 2617a505e4e6061027c1d0f51b4924348374d9b2 Mon Sep 17 00:00:00 2001 From: Luka Skukan Date: Tue, 14 Feb 2017 14:45:09 +0100 Subject: [PATCH 2/5] Change implementation to use custom attribute --- src/components/LoginForm.js | 21 +++++++++++++-------- src/components/RegistrationForm.js | 20 +++++++++++++------- src/components/ResetPasswordForm.js | 18 +++++++++++++----- src/components/UserProfileForm.js | 18 +++++++++++++----- src/utils.js | 13 ++++++++++++- 5 files changed, 64 insertions(+), 26 deletions(-) diff --git a/src/components/LoginForm.js b/src/components/LoginForm.js index da0f602..01ed928 100644 --- a/src/components/LoginForm.js +++ b/src/components/LoginForm.js @@ -297,19 +297,24 @@ export default class LoginForm extends React.Component { return result; } + _spResetErrorsHandler(element) { + return React.createElement( + element.type, + { + ...utils.excludeProps(['spResetErrors'], element.props), + onClick: this.reset.bind(this) + }, + element.props.children + ); + } + render() { if (this.props.children) { - let selectedProps = utils.excludeProps( - ['redirectTo', 'hideSocial', 'onSubmit', 'onSubmitError', 'onSubmitSuccess', 'children'], - { - ...this.props, - reset: this.reset.bind(this), - } - ); + let selectedProps = utils.excludeProps(['redirectTo', 'hideSocial', 'onSubmit', 'onSubmitError', 'onSubmitSuccess', 'children'], this.props); return ( - {utils.makeForm(this, this._mapFormFieldHandler.bind(this), this._spIfHandler.bind(this), this._spBindHandler.bind(this))} + {utils.makeForm(this, this._mapFormFieldHandler.bind(this), this._spIfHandler.bind(this), this._spBindHandler.bind(this), this._spResetErrorsHandler.bind(this))} ); } else { diff --git a/src/components/RegistrationForm.js b/src/components/RegistrationForm.js index deff1c1..07d2022 100644 --- a/src/components/RegistrationForm.js +++ b/src/components/RegistrationForm.js @@ -386,18 +386,24 @@ export default class RegistrationForm extends React.Component { return result; } + _spResetErrorsHandler(element) { + return React.createElement( + element.type, + { + ...utils.excludeProps(['spResetErrors'], element.props), + onClick: this.reset.bind(this) + }, + element.props.children + ); + } + render() { if (this.props.children) { - var selectedProps = utils.excludeProps( - ['redirectTo', 'hideSocial', 'onSubmit', 'onSubmitError', 'onSubmitSuccess', 'children'], - { - ...this.props, - reset: this.reset.bind(this), - }); + var selectedProps = utils.excludeProps(['redirectTo', 'hideSocial', 'onSubmit', 'onSubmitError', 'onSubmitSuccess', 'children'], this.props); return (
- {utils.makeForm(this, this._mapFormFieldHandler.bind(this), this._spIfHandler.bind(this), this._spBindHandler.bind(this))} + {utils.makeForm(this, this._mapFormFieldHandler.bind(this), this._spIfHandler.bind(this), this._spBindHandler.bind(this), this._spResetErrorsHandler.bind(this))}
); } else { diff --git a/src/components/ResetPasswordForm.js b/src/components/ResetPasswordForm.js index 0dff64a..551abf0 100644 --- a/src/components/ResetPasswordForm.js +++ b/src/components/ResetPasswordForm.js @@ -157,16 +157,24 @@ export default class ResetPasswordForm extends React.Component { return result; } + _spResetErrorsHandler(element) { + return React.createElement( + element.type, + { + ...utils.excludeProps(['spResetErrors'], element.props), + onClick: this.reset.bind(this) + }, + element.props.children + ); + } + render() { if (this.props.children) { - var selectedProps = utils.excludeProps(['onSubmit', 'children'], { - ...this.props, - reset: this.reset.bind(this) - }); + var selectedProps = utils.excludeProps(['onSubmit', 'children'], this.props); return (
- {utils.makeForm(this, this._mapFormFieldHandler.bind(this), this._spIfHandler.bind(this), this._spBindHandler.bind(this))} + {utils.makeForm(this, this._mapFormFieldHandler.bind(this), this._spIfHandler.bind(this), this._spBindHandler.bind(this), this._spResetErrorsHandler.bind(this))}
); } else { diff --git a/src/components/UserProfileForm.js b/src/components/UserProfileForm.js index 70f2da2..eca9f54 100644 --- a/src/components/UserProfileForm.js +++ b/src/components/UserProfileForm.js @@ -219,16 +219,24 @@ export default class UserProfileForm extends React.Component { return result; } + _spResetErrorsHandler(element) { + return React.createElement( + element.type, + { + ...utils.excludeProps(['spResetErrors'], element.props), + onClick: this.reset.bind(this) + }, + element.props.children + ); + } + render() { if (this.props.children) { - let selectedProps = utils.excludeProps(['onSubmit', 'children'], { - ...this.props, - reset: this.reset.bind(this), - }); + let selectedProps = utils.excludeProps(['onSubmit', 'children'], this.props); return (
- {utils.makeForm(this, this._mapFormFieldHandler.bind(this), this._spIfHandler.bind(this), this._spBindHandler.bind(this))} + {utils.makeForm(this, this._mapFormFieldHandler.bind(this), this._spIfHandler.bind(this), this._spBindHandler.bind(this), this._spResetErrorsHandler.bind(this))}
); } else { diff --git a/src/utils.js b/src/utils.js index db85aab..df1e834 100644 --- a/src/utils.js +++ b/src/utils.js @@ -215,7 +215,7 @@ class Utils { } } - makeForm(source, fieldMapFn, spIfFn, spBindFn) { + makeForm(source, fieldMapFn, spIfFn, spBindFn, spResetErrorsFn) { var root = React.cloneElement(
, {}, source.props.children); var fieldMap = this.getFormFieldMap(root, fieldMapFn); @@ -259,6 +259,17 @@ class Utils { element = newElement; } } + + if (spResetErrorsFn) { + var spResetErrors = this.takeProp(element.props, 'spResetErrors', 'data-spResetErrors'); + + if (spResetErrors) { + var newElement = spResetErrorsFn(element); + if (newElement !== false || newElement) { + element = newElement; + } + } + } } return element; }; From 300c2fb5aa508b44a46e667b2d5a95f17497c359 Mon Sep 17 00:00:00 2001 From: Luka Skukan Date: Tue, 14 Feb 2017 14:47:52 +0100 Subject: [PATCH 3/5] Add mention of spResetErrors to api.md --- docs/api.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/api.md b/docs/api.md index a93a01d..a7512bf 100644 --- a/docs/api.md +++ b/docs/api.md @@ -259,6 +259,7 @@ Customize the form by providing your own markup.

+

``` @@ -349,7 +350,7 @@ Specify `hideSocial` to hide the ability to register with a social provider. ``` -Customize the form by providing your own markup. +Customize the form by providing your own markup. By default, the registration form will render these four fields, and they will be required by the user: `givenName`, `surname`, `email`, and `password`. Express.js users who want to make `givenName` and/or `surname` optional, or to add new required fields (like `username`), can refer to [Stormpath Express Library Guide](https://docs.stormpath.com/nodejs/express/latest/registration.html). @@ -381,6 +382,7 @@ By default, the registration form will render these four fields, and they will b

+

@@ -492,6 +494,7 @@ Customize the form by providing your own markup.

+

@@ -556,6 +559,7 @@ Customize the form by providing your own markup.

+

@@ -669,6 +673,7 @@ Customize the form by providing your own markup.

+

``` From 75ac0565880d8e0f383322a34afcf21ab86d0625 Mon Sep 17 00:00:00 2001 From: Luka Skukan Date: Tue, 14 Feb 2017 15:16:46 +0100 Subject: [PATCH 4/5] DRY out the code --- src/components/LoginForm.js | 16 +++------------- src/components/RegistrationForm.js | 15 ++------------- src/components/ResetPasswordForm.js | 15 ++------------- src/components/UserProfileForm.js | 15 ++------------- src/utils.js | 22 ++++++++++++++++++---- 5 files changed, 27 insertions(+), 56 deletions(-) diff --git a/src/components/LoginForm.js b/src/components/LoginForm.js index 01ed928..43bb17b 100644 --- a/src/components/LoginForm.js +++ b/src/components/LoginForm.js @@ -132,6 +132,7 @@ class DefaultLoginForm extends React.Component {
{ fieldMarkup ? fieldMarkup : } +
Reset
@@ -155,7 +156,7 @@ export default class LoginForm extends React.Component { isFormProcessing: false }; - reset() { + _reset() { this.setState({ fields: { username: '', @@ -297,24 +298,13 @@ export default class LoginForm extends React.Component { return result; } - _spResetErrorsHandler(element) { - return React.createElement( - element.type, - { - ...utils.excludeProps(['spResetErrors'], element.props), - onClick: this.reset.bind(this) - }, - element.props.children - ); - } - render() { if (this.props.children) { let selectedProps = utils.excludeProps(['redirectTo', 'hideSocial', 'onSubmit', 'onSubmitError', 'onSubmitSuccess', 'children'], this.props); return (
- {utils.makeForm(this, this._mapFormFieldHandler.bind(this), this._spIfHandler.bind(this), this._spBindHandler.bind(this), this._spResetErrorsHandler.bind(this))} + {utils.makeForm(this, this._mapFormFieldHandler.bind(this), this._spIfHandler.bind(this), this._spBindHandler.bind(this), this._reset.bind(this))}
); } else { diff --git a/src/components/RegistrationForm.js b/src/components/RegistrationForm.js index 07d2022..345d3aa 100644 --- a/src/components/RegistrationForm.js +++ b/src/components/RegistrationForm.js @@ -187,7 +187,7 @@ export default class RegistrationForm extends React.Component { isAccountEnabled: false }; - reset() { + _reset() { this.setState({ fields: { givenName: '', @@ -386,24 +386,13 @@ export default class RegistrationForm extends React.Component { return result; } - _spResetErrorsHandler(element) { - return React.createElement( - element.type, - { - ...utils.excludeProps(['spResetErrors'], element.props), - onClick: this.reset.bind(this) - }, - element.props.children - ); - } - render() { if (this.props.children) { var selectedProps = utils.excludeProps(['redirectTo', 'hideSocial', 'onSubmit', 'onSubmitError', 'onSubmitSuccess', 'children'], this.props); return (
- {utils.makeForm(this, this._mapFormFieldHandler.bind(this), this._spIfHandler.bind(this), this._spBindHandler.bind(this), this._spResetErrorsHandler.bind(this))} + {utils.makeForm(this, this._mapFormFieldHandler.bind(this), this._spIfHandler.bind(this), this._spBindHandler.bind(this), this._reset.bind(this))}
); } else { diff --git a/src/components/ResetPasswordForm.js b/src/components/ResetPasswordForm.js index 551abf0..781a678 100644 --- a/src/components/ResetPasswordForm.js +++ b/src/components/ResetPasswordForm.js @@ -53,7 +53,7 @@ export default class ResetPasswordForm extends React.Component { isFormSent: false }; - reset() { + _reset() { this.setState({ fields: { email: '', @@ -157,24 +157,13 @@ export default class ResetPasswordForm extends React.Component { return result; } - _spResetErrorsHandler(element) { - return React.createElement( - element.type, - { - ...utils.excludeProps(['spResetErrors'], element.props), - onClick: this.reset.bind(this) - }, - element.props.children - ); - } - render() { if (this.props.children) { var selectedProps = utils.excludeProps(['onSubmit', 'children'], this.props); return (
- {utils.makeForm(this, this._mapFormFieldHandler.bind(this), this._spIfHandler.bind(this), this._spBindHandler.bind(this), this._spResetErrorsHandler.bind(this))} + {utils.makeForm(this, this._mapFormFieldHandler.bind(this), this._spIfHandler.bind(this), this._spBindHandler.bind(this), this._reset.bind(this))}
); } else { diff --git a/src/components/UserProfileForm.js b/src/components/UserProfileForm.js index eca9f54..9aa31aa 100644 --- a/src/components/UserProfileForm.js +++ b/src/components/UserProfileForm.js @@ -91,7 +91,7 @@ export default class UserProfileForm extends React.Component { isFormSuccessful: false }; - reset() { + _reset() { this.setState({ fields: {}, errorMessage: null, @@ -219,24 +219,13 @@ export default class UserProfileForm extends React.Component { return result; } - _spResetErrorsHandler(element) { - return React.createElement( - element.type, - { - ...utils.excludeProps(['spResetErrors'], element.props), - onClick: this.reset.bind(this) - }, - element.props.children - ); - } - render() { if (this.props.children) { let selectedProps = utils.excludeProps(['onSubmit', 'children'], this.props); return (
- {utils.makeForm(this, this._mapFormFieldHandler.bind(this), this._spIfHandler.bind(this), this._spBindHandler.bind(this), this._spResetErrorsHandler.bind(this))} + {utils.makeForm(this, this._mapFormFieldHandler.bind(this), this._spIfHandler.bind(this), this._spBindHandler.bind(this), this._reset.bind(this))}
); } else { diff --git a/src/utils.js b/src/utils.js index df1e834..0852ec2 100644 --- a/src/utils.js +++ b/src/utils.js @@ -264,10 +264,24 @@ class Utils { var spResetErrors = this.takeProp(element.props, 'spResetErrors', 'data-spResetErrors'); if (spResetErrors) { - var newElement = spResetErrorsFn(element); - if (newElement !== false || newElement) { - element = newElement; - } + const oldHandler = element.props.onClick + ? element.props.onClick + : null; + + element = React.createElement( + element.type, + { + ...this.excludeProps(['spResetErrors', 'data-spResetErrors'], element.props), + onClick(...args) { + spResetErrorsFn(...args); + + if (oldHandler) { + oldHandler(...args); + } + } + }, + element.props.children + ); } } } From 63a8a140e7947d575e7c4da552fe03612495bf2c Mon Sep 17 00:00:00 2001 From: Luka Skukan Date: Tue, 14 Feb 2017 15:17:06 +0100 Subject: [PATCH 5/5] Remove debug component --- src/components/LoginForm.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/LoginForm.js b/src/components/LoginForm.js index 43bb17b..04cdf2d 100644 --- a/src/components/LoginForm.js +++ b/src/components/LoginForm.js @@ -132,7 +132,6 @@ class DefaultLoginForm extends React.Component {
{ fieldMarkup ? fieldMarkup : } -
Reset