'GenerateJsonI18n' => __DIR__ . '/maintenance/generateJsonI18n.php',
'GenerateNormalizerDataAr' => __DIR__ . '/maintenance/language/generateNormalizerDataAr.php',
'GenerateNormalizerDataMl' => __DIR__ . '/maintenance/language/generateNormalizerDataMl.php',
+ 'GeneratePhpCharToUpperMappings' => __DIR__ . '/maintenance/mediawiki.Title/generatePhpCharToUpperMappings.php',
'GenerateSitemap' => __DIR__ . '/maintenance/generateSitemap.php',
'GenerateUcfirstOverrides' => __DIR__ . '/maintenance/language/generateUcfirstOverrides.php',
'GenerateUpperCharTable' => __DIR__ . '/maintenance/language/generateUpperCharTable.php',
},
"repository" : {
"type" : "git",
- "url" : "https://gerrit.wikimedia.org/r/p/mediawiki/core.git"
+ "url" : "https://gerrit.wikimedia.org/r/mediawiki/core.git"
}
}
$htmlForm
->setMethod( 'get' )
->setAction( wfScript() )
- ->setCollapsible( true )
+ ->setCollapsibleOptions( true )
->setId( 'mw-history-searchform' )
->setSubmitText( $this->msg( 'historyaction-submit' )->text() )
->setWrapperAttributes( [ 'id' => 'mw-history-search' ] )
protected $mAction = false;
/**
- * Whether the HTML form can be collapsed
- * @since 1.33
+ * Whether the form can be collapsed
+ * @since 1.34
* @var bool
*/
protected $mCollapsible = false;
/**
- * Whether the HTML form IS collapsed by default
- * @since 1.33
+ * Whether the form is collapsed by default
+ * @since 1.34
* @var bool
*/
protected $mCollapsed = false;
}
/**
- * Make the form collapsible
- * @since 1.33
- * @param bool $collapsed whether it should be by default
- * @return HTMLForm $this for chaining calls (since 1.20)
+ * Set whether the HTML form can be collapsed.
+ *
+ * @since 1.34
+ * @param bool $collapsedByDefault (optional) whether the form is collapsed by default
+ * @return HTMLForm $this for chaining calls
*/
- public function setCollapsible( $collapsed = false ) {
+ public function setCollapsibleOptions( $collapsedByDefault = false ) {
$this->mCollapsible = true;
- $this->mCollapsed = $collapsed;
+ $this->mCollapsed = $collapsedByDefault;
return $this;
}
'classes' => $classes,
'group' => new OOUI\StackLayout( [
'expanded' => false,
- 'classes' => [ 'oo-ui-fieldsetLayout-group mw-collapsible-content' ],
- 'items' => [
- new OOUI\Widget( [
- 'content' => new OOUI\HtmlSnippet( $html )
- ] ),
- ],
+ 'classes' => [ 'mw-collapsible-content' ],
] ),
+ 'items' => [
+ new OOUI\Widget( [
+ 'content' => new OOUI\HtmlSnippet( $html )
+ ] ),
+ ],
] + OOUI\Element::configFromHtmlAttributes( $this->mWrapperAttributes ) );
} else {
$content = new OOUI\HtmlSnippet( $html );
// T221458: MySQL/MariaDB (10.1.37) can sometimes irrationally decide that querying `actor` before
// `logging` and filesorting is somehow better than querying $limit+1 rows from `logging`.
- // Tell it not to reorder the query. But not when tag filtering was used, as it seems as likely
- // to be harmed as helped in that case.
- if ( !$this->mTagFilter ) {
+ // Tell it not to reorder the query. But not when tag filtering or log_search was used, as it
+ // seems as likely to be harmed as helped in that case.
+ if ( !$this->mTagFilter && !array_key_exists( 'ls_field', $this->mConds ) ) {
$options[] = 'STRAIGHT_JOIN';
}
*/
class SearchInputWidget extends TitleInputWidget {
- protected $pushPending = false;
protected $performSearchOnClick = true;
protected $validateTitle = false;
protected $highlightFirst = false;
/**
* @param array $config Configuration options
- * - int|null $config['pushPending'] Whether the input should be visually marked as
- * "pending", while requesting suggestions (default: false)
* - bool|null $config['performSearchOnClick'] If true, the script will start a search
* whenever a user hits a suggestion. If false, the text of the suggestion is inserted into
* the text field only (default: true)
parent::__construct( $config );
// Properties, which are ignored in PHP and just shipped back to JS
- if ( isset( $config['pushPending'] ) ) {
- $this->pushPending = $config['pushPending'];
- }
-
if ( isset( $config['performSearchOnClick'] ) ) {
$this->performSearchOnClick = $config['performSearchOnClick'];
}
}
public function getConfig( &$config ) {
- $config['pushPending'] = $this->pushPending;
$config['performSearchOnClick'] = $this->performSearchOnClick;
if ( $this->dataLocation ) {
$config['dataLocation'] = $this->dataLocation;
/* eslint-env node, es6 */
var i, chars = [];
-for ( i = 0; i < 65536; i++ ) {
- chars.push( String.fromCharCode( i ).toUpperCase() );
+for ( i = 0; i <= 0x10ffff; i++ ) {
+ // eslint-disable-next-line no-restricted-properties
+ chars.push( String.fromCodePoint( i ).toUpperCase() );
}
// eslint-disable-next-line no-console
console.log( JSON.stringify( chars ) );
-#!/usr/bin/env php
<?php
+
/**
- * Utility to generate mapping file used in mw.Title (phpCharToUpper.json)
+ * Update list of upper case differences between JS and PHP
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
*
- * Compares output of String.toUpperCase in JavaScript with
- * mb_strtoupper in PHP, and outputs a list of lower:upper
- * mappings where they differ. This is then used by Title.js
- * to provide the same normalization in the client as on
- * the server.
+ * @file
+ * @ingroup Maintenance
*/
-$data = [];
+use MediaWiki\Shell\Shell;
-// phpcs:disable MediaWiki.Usage.ForbiddenFunctions.exec
-$jsUpperChars = json_decode( exec( 'node generateJsToUpperCaseList.js' ) );
-// phpcs:enable MediaWiki.Usage.ForbiddenFunctions.exec
+require_once __DIR__ . '/../Maintenance.php';
+
+/**
+ * Update list of upper case differences between JS and PHP
+ *
+ * @ingroup Maintenance
+ * @since 1.33
+ */
+class GeneratePhpCharToUpperMappings extends Maintenance {
-for ( $i = 0; $i < 65536; $i++ ) {
- if ( $i >= 0xd800 && $i <= 0xdfff ) {
- // Skip surrogate pairs
- continue;
+ public function __construct() {
+ parent::__construct();
+ $this->addDescription( 'Update list of upper case differences between JS and PHP.' );
}
- $char = mb_convert_encoding( '&#' . $i . ';', 'UTF-8', 'HTML-ENTITIES' );
- $phpUpper = mb_strtoupper( $char );
- $jsUpper = $jsUpperChars[$i];
- if ( $jsUpper !== $phpUpper ) {
- $data[$char] = $phpUpper;
+
+ public function execute() {
+ global $wgContLang, $IP;
+
+ $data = [];
+
+ $result = Shell::command(
+ [ 'node', $IP . '/maintenance/mediawiki.Title/generateJsToUpperCaseList.js' ]
+ )
+ // Node allocates lots of memory
+ ->limits( [ 'memory' => 1024 * 1024 ] )
+ ->execute();
+
+ if ( $result->getExitcode() !== 0 ) {
+ $this->output( $result->getStderr() );
+ return;
+ }
+
+ $jsUpperChars = json_decode( $result->getStdout() );
+
+ for ( $i = 0; $i <= 0x10ffff; $i++ ) {
+ if ( $i >= 0xd800 && $i <= 0xdfff ) {
+ // Skip surrogate pairs
+ continue;
+ }
+ $char = \UtfNormal\Utils::codepointToUtf8( $i );
+ $phpUpper = $wgContLang->ucfirst( $char );
+ $jsUpper = $jsUpperChars[$i];
+ if ( $jsUpper !== $phpUpper ) {
+ $data[$char] = $phpUpper;
+ }
+ }
+
+ $mappingJson = str_replace( ' ', "\t",
+ json_encode( $data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE )
+ ) . "\n";
+ $outputPath = '/resources/src/mediawiki.Title/phpCharToUpper.json';
+ $file = fopen( $IP . $outputPath, 'w' );
+ fwrite( $file, $mappingJson );
+
+ $this->output( count( $data ) . " differences found.\n" );
+ $this->output( "Written to $outputPath\n" );
}
}
-echo str_replace( ' ', "\t",
- json_encode( $data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE )
-) . "\n";
+$maintClass = GeneratePhpCharToUpperMappings::class;
+require_once RUN_MAINTENANCE_IF_MAIN;
],
'mediawiki.content.json' => [
'styles' => 'resources/src/mediawiki.content.json.less',
+ 'targets' => [ 'desktop', 'mobile' ],
],
'mediawiki.confirmCloseWindow' => [
'scripts' => [
*
* @constructor
* @param {Object} [config] Configuration options
- * @cfg {boolean} [pushPending=false] Visually mark the input field as "pending", while
- * requesting suggestions.
* @cfg {boolean} [performSearchOnClick=true] If true, the script will start a search when-
* ever a user hits a suggestion. If false, the text of the suggestion is inserted into the
* text field only.
config = $.extend( {
icon: 'search',
maxLength: undefined,
+ showPendingRequest: false,
performSearchOnClick: true,
dataLocation: 'header'
}, config );
this.$element.addClass( 'mw-widget-searchInputWidget' );
this.lookupMenu.$element.addClass( 'mw-widget-searchWidget-menu' );
this.lastLookupItems = [];
- if ( !config.pushPending ) {
- this.pushPending = false;
- }
if ( config.dataLocation ) {
this.dataLocation = config.dataLocation;
}
<?php
+use Wikimedia\Rdbms\IDatabase;
use Wikimedia\Rdbms\LoadBalancer;
use Wikimedia\TestingAccessWrapper;
}
/**
- * @return PHPUnit_Framework_MockObject_MockObject|Database
+ * @return PHPUnit_Framework_MockObject_MockObject|IDatabase
*/
private function getMockDb() {
- $mock = $this->getMockBuilder( Database::class )
- ->disableOriginalConstructor()
- ->getMock();
+ $mock = $this->createMock( IDatabase::class );
$mock->expects( $this->any() )
->method( 'makeList' )
}
/**
- * @param PHPUnit_Framework_MockObject_MockObject|Database $mockDb
+ * @param PHPUnit_Framework_MockObject_MockObject|IDatabase $mockDb
* @return PHPUnit_Framework_MockObject_MockObject|LoadBalancer
*/
private function getMockLoadBalancer( $mockDb ) {
}
/**
- * @param PHPUnit_Framework_MockObject_MockObject|Database $mockDb
* @return PHPUnit_Framework_MockObject_MockObject|WatchedItemStore
*/
private function getMockWatchedItemStore() {