creations, similar to the topOnly option.
* Add mediawiki.ui.button styling to all pages so wiki content can use styled
buttons.
+* Special:UserLogin/signup now does AJAX checks for invalid and taken usernames,
+ displaying the error live.
+* Special:UserLogin/signup now warns the user if their chosen username has to be
+ normalized.
=== Bug fixes in 1.23 ===
* (bug 41759) The "updated since last visit" markers (on history pages, recent
$status = $this->addNewAccountInternal();
if ( !$status->isGood() ) {
$error = $status->getMessage();
- $this->mainLoginForm( $error->toString() );
+ $this->mainLoginForm( $error->toString(), $status->isOK() ? 'warning' : 'error' );
return;
}
$status = $this->addNewAccountInternal();
if ( !$status->isGood() ) {
$error = $status->getMessage();
- $this->mainLoginForm( $error->toString() );
+ $this->mainLoginForm( $error->toString(), $status->isOK() ? 'warning' : 'error' );
return false;
}
return Status::newFatal( 'sorbs_create_account_reason' );
}
+ // Leading/trailing/multiple whitespace characters are never accepted in usernames and users
+ // know that, don't warn if someone accidentally types it. We do warn about underscores.
+ $name = trim( preg_replace( '/\s+/', ' ', $this->mUsername ) );
+
// Normalize the name so that silly things don't cause "invalid username" errors.
// User::newFromName does some rather strict checking, rejecting e.g. leading/trailing/multiple spaces.
$title = Title::makeTitleSafe( NS_USER, $this->mUsername );
return Status::newFatal( 'noname' );
}
- # Now create a dummy user ($u) and check if it is valid
+ // Now create a dummy user ($u) and check if it is valid.
$u = User::newFromName( $title->getText(), 'creatable' );
+
if ( !is_object( $u ) ) {
return Status::newFatal( 'noname' );
} elseif ( 0 != $u->idForName() ) {
return Status::newFatal( 'userexists' );
+ } elseif ( $name !== $u->getName() ) {
+ // User name was adjusted due to technical restrictions (e.g. first letter capitalized).
+ // This is normally handled by a client-side check, but users with JavaScript disabled get here.
+ $status = Status::newGood();
+ $status->warning( 'createacct-normalization', $name, $u->getName() );
+
+ // Set the form field to the correct name, so the user can just hit the button again.
+ $this->mUsername = $u->getName();
+
+ return $status;
}
if ( $this->mCreateaccountMail ) {
<section class="mw-form-header">
<?php $this->html( 'header' ); /* extensions such as ConfirmEdit add form HTML here */ ?>
</section>
+ <!-- This element is used by the mediawiki.special.userlogin.signup.js module. -->
+ <div
+ id="mw-createacct-status-area"
+ <?php if ( $this->data['message'] ) { ?>
+ class="<?php echo $this->data['messagetype']; ?>box"
+ <?php } else { ?>
+ style="display: none;"
+ <?php } ?>
+ >
<?php if ( $this->data['message'] ) { ?>
- <div class="<?php $this->text( 'messagetype' ); ?>box">
<?php if ( $this->data['messagetype'] == 'error' ) { ?>
<strong><?php $this->msg( 'createacct-error' ); ?></strong>
<br />
<?php } ?>
<?php $this->html( 'message' ); ?>
- </div>
<?php } ?>
+ </div>
<div>
<label for='wpName2'>
'badretype' => 'The passwords you entered do not match.',
'userexists' => 'Username entered already in use.
Please choose a different name.',
+'createacct-normalization' => 'Your username will be adjusted to "$2" due to technical restrictions.',
'loginerror' => 'Login error',
'createacct-error' => 'Account creation error',
'createaccounterror' => 'Could not create account: $1',
* $1 - number of contributors (users)',
'badretype' => 'Used as error message when the new password and its retype do not match.',
'userexists' => 'Used as error message in creating a user account.',
+'createacct-normalization' => 'Used as warning message on account creation when user name is adjusted silently due to technical restrictions (e.g. first letter capitalized, underscores converted to spaces).
+* $1 - the old username
+* $2 - the new username',
'loginerror' => 'Used as title of error message.
{{Identical|Login error}}',
'createacct-error' => 'Used as heading for the error message.',
'createacct-benefit-body3',
'badretype',
'userexists',
+ 'createacct-normalization',
'loginerror',
'createacct-error',
'createaccounterror',
'mediawiki.special.userlogin.signup.js' => array(
'scripts' => 'resources/mediawiki.special/mediawiki.special.userlogin.signup.js',
'messages' => array(
+ 'createacct-error',
'createacct-emailrequired',
+ 'createacct-normalization',
+ 'noname',
+ 'userexists',
+ ),
+ 'dependencies' => array(
+ 'mediawiki.api',
+ 'mediawiki.jqueryMsg',
+ 'jquery.throttle-debounce',
),
- 'dependencies' => 'mediawiki.jqueryMsg',
),
'mediawiki.special.javaScriptTest' => array(
'scripts' => 'resources/mediawiki.special/mediawiki.special.javaScriptTest.js',
*/
( function ( mw, $ ) {
// When sending password by email, hide the password input fields.
- function hidePasswordOnEmail() {
+ $( function () {
// Always required if checked, otherwise it depends, so we use the original
var $emailLabel = $( 'label[for="wpEmail"]' ),
originalText = $emailLabel.text(),
$createByMailCheckbox.on( 'change', updateForCheckbox );
updateForCheckbox();
- }
+ } );
- $( hidePasswordOnEmail );
+ // Show username normalisation warning
+ $( function () {
+ var
+ // All of these are apparently required to be sure we detect any changes.
+ events = 'keyup keydown change mouseup cut paste focus blur',
+ $input = $( '#wpName2' ),
+ $warningContainer = $( '#mw-createacct-status-area' ),
+ api = new mw.Api(),
+ currentRequest,
+ tweakedUsername;
+
+ // Hide any warnings / errors.
+ function cleanup() {
+ $warningContainer.slideUp( function () {
+ $warningContainer
+ .removeAttr( 'class' )
+ .empty();
+ } );
+ }
+
+ function updateUsernameStatus() {
+ var
+ // Leading/trailing/multiple whitespace characters are never accepted in usernames and users
+ // know that, don't warn if someone accidentally types it. We do warn about underscores.
+ username = $.trim( $input.val().replace( /\s+/g, ' ' ) ),
+ currentRequestInternal;
+
+ // Abort any pending requests.
+ if ( currentRequest ) {
+ currentRequest.abort();
+ }
+
+ if ( username === '' ) {
+ cleanup();
+ return;
+ }
+
+ currentRequest = currentRequestInternal = api.get( {
+ action: 'query',
+ list: 'users',
+ ususers: username // '|' in usernames is handled below
+ } ).done( function ( resp ) {
+ var userinfo, state;
+
+ // 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 ( currentRequest !== currentRequestInternal ) {
+ return;
+ }
+
+ tweakedUsername = undefined;
+
+ userinfo = resp.query.users[0];
+
+ if ( resp.query.users.length !== 1 ) {
+ // Happens if the user types '|' into the field
+ state = 'invalid';
+ } else if ( userinfo.invalid !== undefined ) {
+ state = 'invalid';
+ } else if ( userinfo.userid !== undefined ) {
+ state = 'taken';
+ } else if ( username !== userinfo.name ) {
+ state = 'tweaked';
+ } else {
+ state = 'ok';
+ }
+
+ if ( state === 'ok' ) {
+ cleanup();
+ } else if ( state === 'tweaked' ) {
+ $warningContainer
+ .attr( 'class', 'warningbox' )
+ .text( mw.message( 'createacct-normalization', username, userinfo.name ).text() )
+ .slideDown();
+
+ tweakedUsername = userinfo.name;
+ } else {
+ $warningContainer
+ .attr( 'class', 'errorbox' )
+ .empty()
+ .append(
+ $( '<strong>' ).text( mw.message( 'createacct-error' ).text() ),
+ $( '<br>' ) // Ugh
+ );
+
+ if ( state === 'invalid' ) {
+ $warningContainer
+ .attr( 'class', 'errorbox' )
+ .append( document.createTextNode( mw.message( 'noname' ).text() ) )
+ .slideDown();
+ } else if ( state === 'taken' ) {
+ $warningContainer
+ .attr( 'class', 'errorbox' )
+ .append( document.createTextNode( mw.message( 'userexists' ).text() ) )
+ .slideDown();
+ }
+
+ $warningContainer.slideDown();
+ }
+ } ).fail( function () {
+ cleanup();
+ } );
+ }
+
+ $input.on( events, $.debounce( 250, updateUsernameStatus ) );
+
+ $input.closest( 'form' ).on( 'submit', function () {
+ // If the username has to be adjusted before it's accepted, server-side check will force the
+ // form to be resubmitted. Let's prevent that.
+ if ( tweakedUsername !== undefined ) {
+ $input.val( tweakedUsername );
+ }
+ } );
+ } );
}( mediaWiki, jQuery ) );