From 38cc8a697f59b6e73b967177bf7b376f010bd4ab Mon Sep 17 00:00:00 2001 From: =?utf8?q?Bartosz=20Dziewo=C5=84ski?= Date: Fri, 2 Dec 2016 19:17:35 +0100 Subject: [PATCH] HTMLForm: Suppress HTML5 form validation for non-JS users when needed Our 'hide-if' fields are fundamentally incompatible with HTML5 form validation attributes. If you have a checkbox field A, and field B that is required, but hidden if A is unchecked - that's impossible to express with HTML5 form validation. The only thing you can do is remove the validation on B (or on the entire form). The field contents are still validated server-side, just like if the browser did not support HTML5 forms. The validation is also re-enabled in JavaScript, since we have extra support for 'hide-if' field that makes them work. Change-Id: Ia7ffa76965a7c14af9b6d2db007b6255498398d9 --- includes/htmlform/HTMLForm.php | 21 ++++++++++++++++++++ includes/htmlform/HTMLFormField.php | 15 ++++++++++++++ resources/src/mediawiki/htmlform/htmlform.js | 7 +++++++ 3 files changed, 43 insertions(+) diff --git a/includes/htmlform/HTMLForm.php b/includes/htmlform/HTMLForm.php index 5c5a9a7eee..e627cfdc69 100644 --- a/includes/htmlform/HTMLForm.php +++ b/includes/htmlform/HTMLForm.php @@ -1061,6 +1061,9 @@ class HTMLForm extends ContextSource { if ( $this->mName ) { $attribs['name'] = $this->mName; } + if ( $this->needsJSForHtml5FormValidation() ) { + $attribs['novalidate'] = true; + } return $attribs; } @@ -1876,4 +1879,22 @@ class HTMLForm extends ContextSource { protected function getMessage( $value ) { return Message::newFromSpecifier( $value )->setContext( $this ); } + + /** + * Whether this form, with its current fields, requires the user agent to have JavaScript enabled + * for the client-side HTML5 form validation to work correctly. If this function returns true, a + * 'novalidate' attribute will be added on the `
` element. It will be removed if the user + * agent has JavaScript support, in htmlform.js. + * + * @return boolean + * @since 1.29 + */ + public function needsJSForHtml5FormValidation() { + foreach ( $this->mFlatFields as $fieldname => $field ) { + if ( $field->needsJSForHtml5FormValidation() ) { + return true; + } + } + return false; + } } diff --git a/includes/htmlform/HTMLFormField.php b/includes/htmlform/HTMLFormField.php index 804bbff451..487d6f647b 100644 --- a/includes/htmlform/HTMLFormField.php +++ b/includes/htmlform/HTMLFormField.php @@ -1194,4 +1194,19 @@ abstract class HTMLFormField { public function skipLoadData( $request ) { return !empty( $this->mParams['nodata'] ); } + + /** + * Whether this field requires the user agent to have JavaScript enabled for the client-side HTML5 + * form validation to work correctly. + * + * @return boolean + * @since 1.29 + */ + public function needsJSForHtml5FormValidation() { + if ( $this->mHideIf ) { + // This is probably more restrictive than it needs to be, but better safe than sorry + return true; + } + return false; + } } diff --git a/resources/src/mediawiki/htmlform/htmlform.js b/resources/src/mediawiki/htmlform/htmlform.js index 19f8f3ece5..bc835b5924 100644 --- a/resources/src/mediawiki/htmlform/htmlform.js +++ b/resources/src/mediawiki/htmlform/htmlform.js @@ -4,4 +4,11 @@ mw.hook( 'htmlform.enhance' ).fire( $( document ) ); } ); + mw.hook( 'htmlform.enhance' ).add( function ( $root ) { + // Turn HTML5 form validation back on, in cases where it was disabled server-side (see + // HTMLForm::needsJSForHtml5FormValidation()) because we need extra logic implemented in JS to + // validate correctly. Currently, this is only used for forms containing fields with 'hide-if'. + $root.find( '.mw-htmlform' ).removeAttr( 'novalidate' ); + } ); + }( mediaWiki, jQuery ) ); -- 2.20.1