From b57b19f60c64aabb37cbbad70a9e9c8cfcf25c85 Mon Sep 17 00:00:00 2001 From: Luka Skukan Date: Wed, 25 Jan 2017 19:55:11 +0100 Subject: [PATCH 1/3] Prevent containsWord on non-strings --- src/utils.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/utils.js b/src/utils.js index fb7d543..8f2954f 100644 --- a/src/utils.js +++ b/src/utils.js @@ -13,6 +13,10 @@ class Utils { } containsWord(testWord, words) { + if (typeof testWord !== 'string') { + return false; + } + testWord = testWord.toLowerCase(); for (let i = 0; i < words.length; i++) { From 071c40ce1a919f747dc128039d86a8c680bc7560 Mon Sep 17 00:00:00 2001 From: Luka Skukan Date: Thu, 26 Jan 2017 12:41:47 +0100 Subject: [PATCH 2/3] Refactor form binding and add IE fallback --- src/components/ChangePasswordForm.js | 2 +- src/components/LoginForm.js | 2 +- src/components/RegistrationForm.js | 2 +- src/components/ResetPasswordForm.js | 2 +- src/components/UserProfileForm.js | 2 +- src/utils.js | 23 +++++++++++++++++++++++ 6 files changed, 28 insertions(+), 5 deletions(-) diff --git a/src/components/ChangePasswordForm.js b/src/components/ChangePasswordForm.js index 8cbd301..fa2c22e 100644 --- a/src/components/ChangePasswordForm.js +++ b/src/components/ChangePasswordForm.js @@ -142,7 +142,7 @@ export default class ChangePasswordForm extends React.Component { } }; - if (typeof element.type === 'function' && utils.containsWord(element.type.name, ['input', 'field', 'text'])) { + if (utils.isInputLikeComponent(element)) { if (element.props && element.props.name) { tryMapFormField(element.props.name); } diff --git a/src/components/LoginForm.js b/src/components/LoginForm.js index b66ea3d..788dbe2 100644 --- a/src/components/LoginForm.js +++ b/src/components/LoginForm.js @@ -244,7 +244,7 @@ export default class LoginForm extends React.Component { } }; - if (typeof element.type === 'function' && utils.containsWord(element.type.name, ['input', 'field', 'text'])) { + if (utils.isInputLikeComponent(element)) { if (element.props && element.props.name) { tryMapFormField(element.props.name); } diff --git a/src/components/RegistrationForm.js b/src/components/RegistrationForm.js index 70a78d8..658fd4e 100644 --- a/src/components/RegistrationForm.js +++ b/src/components/RegistrationForm.js @@ -325,7 +325,7 @@ export default class RegistrationForm extends React.Component { } }; - if (typeof element.type === 'function' && utils.containsWord(element.type.name, ['input', 'field', 'text'])) { + if (utils.isInputLikeComponent(element)) { if (element.props && element.props.name) { tryMapFormField(element.props.name); } diff --git a/src/components/ResetPasswordForm.js b/src/components/ResetPasswordForm.js index dc98c6d..c8a82a2 100644 --- a/src/components/ResetPasswordForm.js +++ b/src/components/ResetPasswordForm.js @@ -106,7 +106,7 @@ export default class ResetPasswordForm extends React.Component { } }; - if (typeof element.type === 'function' && utils.containsWord(element.type.name, ['input', 'field', 'text'])) { + if (utils.isInputLikeComponent(element)) { if (element.props && element.props.name) { tryMapFormField(element.props.name); } diff --git a/src/components/UserProfileForm.js b/src/components/UserProfileForm.js index 4cb2822..c459712 100644 --- a/src/components/UserProfileForm.js +++ b/src/components/UserProfileForm.js @@ -168,7 +168,7 @@ export default class UserProfileForm extends React.Component { utils.getFieldValue(this.state.defaultFields, element.props.name) : undefined; - if (typeof element.type === 'function' && utils.containsWord(element.type.name, ['input', 'field', 'text'])) { + if (utils.isInputLikeComponent(element)) { if (element.props && element.props.name) { tryMapField(element.props.name, defaultValue); } diff --git a/src/utils.js b/src/utils.js index 8f2954f..4e91907 100644 --- a/src/utils.js +++ b/src/utils.js @@ -12,6 +12,24 @@ class Utils { s4() + '-' + s4() + s4() + s4(); } + functionName(f) { + if (typeof f !== 'function') { + return ''; + } + + if (f.name) { + return f.name; + } + + const parts = f.toString().match(/^function\s*([^\s(]+)/); + + if (parts) { + return parts[1]; + } + + return ''; + } + containsWord(testWord, words) { if (typeof testWord !== 'string') { return false; @@ -29,6 +47,11 @@ class Utils { return false; } + isInputLikeComponent(element, inputNames = ['input', 'field', 'text']) { + return typeof element.type === 'function' + && this.containsWord(this.functionName(element.type), inputNames); + } + takeProp(source, ...fields) { for (let i = 0; i < fields.length; i++) { let fieldName = fields[i]; From 1ab627a9e8d4dc212aba219bbbeff591cedbcef5 Mon Sep 17 00:00:00 2001 From: Luka Skukan Date: Thu, 26 Jan 2017 13:06:05 +0100 Subject: [PATCH 3/3] DRY out field mapping logic --- src/components/ChangePasswordForm.js | 10 +--------- src/components/LoginForm.js | 10 +--------- src/components/RegistrationForm.js | 10 +--------- src/components/ResetPasswordForm.js | 10 +--------- src/components/UserProfileForm.js | 12 +----------- src/utils.js | 12 ++++++++++++ 6 files changed, 17 insertions(+), 47 deletions(-) diff --git a/src/components/ChangePasswordForm.js b/src/components/ChangePasswordForm.js index fa2c22e..0e8aa83 100644 --- a/src/components/ChangePasswordForm.js +++ b/src/components/ChangePasswordForm.js @@ -142,15 +142,7 @@ export default class ChangePasswordForm extends React.Component { } }; - if (utils.isInputLikeComponent(element)) { - if (element.props && element.props.name) { - tryMapFormField(element.props.name); - } - } else if (element.type === 'input' || element.type === 'textarea') { - if (element.props.type !== 'submit') { - tryMapFormField(element.props.name); - } - } + utils.mapFormField(element, tryMapFormField); } _spIfHandler(action, element) { diff --git a/src/components/LoginForm.js b/src/components/LoginForm.js index 788dbe2..6f27fbf 100644 --- a/src/components/LoginForm.js +++ b/src/components/LoginForm.js @@ -244,15 +244,7 @@ export default class LoginForm extends React.Component { } }; - if (utils.isInputLikeComponent(element)) { - if (element.props && element.props.name) { - tryMapFormField(element.props.name); - } - } else if (['input', 'textarea'].indexOf(element.type) > -1) { - if (element.props.type !== 'submit') { - tryMapFormField(element.props.name); - } - } + utils.mapFormField(element, tryMapFormField); } _spIfHandler(action, element) { diff --git a/src/components/RegistrationForm.js b/src/components/RegistrationForm.js index 658fd4e..a18a28d 100644 --- a/src/components/RegistrationForm.js +++ b/src/components/RegistrationForm.js @@ -325,15 +325,7 @@ export default class RegistrationForm extends React.Component { } }; - if (utils.isInputLikeComponent(element)) { - if (element.props && element.props.name) { - tryMapFormField(element.props.name); - } - } else if (['input', 'textarea'].indexOf(element.type) > -1) { - if (element.props.type !== 'submit') { - tryMapFormField(element.props.name); - } - } + utils.mapFormField(element, tryMapFormField); } _spIfHandler(action, element) { diff --git a/src/components/ResetPasswordForm.js b/src/components/ResetPasswordForm.js index c8a82a2..ab4aa61 100644 --- a/src/components/ResetPasswordForm.js +++ b/src/components/ResetPasswordForm.js @@ -106,15 +106,7 @@ export default class ResetPasswordForm extends React.Component { } }; - if (utils.isInputLikeComponent(element)) { - if (element.props && element.props.name) { - tryMapFormField(element.props.name); - } - } else if (['input', 'textarea'].indexOf(element.type) > -1) { - if (element.props.type !== 'submit') { - tryMapFormField(element.props.name); - } - } + utils.mapFormField(element, tryMapFormField); } _spIfHandler(action, element) { diff --git a/src/components/UserProfileForm.js b/src/components/UserProfileForm.js index c459712..1ad1f98 100644 --- a/src/components/UserProfileForm.js +++ b/src/components/UserProfileForm.js @@ -168,17 +168,7 @@ export default class UserProfileForm extends React.Component { utils.getFieldValue(this.state.defaultFields, element.props.name) : undefined; - if (utils.isInputLikeComponent(element)) { - if (element.props && element.props.name) { - tryMapField(element.props.name, defaultValue); - } - } else if (element.type === 'input') { - if (element.props.type === 'submit') { - return; - } - - tryMapField(element.props.name, defaultValue); - } + utils.mapFormField(element, tryMapField, defaultValue); } _spIfHandler(action, element) { diff --git a/src/utils.js b/src/utils.js index 4e91907..c130beb 100644 --- a/src/utils.js +++ b/src/utils.js @@ -143,6 +143,18 @@ class Utils { return React.cloneElement(newElement, newOptions, newChildren); } + mapFormField(element, mappingFn, defaultValue) { + if (this.isInputLikeComponent(element)) { + if (element.props && element.props.name) { + mappingFn(element.props.name, defaultValue); + } + } else if (['input', 'textarea'].indexOf(element.type) > -1) { + if (element.props.type !== 'submit') { + mappingFn(element.props.name, defaultValue); + } + } + } + getFormFieldMap(root, handler) { var fields = {};