From ccc1c08089b6596bc20f6d88db1909f57fab2498 Mon Sep 17 00:00:00 2001 From: Brad Jorsch Date: Mon, 26 Feb 2018 13:07:11 -0500 Subject: [PATCH] Update more forms to limit comments by codepoints rather than bytes This updates the deletion forms, Special:Block, Special:EditTags, Special:MovePage, Special:RevisionDelete, Special:Undelete, and Special:UserRights to limit by code point count rather than by byte (or, in some cases, by UTF-16 code unit). Bug: T185948 Change-Id: I20d11d7cc4f58902cbcb6dda70af533bce6dd170 --- includes/FileDeleteForm.php | 16 +++++- .../fields/HTMLSelectAndOtherField.php | 13 ++++- includes/page/Article.php | 8 ++- includes/specials/SpecialBlock.php | 9 ++- includes/specials/SpecialEditTags.php | 17 ++++-- includes/specials/SpecialMovepage.php | 11 +++- includes/specials/SpecialRevisiondelete.php | 18 ++++-- includes/specials/SpecialUndelete.php | 7 +++ includes/specials/SpecialUserrights.php | 11 +++- resources/Resources.php | 38 +++++++++++++ .../mediawiki.action.delete.file.js | 31 ++++++++++ .../mediawiki.action.delete.js | 30 ++++++++++ .../mediawiki.special.edittags.js | 15 ++++- .../mediawiki.special.movePage.js | 12 +++- .../mediawiki.special.revisionDelete.js | 29 ++++++++++ .../mediawiki.special.undelete.js | 23 ++++++-- .../mediawiki.special.userrights.js | 18 +++++- .../src/mediawiki/htmlform/selectandother.js | 57 +++++++++++++------ 18 files changed, 312 insertions(+), 51 deletions(-) create mode 100644 resources/src/mediawiki.action/mediawiki.action.delete.file.js create mode 100644 resources/src/mediawiki.action/mediawiki.action.delete.js create mode 100644 resources/src/mediawiki.special/mediawiki.special.revisionDelete.js diff --git a/includes/FileDeleteForm.php b/includes/FileDeleteForm.php index 8c843c4438..783de1c0c4 100644 --- a/includes/FileDeleteForm.php +++ b/includes/FileDeleteForm.php @@ -246,6 +246,9 @@ class FileDeleteForm { private function showForm() { global $wgOut, $wgUser, $wgRequest; + $conf = RequestContext::getMain()->getConfig(); + $oldCommentSchema = $conf->get( 'CommentTableSchemaMigrationStage' ) === MIGRATION_OLD; + if ( $wgUser->isAllowed( 'suppressrevision' ) ) { $suppress = " @@ -258,6 +261,8 @@ class FileDeleteForm { $suppress = ''; } + $wgOut->addModules( 'mediawiki.action.delete.file' ); + $checkWatch = $wgUser->getBoolOption( 'watchdeletion' ) || $wgUser->isWatched( $this->title ); $form = Xml::openElement( 'form', [ 'method' => 'post', 'action' => $this->getAction(), 'id' => 'mw-img-deleteconfirm' ] ) . @@ -286,8 +291,15 @@ class FileDeleteForm { Xml::label( wfMessage( 'filedelete-otherreason' )->text(), 'wpReason' ) . " " . - Xml::input( 'wpReason', 60, $wgRequest->getText( 'wpReason' ), - [ 'type' => 'text', 'maxlength' => '255', 'tabindex' => '2', 'id' => 'wpReason' ] ) . + Xml::input( 'wpReason', 60, $wgRequest->getText( 'wpReason' ), [ + 'type' => 'text', + // HTML maxlength uses "UTF-16 code units", which means that characters outside BMP + // (e.g. emojis) count for two each. This limit is overridden in JS to instead count + // Unicode codepoints (or 255 UTF-8 bytes for old schema). + 'maxlength' => $oldCommentSchema ? 255 : CommentStore::COMMENT_CHARACTER_LIMIT, + 'tabindex' => '2', + 'id' => 'wpReason' + ] ) . " {$suppress}"; diff --git a/includes/htmlform/fields/HTMLSelectAndOtherField.php b/includes/htmlform/fields/HTMLSelectAndOtherField.php index cdb8f5b909..610b509305 100644 --- a/includes/htmlform/fields/HTMLSelectAndOtherField.php +++ b/includes/htmlform/fields/HTMLSelectAndOtherField.php @@ -47,6 +47,10 @@ class HTMLSelectAndOtherField extends HTMLSelectField { $textAttribs['class'][] = $this->mClass; } + if ( isset( $this->mParams['maxlength-unit'] ) ) { + $textAttribs['data-mw-maxlength-unit'] = $this->mParams['maxlength-unit']; + } + $allowedParams = [ 'required', 'autofocus', @@ -54,6 +58,7 @@ class HTMLSelectAndOtherField extends HTMLSelectField { 'disabled', 'tabindex', 'maxlength', // gets dynamic with javascript, see mediawiki.htmlform.js + 'maxlength-unit', // 'bytes' or 'codepoints', see mediawiki.htmlform.js ]; $textAttribs += $this->getAttributes( $allowedParams ); @@ -73,9 +78,6 @@ class HTMLSelectAndOtherField extends HTMLSelectField { # TextInput $textAttribs = [ 'name' => $this->mName . '-other', - 'size' => $this->getSize(), - 'class' => [ 'mw-htmlform-select-and-other-field' ], - 'data-id-select' => $this->mID . '-select', 'value' => $value[2], ]; @@ -122,6 +124,11 @@ class HTMLSelectAndOtherField extends HTMLSelectField { 'textinput' => $textAttribs, 'dropdowninput' => $dropdownInputAttribs, 'or' => false, + 'classes' => [ 'mw-htmlform-select-and-other-field' ], + 'data' => [ + 'maxlengthUnit' => isset( $this->mParams['maxlength-unit'] ) + ? $this->mParams['maxlength-unit'] : 'bytes' + ], ] ); } diff --git a/includes/page/Article.php b/includes/page/Article.php index 8eb3709b53..cd7226700e 100644 --- a/includes/page/Article.php +++ b/includes/page/Article.php @@ -1683,6 +1683,7 @@ class Article implements Page { $outputPage->setPageTitle( wfMessage( 'delete-confirm', $title->getPrefixedText() ) ); $outputPage->addBacklinkSubtitle( $title ); $outputPage->setRobotPolicy( 'noindex,nofollow' ); + $outputPage->addModules( 'mediawiki.action.delete' ); $backlinkCache = $title->getBacklinkCache(); if ( $backlinkCache->hasLinks( 'pagelinks' ) || $backlinkCache->hasLinks( 'templatelinks' ) ) { @@ -1727,12 +1728,17 @@ class Article implements Page { ] ); + // HTML maxlength uses "UTF-16 code units", which means that characters outside BMP + // (e.g. emojis) count for two each. This limit is overridden in JS to instead count + // Unicode codepoints (or 255 UTF-8 bytes for old schema). + $conf = $this->getContext()->getConfig(); + $oldCommentSchema = $conf->get( 'CommentTableSchemaMigrationStage' ) === MIGRATION_OLD; $fields[] = new OOUI\FieldLayout( new OOUI\TextInputWidget( [ 'name' => 'wpReason', 'inputId' => 'wpReason', 'tabIndex' => 2, - 'maxLength' => 255, + 'maxLength' => $oldCommentSchema ? 255 : CommentStore::COMMENT_CHARACTER_LIMIT, 'infusable' => true, 'value' => $reason, 'autofocus' => true, diff --git a/includes/specials/SpecialBlock.php b/includes/specials/SpecialBlock.php index 42e7040d0e..23691b251a 100644 --- a/includes/specials/SpecialBlock.php +++ b/includes/specials/SpecialBlock.php @@ -135,6 +135,9 @@ class SpecialBlock extends FormSpecialPage { $suggestedDurations = self::getSuggestedDurations(); + $conf = $this->getConfig(); + $oldCommentSchema = $conf->get( 'CommentTableSchemaMigrationStage' ) === MIGRATION_OLD; + $a = [ 'Target' => [ 'type' => 'user', @@ -157,7 +160,11 @@ class SpecialBlock extends FormSpecialPage { ], 'Reason' => [ 'type' => 'selectandother', - 'maxlength' => 255, + // HTML maxlength uses "UTF-16 code units", which means that characters outside BMP + // (e.g. emojis) count for two each. This limit is overridden in JS to instead count + // Unicode codepoints (or 255 UTF-8 bytes for old schema). + 'maxlength' => $oldCommentSchema ? 255 : CommentStore::COMMENT_CHARACTER_LIMIT, + 'maxlength-unit' => 'codepoints', 'label-message' => 'ipbreason', 'options-message' => 'ipbreason-dropdown', ], diff --git a/includes/specials/SpecialEditTags.php b/includes/specials/SpecialEditTags.php index 962395367b..60d5fd7c8c 100644 --- a/includes/specials/SpecialEditTags.php +++ b/includes/specials/SpecialEditTags.php @@ -239,6 +239,9 @@ class SpecialEditTags extends UnlistedSpecialPage { // Show form if the user can submit if ( $this->isAllowed ) { + $conf = $this->getConfig(); + $oldCommentSchema = $conf->get( 'CommentTableSchemaMigrationStage' ) === MIGRATION_OLD; + $form = Xml::openElement( 'form', [ 'method' => 'post', 'action' => $this->getPageTitle()->getLocalURL( [ 'action' => 'submit' ] ), 'id' => 'mw-revdel-form-revisions' ] ) . @@ -251,12 +254,14 @@ class SpecialEditTags extends UnlistedSpecialPage { Xml::label( $this->msg( 'tags-edit-reason' )->text(), 'wpReason' ) . '' . '' . - Xml::input( - 'wpReason', - 60, - $this->reason, - [ 'id' => 'wpReason', 'maxlength' => 100 ] - ) . + Xml::input( 'wpReason', 60, $this->reason, [ + 'id' => 'wpReason', + // HTML maxlength uses "UTF-16 code units", which means that characters outside BMP + // (e.g. emojis) count for two each. This limit is overridden in JS to instead count + // Unicode codepoints (or 255 UTF-8 bytes for old schema). + // "- 155" is to leave room for the auto-generated part of the log entry. + 'maxlength' => $oldCommentSchema ? 100 : CommentStore::COMMENT_CHARACTER_LIMIT - 155, + ] ) . '' . "\n" . '' . diff --git a/includes/specials/SpecialMovepage.php b/includes/specials/SpecialMovepage.php index 02d6d00232..d30ff4329d 100644 --- a/includes/specials/SpecialMovepage.php +++ b/includes/specials/SpecialMovepage.php @@ -287,8 +287,8 @@ class MovePageForm extends UnlistedSpecialPage { $out->addHTML( "\n" ); } - // Byte limit (not string length limit) for wpReason and wpNewTitleMain - // is enforced in the mediawiki.special.movePage module + // Length limit for wpReason and wpNewTitleMain is enforced in the + // mediawiki.special.movePage module $immovableNamespaces = []; foreach ( array_keys( $this->getLanguage()->getNamespaces() ) as $nsId ) { @@ -326,11 +326,16 @@ class MovePageForm extends UnlistedSpecialPage { ] ); + // HTML maxlength uses "UTF-16 code units", which means that characters outside BMP + // (e.g. emojis) count for two each. This limit is overridden in JS to instead count + // Unicode codepoints (or 255 UTF-8 bytes for old schema). + $conf = $this->getConfig(); + $oldCommentSchema = $conf->get( 'CommentTableSchemaMigrationStage' ) === MIGRATION_OLD; $fields[] = new OOUI\FieldLayout( new OOUI\TextInputWidget( [ 'name' => 'wpReason', 'id' => 'wpReason', - 'maxLength' => 200, + 'maxLength' => $oldCommentSchema ? 200 : CommentStore::COMMENT_CHARACTER_LIMIT, 'infusable' => true, 'value' => $this->reason, ] ), diff --git a/includes/specials/SpecialRevisiondelete.php b/includes/specials/SpecialRevisiondelete.php index aec21dc4d3..e7db9f5e3c 100644 --- a/includes/specials/SpecialRevisiondelete.php +++ b/includes/specials/SpecialRevisiondelete.php @@ -418,8 +418,12 @@ class SpecialRevisionDelete extends UnlistedSpecialPage { // Show form if the user can submit if ( $this->mIsAllowed ) { + $out->addModules( [ 'mediawiki.special.revisionDelete' ] ); $out->addModuleStyles( 'mediawiki.special' ); + $conf = $this->getConfig(); + $oldCommentSchema = $conf->get( 'CommentTableSchemaMigrationStage' ) === MIGRATION_OLD; + $form = Xml::openElement( 'form', [ 'method' => 'post', 'action' => $this->getPageTitle()->getLocalURL( [ 'action' => 'submit' ] ), 'id' => 'mw-revdel-form-revisions' ] ) . @@ -442,12 +446,14 @@ class SpecialRevisionDelete extends UnlistedSpecialPage { Xml::label( $this->msg( 'revdelete-otherreason' )->text(), 'wpReason' ) . '' . '' . - Xml::input( - 'wpReason', - 60, - $this->otherReason, - [ 'id' => 'wpReason', 'maxlength' => 100 ] - ) . + Xml::input( 'wpReason', 60, $this->otherReason, [ + 'id' => 'wpReason', + // HTML maxlength uses "UTF-16 code units", which means that characters outside BMP + // (e.g. emojis) count for two each. This limit is overridden in JS to instead count + // Unicode codepoints (or 255 UTF-8 bytes for old schema). + // "- 155" is to leave room for the 'wpRevDeleteReasonList' value. + 'maxlength' => $oldCommentSchema ? 100 : CommentStore::COMMENT_CHARACTER_LIMIT - 155, + ] ) . '' . "\n" . '' . diff --git a/includes/specials/SpecialUndelete.php b/includes/specials/SpecialUndelete.php index 127a36ba3c..6e6ad779b3 100644 --- a/includes/specials/SpecialUndelete.php +++ b/includes/specials/SpecialUndelete.php @@ -739,6 +739,9 @@ class SpecialUndelete extends SpecialPage { 'content' => new OOUI\HtmlSnippet( $this->msg( 'undeleteextrahelp' )->parseAsBlock() ) ] ); + $conf = $this->getConfig(); + $oldCommentSchema = $conf->get( 'CommentTableSchemaMigrationStage' ) === MIGRATION_OLD; + $fields[] = new OOUI\FieldLayout( new OOUI\TextInputWidget( [ 'name' => 'wpComment', @@ -746,6 +749,10 @@ class SpecialUndelete extends SpecialPage { 'infusable' => true, 'value' => $this->mComment, 'autofocus' => true, + // HTML maxlength uses "UTF-16 code units", which means that characters outside BMP + // (e.g. emojis) count for two each. This limit is overridden in JS to instead count + // Unicode codepoints (or 255 UTF-8 bytes for old schema). + 'maxLength' => $oldCommentSchema ? 255 : CommentStore::COMMENT_CHARACTER_LIMIT, ] ), [ 'label' => $this->msg( 'undeletecomment' )->text(), diff --git a/includes/specials/SpecialUserrights.php b/includes/specials/SpecialUserrights.php index e62731fbf4..40f02a5f4d 100644 --- a/includes/specials/SpecialUserrights.php +++ b/includes/specials/SpecialUserrights.php @@ -716,6 +716,8 @@ class UserrightsPage extends SpecialPage { ->rawParams( $userToolLinks )->parse() ); if ( $canChangeAny ) { + $conf = $this->getConfig(); + $oldCommentSchema = $conf->get( 'CommentTableSchemaMigrationStage' ) === MIGRATION_OLD; $this->getOutput()->addHTML( $this->msg( 'userrights-groups-help', $user->getName() )->parse() . $grouplist . @@ -726,8 +728,13 @@ class UserrightsPage extends SpecialPage { Xml::label( $this->msg( 'userrights-reason' )->text(), 'wpReason' ) . " " . - Xml::input( 'user-reason', 60, $this->getRequest()->getVal( 'user-reason', false ), - [ 'id' => 'wpReason', 'maxlength' => 255 ] ) . + Xml::input( 'user-reason', 60, $this->getRequest()->getVal( 'user-reason', false ), [ + 'id' => 'wpReason', + // HTML maxlength uses "UTF-16 code units", which means that characters outside BMP + // (e.g. emojis) count for two each. This limit is overridden in JS to instead count + // Unicode codepoints (or 255 UTF-8 bytes for old schema). + 'maxlength' => $oldCommentSchema ? 255 : CommentStore::COMMENT_CHARACTER_LIMIT, + ] ) . " diff --git a/resources/Resources.php b/resources/Resources.php index bf31024977..c1d3426874 100644 --- a/resources/Resources.php +++ b/resources/Resources.php @@ -1421,6 +1421,27 @@ return [ /* MediaWiki Action */ + 'mediawiki.action.delete' => [ + 'scripts' => 'resources/src/mediawiki.action/mediawiki.action.delete.js', + 'dependencies' => [ + 'oojs-ui-core', + 'jquery.lengthLimit', + ], + 'messages' => [ + // @todo Load this message in content language + 'colon-separator', + ], + ], + 'mediawiki.action.delete.file' => [ + 'scripts' => 'resources/src/mediawiki.action/mediawiki.action.delete.file.js', + 'dependencies' => [ + 'jquery.lengthLimit', + ], + 'messages' => [ + // @todo Load this message in content language + 'colon-separator', + ], + ], 'mediawiki.action.edit' => [ 'scripts' => [ 'resources/src/mediawiki.action/mediawiki.action.edit.js', @@ -2091,6 +2112,7 @@ return [ 'scripts' => 'resources/src/mediawiki.special/mediawiki.special.edittags.js', 'dependencies' => [ 'jquery.chosen', + 'jquery.lengthLimit', ], 'messages' => [ 'tags-edit-chosen-placeholder', @@ -2151,6 +2173,17 @@ return [ 'scripts' => 'resources/src/mediawiki.special/mediawiki.special.recentchanges.js', 'targets' => [ 'desktop', 'mobile' ], ], + 'mediawiki.special.revisionDelete' => [ + 'scripts' => 'resources/src/mediawiki.special/mediawiki.special.revisionDelete.js', + 'messages' => [ + // @todo Load this message in content language + 'colon-separator', + ], + 'dependencies' => [ + 'jquery.lengthLimit', + ], + 'targets' => [ 'desktop', 'mobile' ], + ], 'mediawiki.special.search' => [ 'scripts' => 'resources/src/mediawiki.special/mediawiki.special.search.js', 'styles' => 'resources/src/mediawiki.special/mediawiki.special.search.css', @@ -2185,6 +2218,10 @@ return [ ], 'mediawiki.special.undelete' => [ 'scripts' => 'resources/src/mediawiki.special/mediawiki.special.undelete.js', + 'dependencies' => [ + 'mediawiki.widgets.visibleLengthLimit', + 'mediawiki.widgets', + ], ], 'mediawiki.special.unwatchedPages' => [ 'scripts' => 'resources/src/mediawiki.special/mediawiki.special.unwatchedPages.js', @@ -2272,6 +2309,7 @@ return [ 'scripts' => 'resources/src/mediawiki.special/mediawiki.special.userrights.js', 'dependencies' => [ 'mediawiki.notification.convertmessagebox', + 'jquery.lengthLimit', ], ], 'mediawiki.special.watchlist' => [ diff --git a/resources/src/mediawiki.action/mediawiki.action.delete.file.js b/resources/src/mediawiki.action/mediawiki.action.delete.file.js new file mode 100644 index 0000000000..d6e679641b --- /dev/null +++ b/resources/src/mediawiki.action/mediawiki.action.delete.file.js @@ -0,0 +1,31 @@ +/*! + * JavaScript for Special:RevisionDelete + */ +( function ( mw, $ ) { + $( function () { + var colonSeparator = mw.message( 'colon-separator' ).text(), + summaryCodePointLimit = mw.config.get( 'wgCommentCodePointLimit' ), + summaryByteLimit = mw.config.get( 'wgCommentByteLimit' ), + $wpDeleteReasonList = $( '#wpDeleteReasonList' ), + $wpReason = $( '#wpReason' ), + filterFn = function ( input ) { + // Should be built the same as in SpecialRevisionDelete::submit() + var comment = $wpDeleteReasonList.val(); + if ( comment === 'other' ) { + comment = input; + } else if ( input !== '' ) { + // Entry from drop down menu + additional comment + comment += colonSeparator + input; + } + return comment; + }; + + // Limit to bytes or UTF-8 codepoints, depending on MediaWiki's configuration + if ( summaryCodePointLimit ) { + $wpReason.codePointLimit( summaryCodePointLimit, filterFn ); + } else if ( summaryByteLimit ) { + $wpReason.bytePointLimit( summaryByteLimit, filterFn ); + } + } ); + +}( mediaWiki, jQuery ) ); diff --git a/resources/src/mediawiki.action/mediawiki.action.delete.js b/resources/src/mediawiki.action/mediawiki.action.delete.js new file mode 100644 index 0000000000..c353a4808f --- /dev/null +++ b/resources/src/mediawiki.action/mediawiki.action.delete.js @@ -0,0 +1,30 @@ +/*! + * Scripts for action=delete at domready + */ +( function ( mw, $ ) { + $( function () { + var colonSeparator = mw.message( 'colon-separator' ).text(), + summaryCodePointLimit = mw.config.get( 'wgCommentCodePointLimit' ), + summaryByteLimit = mw.config.get( 'wgCommentByteLimit' ), + reasonList = OO.ui.infuse( $( '#wpDeleteReasonList' ).closest( '.oo-ui-widget' ) ), + reason = OO.ui.infuse( $( '#wpReason' ).closest( '.oo-ui-widget' ) ), + filterFn = function ( input ) { + // Should be built the same as in Article::delete() + var comment = reasonList.getValue(); + if ( comment === 'other' ) { + comment = input; + } else if ( input !== '' ) { + // Entry from drop down menu + additional comment + comment += colonSeparator + input; + } + return comment; + }; + + // Limit to bytes or UTF-8 codepoints, depending on MediaWiki's configuration + if ( summaryCodePointLimit ) { + reason.$input.codePointLimit( summaryCodePointLimit, filterFn ); + } else if ( summaryByteLimit ) { + reason.$input.bytePointLimit( summaryByteLimit, filterFn ); + } + } ); +}( mediaWiki, jQuery ) ); diff --git a/resources/src/mediawiki.special/mediawiki.special.edittags.js b/resources/src/mediawiki.special/mediawiki.special.edittags.js index 3e6e684332..45c3cf905d 100644 --- a/resources/src/mediawiki.special/mediawiki.special.edittags.js +++ b/resources/src/mediawiki.special/mediawiki.special.edittags.js @@ -3,7 +3,11 @@ */ ( function ( mw, $ ) { $( function () { - var $tagList = $( '#mw-edittags-tag-list' ); + var summaryCodePointLimit = mw.config.get( 'wgCommentCodePointLimit' ), + summaryByteLimit = mw.config.get( 'wgCommentByteLimit' ), + $wpReason = $( '#wpReason' ), + $tagList = $( '#mw-edittags-tag-list' ); + if ( $tagList.length ) { $tagList.chosen( { /* eslint-disable camelcase */ @@ -21,5 +25,14 @@ $( '#mw-edittags-remove-all' ).prop( 'checked', false ); } } ); + + // Limit to bytes or UTF-8 codepoints, depending on MediaWiki's configuration + // use maxLength because it's leaving room for log entry text. + if ( summaryCodePointLimit ) { + $wpReason.codePointLimit(); + } else if ( summaryByteLimit ) { + $wpReason.bytePointLimit(); + } } ); + }( mediaWiki, jQuery ) ); diff --git a/resources/src/mediawiki.special/mediawiki.special.movePage.js b/resources/src/mediawiki.special/mediawiki.special.movePage.js index 2e980ac9fd..d828396ea5 100644 --- a/resources/src/mediawiki.special/mediawiki.special.movePage.js +++ b/resources/src/mediawiki.special/mediawiki.special.movePage.js @@ -3,10 +3,18 @@ */ ( function ( mw, $ ) { $( function () { + var summaryCodePointLimit = mw.config.get( 'wgCommentCodePointLimit' ), + summaryByteLimit = mw.config.get( 'wgCommentByteLimit' ), + wpReason = OO.ui.infuse( $( '#wpReason' ) ); + // Infuse for pretty dropdown OO.ui.infuse( $( '#wpNewTitle' ) ); - // Limit to bytes, not characters - mw.widgets.visibleByteLimit( OO.ui.infuse( $( '#wpReason' ) ) ); + // Limit to bytes or UTF-8 codepoints, depending on MediaWiki's configuration + if ( summaryCodePointLimit ) { + mw.widgets.visibleCodePointLimit( wpReason, summaryCodePointLimit ); + } else if ( summaryByteLimit ) { + mw.widgets.visibleByteLimit( wpReason, summaryByteLimit ); + } // Infuse for nicer "help" popup if ( $( '#wpMovetalk-field' ).length ) { OO.ui.infuse( $( '#wpMovetalk-field' ) ); diff --git a/resources/src/mediawiki.special/mediawiki.special.revisionDelete.js b/resources/src/mediawiki.special/mediawiki.special.revisionDelete.js new file mode 100644 index 0000000000..c6d44fa304 --- /dev/null +++ b/resources/src/mediawiki.special/mediawiki.special.revisionDelete.js @@ -0,0 +1,29 @@ +/*! + * JavaScript for Special:RevisionDelete + */ +( function ( mw, $ ) { + var colonSeparator = mw.message( 'colon-separator' ).text(), + summaryCodePointLimit = mw.config.get( 'wgCommentCodePointLimit' ), + summaryByteLimit = mw.config.get( 'wgCommentByteLimit' ), + $wpRevDeleteReasonList = $( '#wpRevDeleteReasonList' ), + $wpReason = $( '#wpReason' ), + filterFn = function ( input ) { + // Should be built the same as in SpecialRevisionDelete::submit() + var comment = $wpRevDeleteReasonList.val(); + if ( comment === 'other' ) { + comment = input; + } else if ( input !== '' ) { + // Entry from drop down menu + additional comment + comment += colonSeparator + input; + } + return comment; + }; + + // Limit to bytes or UTF-8 codepoints, depending on MediaWiki's configuration + if ( summaryCodePointLimit ) { + $wpReason.codePointLimit( summaryCodePointLimit, filterFn ); + } else if ( summaryByteLimit ) { + $wpReason.bytePointLimit( summaryByteLimit, filterFn ); + } + +}( mediaWiki, jQuery ) ); diff --git a/resources/src/mediawiki.special/mediawiki.special.undelete.js b/resources/src/mediawiki.special/mediawiki.special.undelete.js index 4629d57a21..e3cf598454 100644 --- a/resources/src/mediawiki.special/mediawiki.special.undelete.js +++ b/resources/src/mediawiki.special/mediawiki.special.undelete.js @@ -1,10 +1,23 @@ /*! * JavaScript for Special:Undelete */ -jQuery( function ( $ ) { - $( '#mw-undelete-invert' ).click( function () { - $( '.mw-undelete-revlist input[type="checkbox"]' ).prop( 'checked', function ( i, val ) { - return !val; +( function ( mw, $ ) { + $( function () { + var summaryCodePointLimit = mw.config.get( 'wgCommentCodePointLimit' ), + summaryByteLimit = mw.config.get( 'wgCommentByteLimit' ), + wpComment = OO.ui.infuse( $( '#wpComment' ).closest( '.oo-ui-widget' ) ); + + $( '#mw-undelete-invert' ).click( function () { + $( '.mw-undelete-revlist input[type="checkbox"]' ).prop( 'checked', function ( i, val ) { + return !val; + } ); } ); + + // Limit to bytes or UTF-8 codepoints, depending on MediaWiki's configuration + if ( summaryCodePointLimit ) { + mw.widgets.visibleCodePointLimit( wpComment, summaryCodePointLimit ); + } else if ( summaryByteLimit ) { + mw.widgets.visibleByteLimit( wpComment, summaryByteLimit ); + } } ); -} ); +}( mediaWiki, jQuery ) ); diff --git a/resources/src/mediawiki.special/mediawiki.special.userrights.js b/resources/src/mediawiki.special/mediawiki.special.userrights.js index d3494f74f8..981344d166 100644 --- a/resources/src/mediawiki.special/mediawiki.special.userrights.js +++ b/resources/src/mediawiki.special/mediawiki.special.userrights.js @@ -1,8 +1,12 @@ /*! * JavaScript for Special:UserRights */ -( function ( $ ) { - var convertmessagebox = require( 'mediawiki.notification.convertmessagebox' ); +( function ( mw, $ ) { + var convertmessagebox = require( 'mediawiki.notification.convertmessagebox' ), + summaryCodePointLimit = mw.config.get( 'wgCommentCodePointLimit' ), + summaryByteLimit = mw.config.get( 'wgCommentByteLimit' ), + $wpReason = $( '#wpReason' ); + // Replace successbox with notifications convertmessagebox(); @@ -10,4 +14,12 @@ $( '.mw-userrights-nested select' ).on( 'change', function ( e ) { $( e.target.parentNode ).find( 'input' ).toggle( $( e.target ).val() === 'other' ); } ); -}( jQuery ) ); + + // Limit to bytes or UTF-8 codepoints, depending on MediaWiki's configuration + if ( summaryCodePointLimit ) { + $wpReason.codePointLimit( summaryCodePointLimit ); + } else if ( summaryByteLimit ) { + $wpReason.bytePointLimit( summaryByteLimit ); + } + +}( mediaWiki, jQuery ) ); diff --git a/resources/src/mediawiki/htmlform/selectandother.js b/resources/src/mediawiki/htmlform/selectandother.js index 95227d0194..fda6742063 100644 --- a/resources/src/mediawiki/htmlform/selectandother.js +++ b/resources/src/mediawiki/htmlform/selectandother.js @@ -14,27 +14,52 @@ $root .find( '.mw-htmlform-select-and-other-field' ) .each( function () { - var $this = $( this ), + var $reasonList, currentValReasonList, maxlengthUnit, lengthLimiter, widget, + $this = $( this ), + $widget = $this.closest( '.oo-ui-widget[data-ooui]' ); + + if ( $widget ) { + mw.loader.using( 'mediawiki.widgets.SelectWithInputWidget', function () { + widget = OO.ui.Widget.static.infuse( $widget ); + maxlengthUnit = widget.getData().maxlengthUnit; + lengthLimiter = maxlengthUnit === 'codepoints' ? 'codePointLimit' : 'byteLimit'; + widget.textinput.$input[ lengthLimiter ]( function ( input ) { + // Should be built the same as in HTMLSelectAndOtherField::loadDataFromRequest + var comment = widget.dropdowninput.getValue(); + if ( comment === 'other' ) { + comment = input; + } else if ( input !== '' ) { + // Entry from drop down menu + additional comment + comment += colonSeparator + input; + } + return comment; + } ); + } ); + } else { // find the reason list - $reasonList = $root.find( '#' + $this.data( 'id-select' ) ), + $reasonList = $root.find( '#' + $this.data( 'id-select' ) ); // cache the current selection to avoid expensive lookup currentValReasonList = $reasonList.val(); - $reasonList.change( function () { - currentValReasonList = $reasonList.val(); - } ); + $reasonList.change( function () { + currentValReasonList = $reasonList.val(); + } ); - $this.byteLimit( function ( input ) { - // Should be built the same as in HTMLSelectAndOtherField::loadDataFromRequest - var comment = currentValReasonList; - if ( comment === 'other' ) { - comment = input; - } else if ( input !== '' ) { - // Entry from drop down menu + additional comment - comment += colonSeparator + input; - } - return comment; - } ); + // Select the function for the length limit + maxlengthUnit = $this.data( 'mw-maxlength-unit' ); + lengthLimiter = maxlengthUnit === 'codepoints' ? 'codePointLimit' : 'byteLimit'; + $this[ lengthLimiter ]( function ( input ) { + // Should be built the same as in HTMLSelectAndOtherField::loadDataFromRequest + var comment = currentValReasonList; + if ( comment === 'other' ) { + comment = input; + } else if ( input !== '' ) { + // Entry from drop down menu + additional comment + comment += colonSeparator + input; + } + return comment; + } ); + } } ); } ); -- 2.20.1