* (T112474) Generalized the ResourceLoader mechanism for overriding modules
using a particular page during edit previews.
* Added 'ApiParseMakeOutputPage' hook.
+* (T174313) Added checkbox on Special:ListUsers to display only users in temporary
+ user groups.
=== External library changes in 1.32 ===
* …
* Overriding SearchEngine::{searchText,searchTitle,searchArchiveTitle}
in extending classes is deprecated. Extend related doSearch* methods
instead.
+* CollationFa has been removed completely as it's not needed anymore
=== Other changes in 1.32 ===
* Soft hyphens (U+00AD) are now automatically removed from titles; these
'Collation' => __DIR__ . '/includes/collation/Collation.php',
'CollationCkb' => __DIR__ . '/includes/collation/CollationCkb.php',
'CollationEt' => __DIR__ . '/includes/collation/CollationEt.php',
- 'CollationFa' => __DIR__ . '/includes/collation/CollationFa.php',
'CommandLineInc' => __DIR__ . '/maintenance/commandLine.inc',
'CommandLineInstaller' => __DIR__ . '/maintenance/install.php',
'CommentStore' => __DIR__ . '/includes/CommentStore.php',
$rlClient = new ResourceLoaderClientHtml( $context, [
'target' => $this->getTarget(),
+ 'nonce' => $this->getCSPNonce(),
] );
$rlClient->setConfig( $this->getJSVars() );
$rlClient->setModules( $this->getModules( /*filter*/ true ) );
}
$pieces[] = Html::element( 'title', null, $this->getHTMLTitle() );
- $pieces[] = $this->getRlClient()->getHeadHtml( $this->getCSPNonce() );
+ $pieces[] = $this->getRlClient()->getHeadHtml();
$pieces[] = $this->buildExemptModules();
$pieces = array_merge( $pieces, array_values( $this->getHeadLinksArray() ) );
$pieces = array_merge( $pieces, array_values( $this->mHeadItems ) );
return new CollationCkb;
case 'xx-uca-et':
return new CollationEt;
- case 'xx-uca-fa':
- return new CollationFa;
case 'uppercase-ab':
return new AbkhazUppercaseCollation;
case 'uppercase-ba':
+++ /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
- */
-
-/**
- * Temporary workaround for incorrect collation of Persian language ('fa') in ICU 52 (bug T139110).
- *
- * Replace with other letters that appear in an okish spot in the alphabet
- *
- * - Characters 'و' 'ا' (often appear at the beginning of words)
- * - Characters 'ٲ' 'ٳ' (may appear at the beginning of words in loanwords)
- *
- * @since 1.29
- */
-class CollationFa extends IcuCollation {
-
- // Really hacky - replace with stuff from other blocks.
- private $override = [
- // U+0627 ARABIC LETTER ALEF => U+0623 ARABIC LETTER ALEF WITH HAMZA ABOVE
- "\xd8\xa7" => "\xd8\xa3",
- // U+0648 ARABIC LETTER WAW => U+0649 ARABIC LETTER ALEF MAKSURA
- "\xd9\x88" => "\xd9\x89",
- // U+0672 ARABIC LETTER ALEF WITH WAVY HAMZA ABOVE => U+F3001 (private use area)
- "\xd9\xb2" => "\xF3\xB3\x80\x81",
- // U+0673 ARABIC LETTER ALEF WITH WAVY HAMZA BELOW => U+F3002 (private use area)
- "\xd9\xb3" => "\xF3\xB3\x80\x82",
- ];
-
- public function __construct() {
- parent::__construct( 'fa' );
- }
-
- public function getSortKey( $string ) {
- $modified = strtr( $string, $this->override );
- return parent::getSortKey( $modified );
- }
-
- public function getFirstLetter( $string ) {
- if ( isset( $this->override[substr( $string, 0, 2 )] ) ) {
- return substr( $string, 0, 2 );
- }
- return parent::getFirstLetter( $string );
- }
-}
* startup module if the client has adequate support for MediaWiki JavaScript code.
*
* @param string $script JavaScript code
- * @param string $nonce Content-security-policy nonce, from OutputPage::getCSPNonce()
+ * @param string $nonce [optional] Content-Security-Policy nonce (from OutputPage::getCSPNonce)
* @return WrappedString HTML
*/
public static function makeInlineScript( $script, $nonce = null ) {
* @param ResourceLoaderContext $context
* @param array $options [optional] Array of options
* - 'target': Custom parameter passed to StartupModule.
+ * - 'nonce': From OutputPage::getCSPNonce().
*/
public function __construct( ResourceLoaderContext $context, array $options = [] ) {
$this->context = $context;
$this->resourceLoader = $context->getResourceLoader();
- $this->options = $options;
+ $this->options = $options + [
+ 'target' => null,
+ 'nonce' => null,
+ ];
}
/**
* - Inline scripts can't be asynchronous.
* - For styles, earlier is better.
*
- * @param string $nonce From OutputPage::getCSPNonce()
* @return string|WrappedStringList HTML
*/
- public function getHeadHtml( $nonce ) {
+ public function getHeadHtml() {
+ $nonce = $this->options['nonce'];
$data = $this->getData();
$chunks = [];
// Async scripts. Once the startup is loaded, inline RLQ scripts will run.
// Pass-through a custom 'target' from OutputPage (T143066).
- $startupQuery = isset( $this->options['target'] )
+ $startupQuery = $this->options['target'] !== null
? [ 'target' => (string)$this->options['target'] ]
: [];
$chunks[] = $this->getLoad(
* @param ResourceLoaderContext $mainContext
* @param array $modules One or more module names
* @param string $only ResourceLoaderModule TYPE_ class constant
- * @param array $extraQuery Array with extra query parameters for the request
- * @param string $nonce See OutputPage::getCSPNonce() [Since 1.32]
+ * @param array $extraQuery [optional] Array with extra query parameters for the request
+ * @param string $nonce [optional] Content-Security-Policy nonce (from OutputPage::getCSPNonce)
* @return string|WrappedStringList HTML
*/
public static function makeLoad( ResourceLoaderContext $mainContext, array $modules, $only,
- array $extraQuery, $nonce
+ array $extraQuery = [], $nonce = null
) {
$rl = $mainContext->getResourceLoader();
$chunks = [];
$this->outputHeader();
$this->getOutput()->allowClickjacking();
$this->getOutput()->addHTML(
- Html::openElement( 'table', [ 'class' => 'mw-datatable',
+ Html::openElement( 'table', [ 'class' => 'mw-datatable sortable',
'id' => 'mw-trackingcategories-table' ] ) . "\n" .
"<thead><tr>
<th>" .
if ( $hidelinks || $hidetrans || $hideredirs || $hideimages ) {
$out->addHTML( $this->getFilterPanel() );
}
- $errMsg = is_int( $namespace ) ? 'nolinkshere-ns' : 'nolinkshere';
- $out->addWikiMsg( $errMsg, $this->target->getPrefixedText() );
+ $msgKey = is_int( $namespace ) ? 'nolinkshere-ns-2' : 'nolinkshere-2';
+ $link = $this->getLinkRenderer()->makeKnownLink(
+ $this->target,
+ null,
+ [],
+ $this->target->isRedirect() ? [ 'redirect' => 'no' ] : []
+ );
+
+ $errMsg = $this->msg( $msgKey )->rawParams( $link )->parseAsBlock();
+ $out->addHTML( $errMsg );
$out->setStatusCode( 404 );
}
}
if ( !$this->including() ) {
$out->addHTML( $this->whatlinkshereForm() );
$out->addHTML( $this->getFilterPanel() );
- $out->addWikiMsg( 'linkshere', $this->target->getPrefixedText() );
+
+ $link = $this->getLinkRenderer()->makeKnownLink(
+ $this->target,
+ null,
+ [],
+ $this->target->isRedirect() ? [ 'redirect' => 'no' ] : []
+ );
+
+ $msg = $this->msg( 'linkshere-2' )->rawParams( $link )->parseAsBlock();
+ $out->addHTML( $msg );
$prevnext = $this->getPrevNext( $prevId, $nextId );
$out->addHTML( $prevnext );
$this->requestedGroup = '';
}
$this->editsOnly = $request->getBool( 'editsOnly' );
+ $this->temporaryGroupsOnly = $request->getBool( 'temporaryGroupsOnly' );
$this->creationSort = $request->getBool( 'creationSort' );
$this->including = $including;
$this->mDefaultDirection = $request->getBool( 'desc' )
$options = [];
+ if ( $this->requestedGroup != '' || $this->temporaryGroupsOnly ) {
+ $conds[] = 'ug_expiry >= ' . $dbr->addQuotes( $dbr->timestamp() ) .
+ ( !$this->temporaryGroupsOnly ? ' OR ug_expiry IS NULL' : '' );
+ }
+
if ( $this->requestedGroup != '' ) {
$conds['ug_group'] = $this->requestedGroup;
- $conds[] = 'ug_expiry IS NULL OR ug_expiry >= ' . $dbr->addQuotes( $dbr->timestamp() );
}
if ( $this->requestedUser != '' ) {
'id' => 'editsOnly',
'default' => $this->editsOnly
],
+ 'temporaryGroupsOnly' => [
+ 'type' => 'check',
+ 'label' => $this->msg( 'listusers-temporarygroupsonly' )->text(),
+ 'name' => 'temporaryGroupsOnly',
+ 'id' => 'temporaryGroupsOnly',
+ 'default' => $this->temporaryGroupsOnly
+ ],
'creationSort' => [
'type' => 'check',
'label' => $this->msg( 'listusers-creationsort' )->text(),
'li' => 'Limburgs', # Limburgian
'lij' => 'Ligure', # Ligurian
'liv' => 'Līvõ kēļ', # Livonian
- 'lki' => 'لەکی', # Laki
+ 'lki' => 'لەکی', # Laki
'lmo' => 'lumbaart', # Lombard
'ln' => 'lingála', # Lingala
'lo' => 'ລາວ', # Laotian
"listusers": "User list",
"listusers-summary": "",
"listusers-editsonly": "Show only users with edits",
+ "listusers-temporarygroupsonly": "Show only users in temporary user groups",
"listusers-creationsort": "Sort by creation date",
"listusers-desc": "Sort in descending order",
"usereditcount": "$1 {{PLURAL:$1|edit|edits}}",
"whatlinkshere-title": "Pages that link to \"$1\"",
"whatlinkshere-summary": "",
"whatlinkshere-page": "Page:",
- "linkshere": "The following pages link to <strong>[[:$1]]</strong>:",
- "nolinkshere": "No pages link to <strong>[[:$1]]</strong>.",
- "nolinkshere-ns": "No pages link to <strong>[[:$1]]</strong> in the chosen namespace.",
+ "linkshere-2": "The following pages link to <strong>$1</strong>:",
+ "nolinkshere-2": "No pages link to <strong>$1</strong>.",
+ "nolinkshere-ns-2": "No pages link to <strong>$1</strong> in the chosen namespace.",
"isredirect": "redirect page",
"istemplate": "transclusion",
"isimage": "file link",
"listusers": "{{doc-special|ListUsers}}",
"listusers-summary": "{{notranslate}}\nThe summary displayed at the top of [[Special:Listusers]]. [[mw:Manual:Interface/Special pages summary|mw manual]].",
"listusers-editsonly": "Option in [[Special:ListUsers]].",
+ "listusers-temporarygroupsonly": "Option in [[Special:ListUsers]].",
"listusers-creationsort": "Option in [[Special:ListUsers]].",
"listusers-desc": "Used as label for the checkbox on [[Special:ListUsers]].",
"usereditcount": "Shown behind every username on [[Special:ListUsers]]. Parameters:\n* $1 - number of edits",
"whatlinkshere-title": "Title of the special page [[Special:WhatLinksHere]]. This page appears when you click on the 'What links here' button in the toolbox. $1 is the name of the page concerned.",
"whatlinkshere-summary": "{{doc-specialpagesummary|whatlinkshere}}",
"whatlinkshere-page": "{{Identical|Page}}",
- "linkshere": "This message is the header line of the [[Special:WhatLinksHere/$1]] page generated by clicking \"What links here\" in the sidebar toolbox.\n\nIt is followed by a navigation bar built using {{msg-mw|Viewprevnext}}.\n\nParameters:\n* $1 - page title",
- "nolinkshere": "Used in [[Special:WhatLinksHere]] if empty. Parameters:\n* $1 - page title\nSee also:\n* {{msg-mw|Nolinkshere-ns}}",
- "nolinkshere-ns": "Used in [[Special:WhatLinksHere]] if empty. Parameters:\n* $1 - page title\nSee also:\n* {{msg-mw|Nolinkshere}}",
+ "linkshere-2": "This message is the header line of the [[Special:WhatLinksHere/$1]] page generated by clicking \"What links here\" in the sidebar toolbox.\n\nIt is followed by a navigation bar built using {{msg-mw|Viewprevnext}}.\n\nParameters:\n* $1 - HTML link to the page.",
+ "nolinkshere-2": "Used in [[Special:WhatLinksHere]] if empty. Parameters:\n* $1 - HTML link to the page\nSee also:\n* {{msg-mw|Nolinkshere-ns-html}}",
+ "nolinkshere-ns-2": "Used in [[Special:WhatLinksHere]] if empty. Parameters:\n* $1 - HTML link to the page\nSee also:\n* {{msg-mw|Nolinkshere-html}}",
"isredirect": "Displayed in [[Special:WhatLinksHere]] (see [{{fullurl:Special:WhatLinksHere/Project:Translator|hidelinks=1}} Special:WhatLinksHere/Project:Translator] for example).\n\n{{Identical|Redirect page}}",
"istemplate": "Means that a page (a template, specifically) is used as <code><nowiki>{{Page name}}</nowiki></code>.\nDisplayed in [[Special:WhatLinksHere]] (see [[Special:WhatLinksHere/Template:New portal]] for example).\nIf you are not sure how to translate this term, think of something like \"inclusion\", \"embedding\", or \"insertion\".\n{{Identical|Transclusion}}",
"isimage": "This message is displayed on [[Special:WhatLinksHere]] for images. It means that the image is used on the page (as opposed to just being linked to like an non-image page).\n{{Identical|File link}}",
+++ /dev/null
-<?php
-
-/**
- * @covers CollationFa
- */
-class CollationFaTest extends MediaWikiTestCase {
-
- /*
- * The ordering is a weird hack designed to work only with a very
- * specific version of libicu, and as such can't really be unit tested
- * against a random version of libicu
- */
-
- public function setUp() {
- parent::setUp();
- $this->checkPHPExtension( 'intl' );
- }
-
- /**
- * @dataProvider provideGetFirstLetter
- */
- public function testGetFirstLetter( $letter, $str ) {
- $coll = new CollationFa;
- $this->assertEquals( $letter, $coll->getFirstLetter( $str ), $str );
- }
-
- public function provideGetFirstLetter() {
- return [
- [
- '۷',
- '۷'
- ],
- [
- 'ا',
- 'ا'
- ],
- [
- 'ا',
- 'ایران'
- ],
- [
- 'ب',
- 'برلین'
- ],
- [
- 'و',
- 'واو'
- ],
- [ "\xd8\xa7", "\xd8\xa7Foo" ],
- [ "\xd9\x88", "\xd9\x88Foo" ],
- [ "\xd9\xb2", "\xd9\xb2Foo" ],
- [ "\xd9\xb3", "\xd9\xb3Foo" ],
- ];
- }
-}
$context = self::makeContext();
$context->getResourceLoader()->register( self::makeSampleModules() );
- $client = new ResourceLoaderClientHtml( $context );
+ $client = new ResourceLoaderClientHtml( $context, [
+ 'nonce' => false,
+ ] );
$client->setConfig( [ 'key' => 'value' ] );
$client->setModules( [
'test',
// phpcs:enable
$expected = self::expandVariables( $expected );
- $this->assertEquals( $expected, $client->getHeadHtml( false ) );
+ $this->assertEquals( $expected, $client->getHeadHtml() );
}
/**
. '<script async="" src="/w/load.php?debug=false&lang=nl&modules=startup&only=scripts&skin=fallback&target=example"></script>';
// phpcs:enable
- $this->assertEquals( $expected, $client->getHeadHtml( false ) );
+ $this->assertEquals( $expected, $client->getHeadHtml() );
}
/**
. '<script async="" src="/w/load.php?debug=false&lang=nl&modules=startup&only=scripts&skin=fallback"></script>';
// phpcs:enable
- $this->assertEquals( $expected, $client->getHeadHtml( false ) );
+ $this->assertEquals( $expected, $client->getHeadHtml() );
}
/**