diff --git a/resources/Resources.php b/resources/Resources.php index 1faab9fbcc6..2d400078fd9 100644 --- a/resources/Resources.php +++ b/resources/Resources.php @@ -1312,8 +1312,6 @@ return [ ], 'messages' => [ 'protect-unchain-permissions', - // @todo Load this message in content language - 'colon-separator', ], ], 'mediawiki.action.view.metadata' => [ @@ -2139,11 +2137,6 @@ return [ 'mediawiki.widgets', 'oojs-ui-core', ], - 'messages' => [ - // Used by action.delete.js, special.revisionDelete.js, special.movePage.js, special.undelete.js - // @todo Load this message in content language - 'colon-separator', - ], ], // This bundles various small (under 2 KB?) JavaScript files that: // - .. are only used by logged-in users when a non-default preference was enabled. @@ -2679,8 +2672,19 @@ return [ ], ], 'mediawiki.widgets.visibleLengthLimit' => [ - 'scripts' => [ - 'resources/src/mediawiki.widgets.visibleLengthLimit/mediawiki.widgets.visibleLengthLimit.js' + 'localBasePath' => MW_INSTALL_PATH . '/resources/src/mediawiki.widgets.visibleLengthLimit', + 'remoteBasePath' => "$wgResourceBasePath/resources/src/mediawiki.widgets.visibleLengthLimit", + 'packageFiles' => [ + 'mediawiki.widgets.visibleLengthLimit.js', + [ + 'name' => 'contentMessages.json', + 'type' => 'data', + 'callback' => static function ( Context $context ) { + return [ + 'colonSeparator' => $context->msg( 'colon-separator' )->inContentLanguage()->text(), + ]; + } + ], ], 'dependencies' => [ 'oojs-ui-core', diff --git a/resources/src/mediawiki.action/mediawiki.action.protect.js b/resources/src/mediawiki.action/mediawiki.action.protect.js index ed02fd045d8..423624c1c26 100644 --- a/resources/src/mediawiki.action/mediawiki.action.protect.js +++ b/resources/src/mediawiki.action/mediawiki.action.protect.js @@ -199,27 +199,11 @@ toggleUnchainedInputs( !areAllTypesMatching() ); } - var colonSeparator = mw.msg( 'colon-separator' ), - reasonList = OO.ui.infuse( $( '#wpProtectReasonSelection' ) ), - reason = OO.ui.infuse( $( '#mwProtect-reason' ) ), - filterFunction = function ( input ) { - // Should be built the same as in ProtectionForm::save() - var comment = reasonList.getValue(); - if ( comment === 'other' ) { - comment = input; - } else if ( input !== '' ) { - // Entry from drop down menu + additional comment - comment += colonSeparator + input; - } - return comment; - }; + var reasonList = OO.ui.infuse( $( '#wpProtectReasonSelection' ) ), + reason = OO.ui.infuse( $( '#mwProtect-reason' ) ); // Arbitrary 75 to leave some space for the autogenerated null edit's summary - mw.widgets.visibleCodePointLimit( reason, mw.config.get( 'wgCommentCodePointLimit' ) - 75, filterFunction ); - // Keep the remaining counter in sync when reason list changed - reasonList.on( 'change', function () { - reason.emit( 'change' ); - } ); + mw.widgets.visibleCodePointLimitWithDropdown( reason, reasonList, mw.config.get( 'wgCommentCodePointLimit' ) - 75 ); updateCascadeAndExpire(); }() ); diff --git a/resources/src/mediawiki.htmlform/selectandother.js b/resources/src/mediawiki.htmlform/selectandother.js index f71a465a0cf..eeaa8e74f2b 100644 --- a/resources/src/mediawiki.htmlform/selectandother.js +++ b/resources/src/mediawiki.htmlform/selectandother.js @@ -24,22 +24,9 @@ mw.loader.using( 'mediawiki.widgets.SelectWithInputWidget', function () { widget = OO.ui.Widget.static.infuse( $widget ); maxlengthUnit = widget.getData().maxlengthUnit; - lengthLimiter = maxlengthUnit === 'codepoints' ? 'visibleCodePointLimit' : 'visibleByteLimit '; - mw.widgets[ lengthLimiter ]( widget.textinput, null, 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; - } ); - // Keep the remaining counter in sync when reason list changed - widget.dropdowninput.on( 'change', function () { - widget.textinput.emit( 'change' ); - } ); + lengthLimiter = maxlengthUnit === 'codepoints' ? + 'visibleCodePointLimitWithDropdown' : 'visibleByteLimitWithDropdown'; + mw.widgets[ lengthLimiter ]( widget.textinput, widget.dropdowninput ); } ); } else { // cache the current selection to avoid expensive lookup diff --git a/resources/src/mediawiki.misc-authed-ooui/action.delete.js b/resources/src/mediawiki.misc-authed-ooui/action.delete.js index d612e7edfcb..53e6cfb9f52 100644 --- a/resources/src/mediawiki.misc-authed-ooui/action.delete.js +++ b/resources/src/mediawiki.misc-authed-ooui/action.delete.js @@ -7,25 +7,9 @@ } $( function () { - var colonSeparator = mw.msg( 'colon-separator' ), - reasonList = OO.ui.infuse( $( '#wpDeleteReasonList' ) ), - reason = OO.ui.infuse( $( '#wpReason' ) ), - filterFunction = function ( input ) { - // Should be built the same as in DeleteAction::getDeleteReason() - var comment = reasonList.getValue(); - if ( comment === 'other' ) { - comment = input; - } else if ( input !== '' ) { - // Entry from drop down menu + additional comment - comment += colonSeparator + input; - } - return comment; - }; + var reasonList = OO.ui.infuse( $( '#wpDeleteReasonList' ) ), + reason = OO.ui.infuse( $( '#wpReason' ) ); - mw.widgets.visibleCodePointLimit( reason, mw.config.get( 'wgCommentCodePointLimit' ), filterFunction ); - // Keep the remaining counter in sync when reason list changed - reasonList.on( 'change', function () { - reason.emit( 'change' ); - } ); + mw.widgets.visibleCodePointLimitWithDropdown( reason, reasonList, mw.config.get( 'wgCommentCodePointLimit' ) ); } ); }() ); diff --git a/resources/src/mediawiki.misc-authed-ooui/special.movePage.js b/resources/src/mediawiki.misc-authed-ooui/special.movePage.js index f9cd31d4c55..7cacc6edb9d 100644 --- a/resources/src/mediawiki.misc-authed-ooui/special.movePage.js +++ b/resources/src/mediawiki.misc-authed-ooui/special.movePage.js @@ -13,24 +13,8 @@ // Infuse for pretty dropdown OO.ui.infuse( $( '#wpNewTitle' ) ); - var colonSeparator = mw.msg( 'colon-separator' ), - wpReasonList = OO.ui.infuse( $( '#wpReasonList' ).closest( '.oo-ui-widget' ) ), - filterFunction = function ( input ) { - // Should be built the same as in SpecialMovePage::execute() - var comment = wpReasonList.getValue(); - if ( comment === 'other' ) { - comment = input; - } else if ( input !== '' ) { - // Entry from drop down menu + additional comment - comment += colonSeparator + input; - } - return comment; - }; + var wpReasonList = OO.ui.infuse( $( '#wpReasonList' ).closest( '.oo-ui-widget' ) ); - mw.widgets.visibleCodePointLimit( wpReason, mw.config.get( 'wgCommentCodePointLimit' ), filterFunction ); - // Keep the remaining counter in sync when reason list changed - wpReasonList.on( 'change', function () { - wpReason.emit( 'change' ); - } ); + mw.widgets.visibleCodePointLimitWithDropdown( wpReason, wpReasonList, mw.config.get( 'wgCommentCodePointLimit' ) ); } ); }() ); diff --git a/resources/src/mediawiki.misc-authed-ooui/special.revisionDelete.js b/resources/src/mediawiki.misc-authed-ooui/special.revisionDelete.js index c0b724e2e34..a453a8a7816 100644 --- a/resources/src/mediawiki.misc-authed-ooui/special.revisionDelete.js +++ b/resources/src/mediawiki.misc-authed-ooui/special.revisionDelete.js @@ -6,24 +6,8 @@ return; } - var colonSeparator = mw.msg( 'colon-separator' ), - wpRevDeleteReasonList = OO.ui.infuse( $( '#wpRevDeleteReasonList' ) ), - wpReason = OO.ui.infuse( $( '#wpReason' ) ), - filterFunction = function ( input ) { - // Should be built the same as in SpecialRevisionDelete::submit() - var comment = wpRevDeleteReasonList.getValue(); - if ( comment === 'other' ) { - comment = input; - } else if ( input !== '' ) { - // Entry from drop down menu + additional comment - comment += colonSeparator + input; - } - return comment; - }; + var wpRevDeleteReasonList = OO.ui.infuse( $( '#wpRevDeleteReasonList' ) ), + wpReason = OO.ui.infuse( $( '#wpReason' ) ); - mw.widgets.visibleCodePointLimit( wpReason, mw.config.get( 'wgCommentCodePointLimit' ), filterFunction ); - // Keep the remaining counter in sync when reason list changed - wpRevDeleteReasonList.on( 'change', function () { - wpReason.emit( 'change' ); - } ); + mw.widgets.visibleCodePointLimitWithDropdown( wpReason, wpRevDeleteReasonList, mw.config.get( 'wgCommentCodePointLimit' ) ); }() ); diff --git a/resources/src/mediawiki.misc-authed-ooui/special.undelete.js b/resources/src/mediawiki.misc-authed-ooui/special.undelete.js index a198566b815..3e9b85c8916 100644 --- a/resources/src/mediawiki.misc-authed-ooui/special.undelete.js +++ b/resources/src/mediawiki.misc-authed-ooui/special.undelete.js @@ -20,19 +20,7 @@ wpComment = OO.ui.infuse( $widget ); - var colonSeparator = mw.msg( 'colon-separator' ), - wpCommentList = OO.ui.infuse( $( '#wpCommentList' ).closest( '.oo-ui-widget' ) ), - filterFunction = function ( input ) { - // Should be built the same as in SpecialUndelete::loadRequest() - var comment = wpCommentList.getValue(); - if ( comment === 'other' ) { - comment = input; - } else if ( input !== '' ) { - // Entry from drop down menu + additional comment - comment += colonSeparator + input; - } - return comment; - }; + var wpCommentList = OO.ui.infuse( $( '#wpCommentList' ).closest( '.oo-ui-widget' ) ); $( '#mw-undelete-invert' ).on( 'click', function () { $( '.mw-undelete-revlist input[type="checkbox"]' ).prop( 'checked', function ( i, val ) { @@ -40,10 +28,6 @@ } ); } ); - mw.widgets.visibleCodePointLimit( wpComment, mw.config.get( 'wgCommentCodePointLimit' ), filterFunction ); - // Keep the remaining counter in sync when reason list changed - wpCommentList.on( 'change', function () { - wpComment.emit( 'change' ); - } ); + mw.widgets.visibleCodePointLimitWithDropdown( wpComment, wpCommentList, mw.config.get( 'wgCommentCodePointLimit' ) ); } ); }() ); diff --git a/resources/src/mediawiki.widgets.visibleLengthLimit/mediawiki.widgets.visibleLengthLimit.js b/resources/src/mediawiki.widgets.visibleLengthLimit/mediawiki.widgets.visibleLengthLimit.js index 70be20943a9..6b748f3a52f 100644 --- a/resources/src/mediawiki.widgets.visibleLengthLimit/mediawiki.widgets.visibleLengthLimit.js +++ b/resources/src/mediawiki.widgets.visibleLengthLimit/mediawiki.widgets.visibleLengthLimit.js @@ -1,31 +1,30 @@ ( function () { var byteLength = require( 'mediawiki.String' ).byteLength, - codePointLength = require( 'mediawiki.String' ).codePointLength; + codePointLength = require( 'mediawiki.String' ).codePointLength, + colonSeparator = require( './contentMessages.json' ).colonSeparator; /** - * Loaded from `mediawiki.widgets.visibleLengthLimit` module. - * Add a visible byte limit label to a TextInputWidget. - * - * Uses jQuery#byteLimit to enforce the limit. - * - * @param {OO.ui.TextInputWidget} textInputWidget Text input widget - * @param {number} [limit] Byte limit, defaults to $input's maxlength - * @param {Function} [filterFunction] Function to call on the string before assessing the length. + * @internal + * @param {string} lengthLimiter + * @param {OO.ui.TextInputWidget} textInputWidget + * @param {number} [limit] + * @param {Function} [filterFunction] */ - mw.widgets.visibleByteLimit = function ( textInputWidget, limit, filterFunction ) { + function internalVisibleLimit( lengthLimiter, textInputWidget, limit, filterFunction ) { limit = limit || +textInputWidget.$input.attr( 'maxlength' ); if ( !filterFunction || typeof filterFunction !== 'function' ) { filterFunction = undefined; } + var lengthFunction = lengthLimiter === 'byteLimit' ? byteLength : codePointLength; function updateCount() { var value = textInputWidget.getValue(), remaining; if ( filterFunction ) { value = filterFunction( value ); } - remaining = limit - byteLength( value ); + remaining = limit - lengthFunction( value ); if ( remaining > 99 ) { remaining = ''; } else { @@ -38,7 +37,48 @@ updateCount(); // Actually enforce limit - textInputWidget.$input.byteLimit( limit, filterFunction ); + textInputWidget.$input[ lengthLimiter ]( limit, filterFunction ); + } + + /** + * @internal + * @param {string} lengthLimiter + * @param {OO.ui.TextInputWidget} textInputWidget + * @param {OO.ui.DropdownInputWidget} dropdownInputWidget Dropdown input widget + * @param {number} [limit] + */ + function internalVisibleLimitWithDropdown( lengthLimiter, textInputWidget, dropdownInputWidget, limit ) { + var filterFunction = function ( input ) { + var comment = dropdownInputWidget.getValue(); + if ( comment === 'other' ) { + comment = input; + } else if ( input !== '' ) { + // Entry from drop down menu + additional comment + comment += colonSeparator + input; + } + return comment; + }; + + internalVisibleLimit( lengthLimiter, textInputWidget, limit, filterFunction ); + + // Keep the remaining counter in sync when reason list changed + dropdownInputWidget.on( 'change', function () { + textInputWidget.emit( 'change' ); + } ); + } + + /** + * Loaded from `mediawiki.widgets.visibleLengthLimit` module. + * Add a visible byte limit label to a TextInputWidget. + * + * Uses jQuery#byteLimit to enforce the limit. + * + * @param {OO.ui.TextInputWidget} textInputWidget Text input widget + * @param {number} [limit] Byte limit, defaults to $input's maxlength + * @param {Function} [filterFunction] Function to call on the string before assessing the length. + */ + mw.widgets.visibleByteLimit = function ( textInputWidget, limit, filterFunction ) { + internalVisibleLimit( 'byteLimit', textInputWidget, limit, filterFunction ); }; /** @@ -52,31 +92,35 @@ * @param {Function} [filterFunction] Function to call on the string before assessing the length. */ mw.widgets.visibleCodePointLimit = function ( textInputWidget, limit, filterFunction ) { - limit = limit || +textInputWidget.$input.attr( 'maxlength' ); - if ( !filterFunction || typeof filterFunction !== 'function' ) { - filterFunction = undefined; - } + internalVisibleLimit( 'codePointLimit', textInputWidget, limit, filterFunction ); + }; - function updateCount() { - var value = textInputWidget.getValue(), - remaining; - if ( filterFunction ) { - value = filterFunction( value ); - } - remaining = limit - codePointLength( value ); - if ( remaining > 99 ) { - remaining = ''; - } else { - remaining = mw.language.convertNumber( remaining ); - } - textInputWidget.setLabel( remaining ); - } - textInputWidget.on( 'change', updateCount ); - // Initialise value - updateCount(); + /** + * Loaded from `mediawiki.widgets.visibleLengthLimit` module. + * Add a visible byte limit label to a TextInputWidget/DropdownInputWidget + * + * Uses jQuery#byteLimit to enforce the limit. + * + * @param {OO.ui.TextInputWidget} textInputWidget Text input widget + * @param {OO.ui.DropdownInputWidget} dropdownInputWidget Dropdown input widget + * @param {number} [limit] Code point limit, defaults to $input's maxlength + */ + mw.widgets.visibleByteLimitWithDropdown = function ( textInputWidget, dropdownInputWidget, limit ) { + internalVisibleLimitWithDropdown( 'byteLimit', textInputWidget, dropdownInputWidget, limit ); + }; - // Actually enforce limit - textInputWidget.$input.codePointLimit( limit, filterFunction ); + /** + * Loaded from `mediawiki.widgets.visibleLengthLimit` module. + * Add a visible codepoint (character) limit label to a TextInputWidget/DropdownInputWidget + * + * Uses jQuery#codePointLimit to enforce the limit. + * + * @param {OO.ui.TextInputWidget} textInputWidget Text input widget + * @param {OO.ui.DropdownInputWidget} dropdownInputWidget Dropdown input widget + * @param {number} [limit] Code point limit, defaults to $input's maxlength + */ + mw.widgets.visibleCodePointLimitWithDropdown = function ( textInputWidget, dropdownInputWidget, limit ) { + internalVisibleLimitWithDropdown( 'codePointLimit', textInputWidget, dropdownInputWidget, limit ); }; }() );