<exclude-pattern>*/includes/jobqueue/JobSpecification\.php</exclude-pattern>
<exclude-pattern>*/includes/RevisionList\.php</exclude-pattern>
<exclude-pattern>*/includes/installer/PhpBugTests\.php</exclude-pattern>
- <exclude-pattern>*/includes/exception/LocalizedException\.php</exclude-pattern>
<exclude-pattern>*/includes/specials/SpecialMostinterwikis\.php</exclude-pattern>
<exclude-pattern>*/includes/cache/CacheDependency\.php</exclude-pattern>
<exclude-pattern>*/includes/cache/CacheHelper\.php</exclude-pattern>
<exclude-pattern>*/includes/deferred/CdnCacheUpdate\.php</exclude-pattern>
<exclude-pattern>*/includes/diff/DairikiDiff\.php</exclude-pattern>
<exclude-pattern>*/includes/diff/DiffEngine\.php</exclude-pattern>
- <exclude-pattern>*/includes/exception/LocalizedException\.php</exclude-pattern>
<exclude-pattern>*/includes/Feed\.php</exclude-pattern>
<exclude-pattern>*/includes/filerepo/file/LocalFile\.php</exclude-pattern>
<exclude-pattern>*/includes/gallery/PackedOverlayImageGallery\.php</exclude-pattern>
* (T209699) The jquery.async module has been deprecated. JavaScript code that
needs asynchronous behaviour should use Promises.
* Password::equals() is deprecated, use verify().
+* BaseTemplate::msgWiki() and QuickTemplate::msgWiki() will be removed. Use
+ other means to fetch a properly escaped message string or Message object.
=== Other changes in 1.33 ===
* (T208871) The hard-coded Google search form on the database error page was
'IEUrlExtension' => __DIR__ . '/includes/libs/IEUrlExtension.php',
'IExpiringStore' => __DIR__ . '/includes/libs/objectcache/IExpiringStore.php',
'IJobSpecification' => __DIR__ . '/includes/jobqueue/JobSpecification.php',
- 'ILocalizedException' => __DIR__ . '/includes/exception/LocalizedException.php',
+ 'ILocalizedException' => __DIR__ . '/includes/exception/ILocalizedException.php',
'IMaintainableDatabase' => __DIR__ . '/includes/libs/rdbms/database/IMaintainableDatabase.php',
'IP' => __DIR__ . '/includes/libs/IP.php',
'IPTC' => __DIR__ . '/includes/media/IPTC.php',
--- /dev/null
+<?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
+ *
+ * @file
+ */
+
+/**
+ * Interface for MediaWiki-localized exceptions
+ *
+ * @since 1.29
+ * @ingroup Exception
+ */
+interface ILocalizedException {
+ /**
+ * Return a Message object for this exception
+ * @return Message
+ */
+ public function getMessageObject();
+}
* @file
*/
-/**
- * Interface for MediaWiki-localized exceptions
- *
- * @since 1.29
- * @ingroup Exception
- */
-interface ILocalizedException {
- /**
- * Return a Message object for this exception
- * @return Message
- */
- public function getMessageObject();
-}
-
/**
* Basic localized exception.
*
/**
* @param string $str
* @warning You should never use this method. I18n messages should be escaped
- * @deprecated 1.32 Use ->msg() or ->msgWiki() instead.
+ * @deprecated 1.32 Use ->msg() or ->getMsg() instead.
* @suppress SecurityCheck-XSS
* @return-taint exec_html
*/
echo $this->getMsg( $str )->text();
}
+ /**
+ * @deprecated since 1.33 Use ->msg() or ->getMsg() instead.
+ */
function msgWiki( $str ) {
+ // TODO: Add wfDeprecated( __METHOD__, '1.33' ) after 1.33 got released
echo $this->getMsg( $str )->parseAsBlock();
}
* @private
* @param string $msgKey
* @warning You should never use this method. I18n messages should be escaped
- * @deprecated 1.32 Use ->msg() or ->msgWiki() instead.
+ * @deprecated 1.32 Use ->msg() instead.
* @suppress SecurityCheck-XSS
* @return-taint exec_html
*/
/**
* An ugly, ugly hack.
- * @private
+ * @deprecated since 1.33 Use ->msg() instead.
* @param string $msgKey
*/
function msgWiki( $msgKey ) {
+ // TODO: Add wfDeprecated( __METHOD__, '1.33' ) after 1.33 got released
global $wgOut;
$text = wfMessage( $msgKey )->plain();
* @param string $mediaType
*/
protected function outputTableStart( $mediaType ) {
- $this->getOutput()->addHTML(
+ $out = $this->getOutput();
+ $out->addModuleStyles( 'jquery.tablesorter.styles' );
+ $out->addModules( 'jquery.tablesorter' );
+ $out->addHTML(
Html::openElement(
'table',
[ 'class' => [
}
}
+ $out->addModuleStyles( 'jquery.tablesorter.styles' );
+ $out->addModules( 'jquery.tablesorter' );
$out->addHTML( Xml::tags(
'table',
[ 'class' => 'mw-datatable sortable mw-tags-table' ],
$this->setHeaders();
$this->outputHeader();
$this->getOutput()->allowClickjacking();
+ $this->getOutput()->addModuleStyles( 'jquery.tablesorter.styles' );
+ $this->getOutput()->addModules( 'jquery.tablesorter' );
$this->getOutput()->addHTML(
Html::openElement( 'table', [ 'class' => 'mw-datatable sortable',
'id' => 'mw-trackingcategories-table' ] ) . "\n" .
die( "This script can only be run from the command line.\n" );
}
+// class Collator is provided by the intl extension.
+// It is only suggested in composer.json, so remind here when not loaded.
+if ( !extension_loaded( 'intl' ) ) {
+ die( "This script needs the 'intl' extension to be loaded." );
+}
+
$CREDITS = 'CREDITS';
$START_CONTRIBUTORS = '<!-- BEGIN CONTRIBUTOR LIST -->';
$END_CONTRIBUTORS = '<!-- END CONTRIBUTOR LIST -->';
"selenium-test": "wdio ./tests/selenium/wdio.conf.js"
},
"devDependencies": {
- "eslint-config-wikimedia": "0.10.0",
+ "eslint-config-wikimedia": "0.10.1",
"grunt": "1.0.3",
"grunt-banana-checker": "0.6.0",
"grunt-contrib-copy": "1.0.0",
'jquery.tablesorter' => [
'targets' => [ 'desktop', 'mobile' ],
'scripts' => 'resources/src/jquery.tablesorter/jquery.tablesorter.js',
- 'styles' => 'resources/src/jquery.tablesorter/jquery.tablesorter.less',
'messages' => [ 'sort-descending', 'sort-ascending' ],
'dependencies' => [
+ 'jquery.tablesorter.styles',
'mediawiki.RegExp',
'mediawiki.language.months',
],
],
+ 'jquery.tablesorter.styles' => [
+ 'targets' => [ 'desktop', 'mobile' ],
+ 'styles' => 'resources/src/jquery.tablesorter.styles/jquery.tablesorter.styles.less',
+ ],
'jquery.textSelection' => [
'scripts' => 'resources/src/jquery/jquery.textSelection.js',
'dependencies' => 'jquery.client',
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="21" height="9" viewBox="0 0 21 9">
+ <path d="M14.5 5l-4 4-4-4zM14.5 4l-4-4-4 4z"/>
+</svg>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="21" height="4" viewBox="0 0 21 4">
+ <path d="M14.5 0l-4 4-4-4z"/>
+</svg>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="21" height="4" viewBox="0 0 21 4">
+ <path d="M6.5 4l4-4 4 4z"/>
+</svg>
--- /dev/null
+@import 'mediawiki.mixins';
+
+/* Table Sorting */
+
+.client-js .sortable:not( .jquery-tablesorter ) > thead > :last-of-type > th:not( .unsortable ),
+.jquery-tablesorter th.headerSort {
+ .background-image-svg( 'images/sort_both.svg', 'images/sort_both.png' );
+ cursor: pointer;
+ background-repeat: no-repeat;
+ background-position: center right;
+ padding-right: 21px;
+}
+
+.jquery-tablesorter {
+ th.headerSortUp {
+ .background-image-svg( 'images/sort_up.svg', 'images/sort_up.png' );
+ }
+
+ th.headerSortDown {
+ .background-image-svg( 'images/sort_down.svg', 'images/sort_down.png' );
+ }
+}
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="21" height="9" viewBox="0 0 21 9">
- <path d="M14.5 5l-4 4-4-4zM14.5 4l-4-4-4 4z"/>
-</svg>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="21" height="4" viewBox="0 0 21 4">
- <path d="M14.5 0l-4 4-4-4z"/>
-</svg>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="21" height="4" viewBox="0 0 21 4">
- <path d="M6.5 4l4-4 4 4z"/>
-</svg>
+++ /dev/null
-@import 'mediawiki.mixins';
-
-/* Table Sorting */
-
-table.jquery-tablesorter {
- th.headerSort {
- .background-image-svg( 'images/sort_both.svg', 'images/sort_both.png' );
- cursor: pointer;
- background-repeat: no-repeat;
- background-position: center right;
- padding-right: 21px;
- }
-
- th.headerSortUp {
- .background-image-svg( 'images/sort_up.svg', 'images/sort_up.png' );
- }
-
- th.headerSortDown {
- .background-image-svg( 'images/sort_down.svg', 'images/sort_down.png' );
- }
-}
}
}
- // eslint-disable-next-line jquery/no-animate-toggle
$containers.toggle( action === 'expand' );
hookCallback();
}
// Only fetch if the value in the textbox changed and is not empty, or if the results were hidden
// if the textbox is empty then clear the result div, but leave other settings intouched
if ( val.length === 0 ) {
- // eslint-disable-next-line jquery/no-animate-toggle
$.suggestions.hide( context );
context.data.prevText = '';
} else if (
if ( context.data !== undefined ) {
if ( context.data.$textbox.val().length === 0 ) {
// Hide the div when no suggestion exist
- // eslint-disable-next-line jquery/no-animate-toggle
$.suggestions.hide( context );
} else {
// Rebuild the suggestions list
break;
// Escape
case 27:
- // eslint-disable-next-line jquery/no-animate-toggle
$.suggestions.hide( context );
$.suggestions.restore( context );
$.suggestions.cancel( context );
case 13:
preventDefault = wasVisible;
selected = context.data.$container.find( '.suggestions-result-current' );
- // eslint-disable-next-line jquery/no-animate-toggle
$.suggestions.hide( context );
if ( selected.length === 0 || context.data.selectedWithMouse ) {
// If nothing is selected or if something was selected with the mouse
// This will hide the link we're just clicking on, which causes problems
// when done synchronously in at least Firefox 3.6 (T64858).
setTimeout( function () {
- // eslint-disable-next-line jquery/no-animate-toggle
$.suggestions.hide( context );
} );
}
// This will hide the link we're just clicking on, which causes problems
// when done synchronously in at least Firefox 3.6 (T64858).
setTimeout( function () {
- // eslint-disable-next-line jquery/no-animate-toggle
$.suggestions.hide( context );
} );
}
} )
.on( 'keypress', function ( e ) {
context.data.keypressedCount++;
- // eslint-disable-next-line jquery/no-event-shorthand
$.suggestions.keypress( e, context, context.data.keypressed );
} )
.on( 'keyup', function ( e ) {
e.which === context.data.keypressed &&
allowed.indexOf( e.which ) !== -1
) {
- // eslint-disable-next-line jquery/no-event-shorthand
$.suggestions.keypress( e, context, context.data.keypressed );
}
} )
if ( context.data.mouseDownOn.length > 0 ) {
return;
}
- // eslint-disable-next-line jquery/no-animate-toggle
$.suggestions.hide( context );
$.suggestions.cancel( context );
} );
} );
}
- function humanSize( bytes ) {
+ function humanSize( bytesInput ) {
var i,
+ bytes = +bytesInput,
units = [ '', ' KiB', ' MiB', ' GiB', ' TiB', ' PiB' ];
- if ( !$.isNumeric( bytes ) || bytes === 0 ) {
- return bytes;
+ if ( bytes === 0 || isNaN( bytes ) ) {
+ return bytesInput;
}
for ( i = 0; bytes >= 1024; bytes /= 1024 ) {
$area.css( 'display', 'none' );
notif.$notification.remove();
} else {
+ // FIXME: Use CSS transition
+ // eslint-disable-next-line jquery/no-slide
notif.$notification.slideUp( 'fast', function () {
$( this ).remove();
} );
title: '', // Because it's a hidden group, this title actually appears nowhere
hidden: true,
allowArbitrary: true,
+ // FIXME: $.isNumeric is deprecated
validate: $.isNumeric,
range: {
min: 0, // The server normalizes negative numbers to 0 results
title: '', // Because it's a hidden group, this title actually appears nowhere
hidden: true,
allowArbitrary: true,
+ // FIXME: $.isNumeric is deprecated
validate: $.isNumeric,
range: {
min: 0,
* @param {number|string} newValue New value
*/
mw.rcfilters.Controller.prototype.updateNumericPreference = function ( prefName, newValue ) {
+ // FIXME: $.isNumeric is deprecated
+ // eslint-disable-next-line jquery/no-is-numeric
if ( !$.isNumeric( newValue ) ) {
return;
}
// OO.ui.ButtonWidget doesn't take focus itself (T128054)
$focus = $( '#mw-apisandbox-ui' ).find( document.activeElement );
if ( $focus.length ) {
- // eslint-disable-next-line jquery/no-event-shorthand
$focus[ 0 ].blur();
}
}
that.deprecatedItemsFieldset = new OO.ui.FieldsetLayout().addItems( deprecatedItems ).toggle( false );
- // eslint-disable-next-line jquery/no-animate-toggle
tmp = $( '<fieldset>' )
.toggle( !that.deprecatedItemsFieldset.isEmpty() )
.append(
// Dynamically show/hide the "other time" input under each dropdown
$( '.mw-userrights-nested select' ).on( 'change', function ( e ) {
- // eslint-disable-next-line jquery/no-animate-toggle
$( e.target.parentNode ).find( 'input' ).toggle( $( e.target ).val() === 'other' );
} );
$this->assertEquals( CONTENT_MODEL_WIKITEXT, $content->getContentHandler()->getModelID() );
}
+ /**
+ * @covers ParserOptions::getRedirectTarget
+ * @covers ParserOptions::setRedirectTarget
+ */
public function testRedirectParserOption() {
$title = Title::newFromText( 'testRedirectParserOption' );
return $indexes;
}
+ /**
+ * @coversNothing
+ */
public function testCaseInsensitiveLike() {
// TODO: Test this for all databases
$db = DatabaseSqlite::newStandaloneInstance( ':memory:' );
class LogstashFormatterTest extends \PHPUnit\Framework\TestCase {
/**
* @dataProvider provideV1
+ * @covers MediaWiki\Logger\Monolog\LogstashFormatter::formatV1
* @param array $record The input record.
* @param array $expected Associative array of expected keys and their values.
* @param array $notExpected List of keys that should not exist.
];
}
+ /**
+ * @covers MediaWiki\Logger\Monolog\LogstashFormatter::formatV1
+ */
public function testV1WithPrefix() {
$formatter = new LogstashFormatter( 'app', 'system', null, 'ctx_', LogstashFormatter::V1 );
$record = [ 'extra' => [ 'url' => 1 ], 'context' => [ 'url' => 2 ] ];
$this->assertSame( 'special', $cache->makeGlobalKey( 'a', 'b' ) );
}
+ /**
+ * @covers MultiWriteBagOStuff::add
+ */
public function testDuplicateStoreAdd() {
$bag = new HashBagOStuff();
$cache = new MultiWriteBagOStuff( [
$this->assertSame( 'CAST( fieldName AS SIGNED )', $output );
}
- /*
+ /**
* @covers Wikimedia\Rdbms\Database::setIndexAliases
*/
public function testIndexAliases() {
];
}
+ /**
+ * @covers Wikimedia\Rdbms\Database::insertSelect
+ * @covers Wikimedia\Rdbms\Database::nativeInsertSelect
+ */
public function testInsertSelectBatching() {
$dbWeb = new DatabaseTestHelper( __CLASS__, [ 'cliMode' => false ] );
$rows = [];
/**
* @expectedException \Wikimedia\Rdbms\DBTransactionStateError
+ * @covers \Wikimedia\Rdbms\Database::assertTransactionStatus
*/
public function testTransactionErrorState1() {
$wrapper = TestingAccessWrapper::newFromObject( $this->database );
$this->assertFieldValues( $a, $expected );
}
+ /**
+ * @covers ParserOutput::mergeInternalMetaDataFrom
+ * @covers ParserOutput::getTimes
+ * @covers ParserOutput::resetParseStartTime
+ */
public function testMergeInternalMetaDataFrom_parseStartTime() {
/** @var object $a */
$a = new ParserOutput();
/**
* @group Parser
+ * @covers MWTidy
*/
class TidyTest extends MediaWikiTestCase {
*/
class MediaWikiSiteTest extends SiteTest {
+ /**
+ * @covers MediaWikiSite::normalizePageName
+ */
public function testNormalizePageTitle() {
$this->setMwGlobals( [
'wgCapitalLinks' => true,
public function testGetFormFields() {
$this->setMwGlobals( [
'wgEnablePartialBlocks' => false,
+ 'wgBlockAllowsUTEdit' => true,
] );
$page = $this->newSpecialPage();
$wrappedPage = TestingAccessWrapper::newFromObject( $page );
public function testMaybeAlterFormDefaults() {
$this->setMwGlobals( [
'wgEnablePartialBlocks' => false,
+ 'wgBlockAllowsUTEdit' => true,
] );
$block = $this->insertBlock();