[ 'ar_rev_id' => $revids ],
__METHOD__
),
- ], false );
+ ], $db::UNION_DISTINCT );
$res = $db->query( $sql, __METHOD__ );
foreach ( $res as $row ) {
if ( (int)$row->id === (int)$params['startid'] ) {
*/
const QUERY_PSEUDO_PERMANENT = 2;
+ /** @var bool Parameter to unionQueries() for UNION ALL */
+ const UNION_ALL = true;
+ /** @var bool Parameter to unionQueries() for UNION DISTINCT */
+ const UNION_DISTINCT = false;
+
/**
* A string describing the current software version, and possibly
* other details in a user-friendly way. Will be listed on Special:Version, etc.
* This is used for providing overload point for other DB abstractions
* not compatible with the MySQL syntax.
* @param array $sqls SQL statements to combine
- * @param bool $all Use UNION ALL
+ * @param bool $all Either IDatabase::UNION_ALL or IDatabase::UNION_DISTINCT
* @return string SQL fragment
*/
public function unionQueries( $sqls, $all );
$links = '';
if ( $talk ) {
$tools = self::getUserLinks( $this, $userObj );
- $links = $this->getLanguage()->pipeList( $tools );
+ $links = Html::openElement( 'span', [ 'class' => 'mw-changeslist-links' ] );
+ foreach ( $tools as $tool ) {
+ $links .= Html::rawElement( 'span', [], $tool ) . ' ';
+ }
+ $links = trim( $links ) . Html::closeElement( 'span' );
// Show a note if the user is blocked and display the last block log entry.
// Do not expose the autoblocks, since that may lead to a leak of accounts' IPs,
}
return Html::rawElement( 'div', [ 'class' => 'mw-contributions-user-tools' ],
- $this->msg( 'contribsub2' )->rawParams( $user, $links )->params( $userObj->getName() )
+ $this->msg( 'contributions-subtitle' )->rawParams( $user )->params( $userObj->getName() )
+ . ' ' . $links
);
}
$sql = $subsql[0];
} else {
// need to resort and relimit after union
- $sql = $dbr->unionQueries( $subsql, false ) . ' ORDER BY rc_timestamp DESC';
+ $sql = $dbr->unionQueries( $subsql, $dbr::UNION_DISTINCT ) .
+ ' ORDER BY rc_timestamp DESC';
$sql = $dbr->limitResult( $sql, $limit, false );
}
"mycontris": "Contributions",
"anoncontribs": "Contributions",
"contribsub2": "For {{GENDER:$3|$1}} ($2)",
+ "contributions-subtitle": "For {{GENDER:$3|$1}}",
"contributions-userdoesnotexist": "User account \"$1\" is not registered.",
"negative-namespace-not-supported": "Namespaces with negative values are not supported.",
"nocontribs": "No changes were found matching these criteria.",
"mycontris": "In the personal urls page section - right upper corner.\n\nSee also:\n* {{msg-mw|Mycontris}}\n* {{msg-mw|Accesskey-pt-mycontris}}\n* {{msg-mw|Tooltip-pt-mycontris}}\n{{Identical|Contribution}}",
"anoncontribs": "Same as {{msg-mw|mycontris}} but used for non-logged-in users.\n\nSee also:\n* {{msg-mw|Accesskey-pt-anoncontribs}}\n* {{msg-mw|Tooltip-pt-anoncontribs}}\n{{Identical|Contribution}}",
"contribsub2": "Contributions for \"user\" (links). Parameters:\n* $1 is an IP address or a username, with a link which points to the user page (if registered user).\n* $2 is list of tool links. The list contains a link which has text {{msg-mw|Sp-contributions-talk}}.\n* $3 is a plain text username used for GENDER.\n{{Identical|For $1}}",
+ "contributions-subtitle": "Successor to {{msg-mw|contribssub2}}. Contributions for \"user\". Parameters:\n* $1 is an IP address or a username, with a link which points to the user page (if registered user).\n",
"contributions-userdoesnotexist": "This message is used in [[Special:Contributions]]. It is used to tell the user that the name he searched for doesn't exist.\n\nParameters:\n* $1 - a username\n{{Identical|Userdoesnotexist}}",
"negative-namespace-not-supported": "This message is used in [[Special:Contributions]] to tell users that use namespaces with negative value. It not supported as associated namespace(s) doesn't exist.",
"nocontribs": "Used in [[Special:Contributions]] and [[Special:DeletedContributions]].\n\nSee examples: [[Special:Contributions/x]] and [[Special:DeletedContributions/x]].\n\nParameters:\n* $1 - (Unused) the user name",
$oiWheres ? $dbr->makeList( $oiWheres, LIST_OR ) : '1=0'
)
],
- true // UNION ALL (performance)
+ $dbr::UNION_ALL
),
__METHOD__
);
--- /dev/null
+/* eslint-env node, es6 */
+var i, chars = [];
+
+for ( i = 0; i < 65536; i++ ) {
+ chars.push( String.fromCharCode( i ).toUpperCase() );
+}
+// eslint-disable-next-line no-console
+console.log( JSON.stringify( chars ) );
--- /dev/null
+#!/usr/bin/env php
+<?php
+/**
+ * Utility to generate mapping file used in phpCharToUpper.js
+ *
+ * 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.
+ */
+
+$data = [];
+
+// phpcs:disable MediaWiki.Usage.ForbiddenFunctions.exec
+$jsUpperChars = json_decode( exec( 'node generateJsToUpperCaseList.js' ) );
+// phpcs:enable MediaWiki.Usage.ForbiddenFunctions.exec
+
+for ( $i = 0; $i < 65536; $i++ ) {
+ if ( $i >= 0xd800 && $i <= 0xdfff ) {
+ // Skip surrogate pairs
+ continue;
+ }
+ $char = mb_convert_encoding( '&#' . $i . ';', 'UTF-8', 'HTML-ENTITIES' );
+ $phpUpper = mb_strtoupper( $char );
+ $jsUpper = $jsUpperChars[$i];
+ if ( $jsUpper !== $phpUpper ) {
+ $data[$char] = $phpUpper;
+ }
+}
+
+echo 'var toUpperMapping = ' . str_replace( '"', "'",
+ str_replace( ' ', "\t",
+ json_encode( $data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE )
+ )
+) . ";\n";
'skinStyles' => [
'default' => 'resources/src/mediawiki.action/mediawiki.action.history.styles.css',
],
+ 'targets' => [ 'desktop', 'mobile' ],
],
'mediawiki.action.view.dblClickEdit' => [
'scripts' => 'resources/src/mediawiki.action/mediawiki.action.view.dblClickEdit.js',