Merge htmlform.checker.js into special.userlogin.signup.js module
Bug: T253362 Change-Id: I749c1955b765ce4ca1b9a191d1a051933a21f16a
This commit is contained in:
parent
2ee29c7e37
commit
743edb1be0
5 changed files with 201 additions and 204 deletions
|
|
@ -32,7 +32,6 @@
|
|||
"mw.cookie",
|
||||
"mw.experiments",
|
||||
"mw.viewport",
|
||||
"mw.htmlform.*",
|
||||
"mw.visibleTimeout"
|
||||
]
|
||||
},
|
||||
|
|
|
|||
|
|
@ -759,15 +759,6 @@ return [
|
|||
],
|
||||
'targets' => [ 'desktop', 'mobile' ],
|
||||
],
|
||||
'mediawiki.htmlform.checker' => [
|
||||
'scripts' => [
|
||||
'resources/src/mediawiki.htmlform.checker.js',
|
||||
],
|
||||
'dependencies' => [
|
||||
'mediawiki.util',
|
||||
],
|
||||
'targets' => [ 'desktop', 'mobile' ],
|
||||
],
|
||||
'mediawiki.htmlform.ooui' => [
|
||||
'scripts' => [
|
||||
'resources/src/mediawiki.htmlform.ooui/Element.js',
|
||||
|
|
@ -2144,6 +2135,7 @@ return [
|
|||
'remoteBasePath' => "$wgResourceBasePath/resources/src/mediawiki.special.createaccount",
|
||||
'packageFiles' => [
|
||||
'signup.js',
|
||||
'HtmlformChecker.js'
|
||||
],
|
||||
'messages' => [
|
||||
'createacct-emailrequired',
|
||||
|
|
@ -2154,7 +2146,7 @@ return [
|
|||
'dependencies' => [
|
||||
'mediawiki.api',
|
||||
'mediawiki.jqueryMsg',
|
||||
'mediawiki.htmlform.checker',
|
||||
'mediawiki.util',
|
||||
],
|
||||
],
|
||||
'mediawiki.special.userlogin.signup.styles' => [
|
||||
|
|
|
|||
|
|
@ -1,191 +0,0 @@
|
|||
( function () {
|
||||
|
||||
// FIXME: mw.htmlform.Element also sets this to empty object
|
||||
mw.htmlform = {};
|
||||
|
||||
/**
|
||||
* @class mw.htmlform.Checker
|
||||
*/
|
||||
|
||||
/**
|
||||
* A helper class to add validation to non-OOUI HtmlForm fields.
|
||||
*
|
||||
* @constructor
|
||||
* @param {jQuery} $element Form field generated by HTMLForm
|
||||
* @param {Function} validator Validation callback
|
||||
* @param {string} validator.value Value of the form field to be validated
|
||||
* @param {jQuery.Promise} validator.return The promise should be resolved
|
||||
* with an object with two properties: Boolean 'valid' to indicate success
|
||||
* or failure of validation, and an array 'messages' to be passed to
|
||||
* setErrors() on failure.
|
||||
*/
|
||||
mw.htmlform.Checker = function ( $element, validator ) {
|
||||
this.validator = validator;
|
||||
this.$element = $element;
|
||||
|
||||
this.$errorBox = $element.next( '.errorbox' );
|
||||
if ( !this.$errorBox.length ) {
|
||||
this.$errorBox = $( '<div>' );
|
||||
this.$errorBox.hide();
|
||||
$element.after( this.$errorBox );
|
||||
}
|
||||
|
||||
this.currentValue = this.$element.val();
|
||||
};
|
||||
|
||||
/**
|
||||
* Attach validation events to the form element
|
||||
*
|
||||
* @param {jQuery} [$extraElements] Additional elements to listen for change
|
||||
* events on.
|
||||
* @return {mw.htmlform.Checker}
|
||||
* @chainable
|
||||
*/
|
||||
mw.htmlform.Checker.prototype.attach = function ( $extraElements ) {
|
||||
var $e,
|
||||
// We need to hook to all of these events to be sure we are
|
||||
// notified of all changes to the value of an <input type=text>
|
||||
// field.
|
||||
events = 'keyup keydown change mouseup cut paste focus blur';
|
||||
|
||||
$e = this.$element;
|
||||
if ( $extraElements ) {
|
||||
$e = $e.add( $extraElements );
|
||||
}
|
||||
$e.on( events, mw.util.debounce( 1000, this.validate.bind( this ) ) );
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Validate the form element
|
||||
*
|
||||
* @return {jQuery.Promise}
|
||||
*/
|
||||
mw.htmlform.Checker.prototype.validate = function () {
|
||||
var currentRequestInternal,
|
||||
that = this,
|
||||
value = this.$element.val();
|
||||
|
||||
// Abort any pending requests.
|
||||
if ( this.currentRequest && this.currentRequest.abort ) {
|
||||
this.currentRequest.abort();
|
||||
}
|
||||
|
||||
if ( value === '' ) {
|
||||
this.currentValue = value;
|
||||
this.setErrors( true, [] );
|
||||
return;
|
||||
}
|
||||
|
||||
this.currentRequest = currentRequestInternal = this.validator( value )
|
||||
.done( function ( info ) {
|
||||
var forceReplacement = value !== that.currentValue;
|
||||
|
||||
// Another request was fired in the meantime, the result we got here is no longer current.
|
||||
// This shouldn't happen as we abort pending requests, but you never know.
|
||||
if ( that.currentRequest !== currentRequestInternal ) {
|
||||
return;
|
||||
}
|
||||
// If we're here, then the current request has finished, avoid calling .abort() needlessly.
|
||||
that.currentRequest = undefined;
|
||||
|
||||
that.currentValue = value;
|
||||
|
||||
that.setErrors( info.valid, info.messages, forceReplacement );
|
||||
} ).fail( function () {
|
||||
that.currentValue = null;
|
||||
that.setErrors( true, [] );
|
||||
} );
|
||||
|
||||
return currentRequestInternal;
|
||||
};
|
||||
|
||||
/**
|
||||
* Display errors associated with the form element
|
||||
*
|
||||
* @param {boolean} valid Whether the input is still valid regardless of the messages
|
||||
* @param {Array} errors Errorbox messages. Each errorbox message will be appended to a
|
||||
* `<div>` or `<li>`, as with jQuery.append().
|
||||
* @param {boolean} [forceReplacement] Set true to force a visual replacement even
|
||||
* if the errors are the same. Ignored if errors are empty.
|
||||
* @return {mw.htmlform.Checker}
|
||||
* @chainable
|
||||
*/
|
||||
mw.htmlform.Checker.prototype.setErrors = function ( valid, errors, forceReplacement ) {
|
||||
var $oldErrorBox, showFunc, $text, replace,
|
||||
$errorBox = this.$errorBox;
|
||||
|
||||
if ( errors.length === 0 ) {
|
||||
// FIXME: Use CSS transition
|
||||
// eslint-disable-next-line no-jquery/no-slide
|
||||
$errorBox.slideUp( function () {
|
||||
$errorBox
|
||||
.removeAttr( 'class' )
|
||||
.empty();
|
||||
} );
|
||||
} else {
|
||||
// Animate the replacement if told to by the caller (i.e. to make it visually
|
||||
// obvious that the changed field value gives the same errorbox) or if
|
||||
// the errorbox text changes (because it makes more sense than
|
||||
// changing the text with no animation).
|
||||
replace = forceReplacement;
|
||||
if ( !replace ) {
|
||||
$text = $( '<div>' );
|
||||
// Match behavior of HTMLFormField::formatErrors()
|
||||
if ( errors.length === 1 ) {
|
||||
$text.append( errors[ 0 ] );
|
||||
} else {
|
||||
$text.append( $( '<ul>' ).append( errors.map( function ( e ) {
|
||||
return $( '<li>' ).append( e );
|
||||
} ) ) );
|
||||
}
|
||||
if ( $text.text() !== $errorBox.text() ) {
|
||||
replace = true;
|
||||
}
|
||||
}
|
||||
|
||||
$oldErrorBox = $errorBox;
|
||||
if ( replace ) {
|
||||
this.$errorBox = $errorBox = $( '<div>' );
|
||||
$errorBox.hide();
|
||||
$oldErrorBox.after( this.$errorBox );
|
||||
}
|
||||
|
||||
showFunc = function () {
|
||||
if ( $oldErrorBox !== $errorBox ) {
|
||||
$oldErrorBox
|
||||
.removeAttr( 'class' )
|
||||
.detach();
|
||||
}
|
||||
$errorBox
|
||||
.attr( 'class', valid ? 'warningbox' : 'errorbox' )
|
||||
.empty();
|
||||
// Match behavior of HTMLFormField::formatErrors()
|
||||
if ( errors.length === 1 ) {
|
||||
$errorBox.append( errors[ 0 ] );
|
||||
} else {
|
||||
$errorBox.append( $( '<ul>' ).append( errors.map( function ( e ) {
|
||||
return $( '<li>' ).append( e );
|
||||
} ) ) );
|
||||
}
|
||||
// FIXME: Use CSS transition
|
||||
// eslint-disable-next-line no-jquery/no-slide
|
||||
$errorBox.slideDown();
|
||||
};
|
||||
if (
|
||||
$oldErrorBox !== $errorBox &&
|
||||
// eslint-disable-next-line no-jquery/no-class-state
|
||||
( $oldErrorBox.hasClass( 'errorbox' ) || $oldErrorBox.hasClass( 'warningbox' ) )
|
||||
) {
|
||||
// eslint-disable-next-line no-jquery/no-slide
|
||||
$oldErrorBox.slideUp( showFunc );
|
||||
} else {
|
||||
showFunc();
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
}() );
|
||||
195
resources/src/mediawiki.special.createaccount/HtmlformChecker.js
Normal file
195
resources/src/mediawiki.special.createaccount/HtmlformChecker.js
Normal file
|
|
@ -0,0 +1,195 @@
|
|||
/**
|
||||
* A helper class to add validation to non-OOUI HtmlForm fields.
|
||||
*
|
||||
* @private
|
||||
* @class mw.htmlform.Checker
|
||||
*
|
||||
* @constructor
|
||||
* @param {jQuery} $element Form field generated by HTMLForm
|
||||
* @param {Function} validator Validation callback
|
||||
* @param {string} validator.value Value of the form field to be validated
|
||||
* @param {jQuery.Promise} validator.return The promise should be resolved
|
||||
* with an object with two properties: Boolean 'valid' to indicate success
|
||||
* or failure of validation, and an array 'messages' to be passed to
|
||||
* setErrors() on failure.
|
||||
*/
|
||||
function HtmlformChecker( $element, validator ) {
|
||||
this.validator = validator;
|
||||
this.$element = $element;
|
||||
|
||||
this.$errorBox = $element.next( '.errorbox' );
|
||||
if ( !this.$errorBox.length ) {
|
||||
this.$errorBox = $( '<div>' );
|
||||
this.$errorBox.hide();
|
||||
$element.after( this.$errorBox );
|
||||
}
|
||||
|
||||
this.currentValue = this.$element.val();
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach validation events to the form element
|
||||
*
|
||||
* @param {jQuery} [$extraElements] Additional elements to listen for change
|
||||
* events on.
|
||||
* @return {mw.htmlform.Checker}
|
||||
* @chainable
|
||||
*/
|
||||
HtmlformChecker.prototype.attach = function ( $extraElements ) {
|
||||
var $e = this.$element,
|
||||
// We need to hook to all of these events to be sure we are
|
||||
// notified of all changes to the value of an <input type=text>
|
||||
// field.
|
||||
events = 'keyup keydown change mouseup cut paste focus blur';
|
||||
|
||||
if ( $extraElements ) {
|
||||
$e = $e.add( $extraElements );
|
||||
}
|
||||
$e.on( events, mw.util.debounce( 1000, this.validate.bind( this ) ) );
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Validate the form element
|
||||
*
|
||||
* @return {jQuery.Promise}
|
||||
*/
|
||||
HtmlformChecker.prototype.validate = function () {
|
||||
var currentRequestInternal,
|
||||
that = this,
|
||||
value = this.$element.val();
|
||||
|
||||
// Abort any pending requests.
|
||||
if ( this.currentRequest && this.currentRequest.abort ) {
|
||||
this.currentRequest.abort();
|
||||
}
|
||||
|
||||
if ( value === '' ) {
|
||||
this.currentValue = value;
|
||||
this.setErrors( true, [] );
|
||||
return;
|
||||
}
|
||||
|
||||
this.currentRequest = currentRequestInternal = this.validator( value )
|
||||
.done( function ( info ) {
|
||||
var forceReplacement = value !== that.currentValue;
|
||||
|
||||
// Another request was fired in the meantime, the result we got here is no longer current.
|
||||
// This shouldn't happen as we abort pending requests, but you never know.
|
||||
if ( that.currentRequest !== currentRequestInternal ) {
|
||||
return;
|
||||
}
|
||||
// If we're here, then the current request has finished, avoid calling .abort() needlessly.
|
||||
that.currentRequest = undefined;
|
||||
|
||||
that.currentValue = value;
|
||||
|
||||
that.setErrors( info.valid, info.messages, forceReplacement );
|
||||
} ).fail( function () {
|
||||
that.currentValue = null;
|
||||
that.setErrors( true, [] );
|
||||
} );
|
||||
|
||||
return currentRequestInternal;
|
||||
};
|
||||
|
||||
/**
|
||||
* Display errors associated with the form element
|
||||
*
|
||||
* @param {boolean} valid Whether the input is still valid regardless of the messages
|
||||
* @param {Array} errors Errorbox messages. Each errorbox message will be appended to a
|
||||
* `<div>` or `<li>`, as with jQuery.append().
|
||||
* @param {boolean} [forceReplacement] Set true to force a visual replacement even
|
||||
* if the errors are the same. Ignored if errors are empty.
|
||||
* @return {mw.htmlform.Checker}
|
||||
* @chainable
|
||||
*/
|
||||
HtmlformChecker.prototype.setErrors = function ( valid, errors, forceReplacement ) {
|
||||
var $oldErrorBox,
|
||||
showFunc,
|
||||
$text,
|
||||
replace,
|
||||
$errorBox = this.$errorBox;
|
||||
|
||||
if ( errors.length === 0 ) {
|
||||
// FIXME: Use CSS transition
|
||||
// eslint-disable-next-line no-jquery/no-slide
|
||||
$errorBox.slideUp( function () {
|
||||
$errorBox
|
||||
.removeAttr( 'class' )
|
||||
.empty();
|
||||
} );
|
||||
} else {
|
||||
// Animate the replacement if told to by the caller (i.e. to make it visually
|
||||
// obvious that the changed field value gives the same errorbox) or if
|
||||
// the errorbox text changes (because it makes more sense than
|
||||
// changing the text with no animation).
|
||||
replace = forceReplacement;
|
||||
if ( !replace ) {
|
||||
$text = $( '<div>' );
|
||||
// Match behavior of HTMLFormField::formatErrors()
|
||||
if ( errors.length === 1 ) {
|
||||
$text.append( errors[ 0 ] );
|
||||
} else {
|
||||
$text.append(
|
||||
$( '<ul>' ).append(
|
||||
errors.map( function ( e ) {
|
||||
return $( '<li>' ).append( e );
|
||||
} )
|
||||
)
|
||||
);
|
||||
}
|
||||
if ( $text.text() !== $errorBox.text() ) {
|
||||
replace = true;
|
||||
}
|
||||
}
|
||||
|
||||
$oldErrorBox = $errorBox;
|
||||
if ( replace ) {
|
||||
this.$errorBox = $errorBox = $( '<div>' );
|
||||
$errorBox.hide();
|
||||
$oldErrorBox.after( this.$errorBox );
|
||||
}
|
||||
|
||||
showFunc = function () {
|
||||
if ( $oldErrorBox !== $errorBox ) {
|
||||
$oldErrorBox
|
||||
.removeAttr( 'class' )
|
||||
.detach();
|
||||
}
|
||||
$errorBox
|
||||
.attr( 'class', valid ? 'warningbox' : 'errorbox' )
|
||||
.empty();
|
||||
// Match behavior of HTMLFormField::formatErrors()
|
||||
if ( errors.length === 1 ) {
|
||||
$errorBox.append( errors[ 0 ] );
|
||||
} else {
|
||||
$errorBox.append(
|
||||
$( '<ul>' ).append(
|
||||
errors.map( function ( e ) {
|
||||
return $( '<li>' ).append( e );
|
||||
} )
|
||||
)
|
||||
);
|
||||
}
|
||||
// FIXME: Use CSS transition
|
||||
// eslint-disable-next-line no-jquery/no-slide
|
||||
$errorBox.slideDown();
|
||||
};
|
||||
if (
|
||||
$oldErrorBox !== $errorBox &&
|
||||
// eslint-disable-next-line no-jquery/no-class-state
|
||||
( $oldErrorBox.hasClass( 'errorbox' ) || $oldErrorBox.hasClass( 'warningbox' ) )
|
||||
) {
|
||||
// eslint-disable-next-line no-jquery/no-slide
|
||||
$oldErrorBox.slideUp( showFunc );
|
||||
} else {
|
||||
showFunc();
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
module.exports = HtmlformChecker;
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
/*!
|
||||
* JavaScript for signup form.
|
||||
*/
|
||||
var HtmlformChecker = require( './HtmlformChecker.js' );
|
||||
|
||||
// When sending password by email, hide the password input fields.
|
||||
$( function () {
|
||||
// Always required if checked, otherwise it depends, so we use the original
|
||||
|
|
@ -120,9 +122,9 @@ mw.hook( 'htmlform.enhance' ).add( function ( $root ) {
|
|||
return d.promise( { abort: apiPromise.abort } );
|
||||
}
|
||||
|
||||
usernameChecker = new mw.htmlform.Checker( $usernameInput, checkUsername );
|
||||
usernameChecker = new HtmlformChecker( $usernameInput, checkUsername );
|
||||
usernameChecker.attach();
|
||||
|
||||
passwordChecker = new mw.htmlform.Checker( $passwordInput, checkPassword );
|
||||
passwordChecker = new HtmlformChecker( $passwordInput, checkPassword );
|
||||
passwordChecker.attach( $usernameInput.add( $emailInput ).add( $realNameInput ) );
|
||||
} );
|
||||
|
|
|
|||
Loading…
Reference in a new issue