Page MenuHomePhabricator

multiple-collations.patch

Authored By
bzimport
Nov 22 2014, 12:20 AM
Size
26 KB
Referenced Files
None
Subscribers
None

multiple-collations.patch

diff --git a/includes/CategoryViewer.php b/includes/CategoryViewer.php
index dff3802..a2891f1 100644
--- a/includes/CategoryViewer.php
+++ b/includes/CategoryViewer.php
@@ -32,6 +32,11 @@ class CategoryViewer extends ContextSource {
var $collation;
/**
+ * @var Collation name
+ */
+ var $collationName;
+
+ /**
* @var ImageGallery
*/
var $gallery;
@@ -59,7 +64,7 @@ class CategoryViewer extends ContextSource {
* @param $query Array
*/
function __construct( $title, IContextSource $context, $from = '', $until = '', $query = array() ) {
- global $wgCategoryPagingLimit;
+ global $wgCategoryPagingLimit, $wgCategoryCollation;
$this->title = $title;
$this->setContext( $context );
$this->from = $from;
@@ -67,7 +72,14 @@ class CategoryViewer extends ContextSource {
$this->limit = $wgCategoryPagingLimit;
$this->cat = Category::newFromTitle( $title );
$this->query = $query;
- $this->collation = Collation::singleton();
+ if ( isset( $query['collation'] ) && in_array( $query['collation'], $wgCategoryCollation ) ) {
+ $this->collationName = $query['collation'];
+ } else if ( in_array( $context->getUser()->getOption( 'collation' ), $wgCategoryCollation ) ) {
+ $this->collationName = $context->getUser()->getOption( 'collation' );
+ } else {
+ $this->collationName = $wgCategoryCollation[0];
+ }
+ $this->collation = Collation::singleton( $this->collationName );
unset( $this->query['title'] );
}
@@ -106,6 +118,8 @@ class CategoryViewer extends ContextSource {
// Give a proper message if category is empty
if ( $r == '' ) {
$r = wfMsgExt( 'category-empty', array( 'parse' ) );
+ } else {
+ $r = $this->getCollationSelector() . $r;
}
$lang = $this->getLanguage();
@@ -285,7 +299,11 @@ class CategoryViewer extends ContextSource {
'page_is_redirect', 'cl_sortkey', 'cat_id', 'cat_title',
'cat_subcats', 'cat_pages', 'cat_files',
'cl_sortkey_prefix', 'cl_collation' ),
- array_merge( array( 'cl_to' => $this->title->getDBkey() ), $extraConds ),
+ array_merge(
+ array( 'cl_to' => $this->title->getDBkey() ),
+ array( 'cl_collation IN (' . $dbr->makeList( array( '', $this->collationName ) ) . ')' ),
+ $extraConds
+ ),
__METHOD__,
array(
'USE INDEX' => array( 'categorylinks' => 'cl_sortkey' ),
@@ -342,6 +360,42 @@ class CategoryViewer extends ContextSource {
/**
* @return string
*/
+ function getCollationSelector() {
+ global $wgCategoryCollation;
+
+ if ( count( $wgCategoryCollation ) > 1 ) {
+ $this->getContext()->getOutput()->addModules( 'mediawiki.page.category' );
+ $items = array();
+ foreach ( $wgCategoryCollation as $collation ) {
+ $items[] = Html::element( 'option', array(
+ 'value' => $collation,
+ ) + (
+ $this->collationName === $collation ? array( 'selected' ) : array()
+ ), $this->getContext()->msg( "collation-$collation" )->text() );
+ }
+ $html = Html::rawElement( 'label', array( 'for' => 'mw-collation-select' ),
+ $this->getContext()->msg( 'category-collation' ) );
+ $html .= Html::input( 'title', $this->title->getPrefixedText(), 'hidden' );
+ $html .= Html::rawElement( 'select', array(
+ 'name' => 'collation',
+ 'id' => 'mw-collation-select',
+ ), implode( $items ) );
+ $html .= Html::input( 'go', $this->getContext()->msg( 'go' )->text(), 'submit', array(
+ 'id' => 'mw-collation-go',
+ ) );
+ return Html::rawElement( 'form', array(
+ 'action' => wfScript(),
+ 'method' => 'get',
+ 'id' => 'mw-collation-selector'
+ ), $html );
+ } else {
+ return '';
+ }
+ }
+
+ /**
+ * @return string
+ */
function getSubcategorySection() {
# Don't show subcategories section if there are none.
$r = '';
diff --git a/includes/Collation.php b/includes/Collation.php
index e4ffae6..0f404d1 100644
--- a/includes/Collation.php
+++ b/includes/Collation.php
@@ -1,17 +1,26 @@
<?php
abstract class Collation {
- static $instance;
+ static $instance = array();
/**
* @return Collation
*/
- static function singleton() {
- if ( !self::$instance ) {
- global $wgCategoryCollation;
- self::$instance = self::factory( $wgCategoryCollation );
+ static function singleton( $name = null ) {
+ global $wgCategoryCollation;
+
+ if ( !isset( $name ) ) {
+ foreach ( $wgCategoryCollation as $name ) {
+ self::singleton( $name );
+ }
+ return self::$instance;
+ }
+ if ( !isset( self::$instance[$name] ) ) {
+ if ( in_array( $name, $wgCategoryCollation ) ) {
+ self::$instance[$name] = self::factory( $name );
+ }
}
- return self::$instance;
+ return self::$instance[$name];
}
/**
diff --git a/includes/DefaultSettings.php b/includes/DefaultSettings.php
index e214b7b..b728f26 100644
--- a/includes/DefaultSettings.php
+++ b/includes/DefaultSettings.php
@@ -5022,7 +5022,7 @@ $wgCategoryPagingLimit = 200;
* Extensions can define there own collations by subclassing Collation
* and using the Collation::factory hook.
*/
-$wgCategoryCollation = 'uppercase';
+$wgCategoryCollation = array( 'uppercase' );
/** @} */ # End categories }
diff --git a/includes/LinksUpdate.php b/includes/LinksUpdate.php
index 716e7d8..09dd14e 100644
--- a/includes/LinksUpdate.php
+++ b/includes/LinksUpdate.php
@@ -477,7 +477,7 @@ class LinksUpdate {
* @return array
*/
private function getCategoryInsertions( $existing = array() ) {
- global $wgContLang, $wgCategoryCollation;
+ global $wgContLang;
$diffs = array_diff_assoc( $this->mCategories, $existing );
$arr = array();
foreach ( $diffs as $name => $prefix ) {
@@ -492,22 +492,24 @@ class LinksUpdate {
$type = 'page';
}
- # Treat custom sortkeys as a prefix, so that if multiple
- # things are forced to sort as '*' or something, they'll
- # sort properly in the category rather than in page_id
- # order or such.
- $sortkey = Collation::singleton()->getSortKey(
- $this->mTitle->getCategorySortkey( $prefix ) );
+ foreach ( Collation::singleton() as $collationName => $collation ) {
+ # Treat custom sortkeys as a prefix, so that if multiple
+ # things are forced to sort as '*' or something, they'll
+ # sort properly in the category rather than in page_id
+ # order or such.
+ $sortkey = $collation->getSortKey(
+ $this->mTitle->getCategorySortkey( $prefix ) );
- $arr[] = array(
- 'cl_from' => $this->mId,
- 'cl_to' => $name,
- 'cl_sortkey' => $sortkey,
- 'cl_timestamp' => $this->mDb->timestamp(),
- 'cl_sortkey_prefix' => $prefix,
- 'cl_collation' => $wgCategoryCollation,
- 'cl_type' => $type,
- );
+ $arr[] = array(
+ 'cl_from' => $this->mId,
+ 'cl_to' => $name,
+ 'cl_sortkey' => $sortkey,
+ 'cl_timestamp' => $this->mDb->timestamp(),
+ 'cl_sortkey_prefix' => $prefix,
+ 'cl_collation' => $collationName,
+ 'cl_type' => $type,
+ );
+ }
}
return $arr;
}
diff --git a/includes/Preferences.php b/includes/Preferences.php
index bc8e47f..e140c71 100644
--- a/includes/Preferences.php
+++ b/includes/Preferences.php
@@ -134,9 +134,9 @@ class Preferences {
*/
static function profilePreferences( $user, IContextSource $context, &$defaultPreferences ) {
global $wgAuth, $wgContLang, $wgParser, $wgCookieExpiration, $wgLanguageCode,
- $wgDisableTitleConversion, $wgDisableLangConversion, $wgMaxSigChars,
- $wgEnableEmail, $wgEmailConfirmToEdit, $wgEnableUserEmail, $wgEmailAuthentication,
- $wgEnotifWatchlist, $wgEnotifUserTalk, $wgEnotifRevealEditorAddress;
+ $wgDisableTitleConversion, $wgDisableLangConversion, $wgMaxSigChars, $wgEnableEmail,
+ $wgEmailConfirmToEdit, $wgEnableUserEmail, $wgEmailAuthentication, $wgEnotifWatchlist,
+ $wgEnotifUserTalk, $wgEnotifRevealEditorAddress, $wgCategoryCollation;
## User info #####################################
// Information panel
@@ -297,6 +297,21 @@ class Preferences {
}
}
+ /* Check if there are more than one collations configured on this site */
+ if ( count( $wgCategoryCollation ) > 1 ) {
+ $options = array();
+ foreach ( $wgCategoryCollation as $collation ) {
+ $options[$context->msg( "collation-$collation" )->text()] = $collation;
+ }
+ $defaultPreferences['collation'] = array(
+ 'label-message' => 'prefs-collation',
+ 'type' => 'select',
+ 'options' => $options,
+ 'section' => 'personal/i18n',
+ 'help-message' => 'prefs-help-collation',
+ );
+ }
+
if ( count( $variantArray ) > 1 && !$wgDisableLangConversion && !$wgDisableTitleConversion ) {
$defaultPreferences['noconvertlink'] =
array(
diff --git a/includes/Setup.php b/includes/Setup.php
index 2777f73..afe3668 100644
--- a/includes/Setup.php
+++ b/includes/Setup.php
@@ -348,6 +348,14 @@ if ( $wgAjaxUploadDestCheck ) {
$wgAjaxExportList[] = 'SpecialUpload::ajaxGetExistsWarning';
}
+if ( !is_array( $wgCategoryCollation ) ) {
+ $wgCategoryCollation = array( $wgCategoryCollation );
+}
+
+if ( !isset( $wgDefaultUserOptions['collation'] ) ) {
+ $wgDefaultUserOptions['collation'] = $wgCategoryCollation[0];
+}
+
if ( $wgNewUserLog ) {
# Add a new log type
$wgLogTypes[] = 'newusers';
diff --git a/includes/Title.php b/includes/Title.php
index 769adb9..09c1e4a 100644
--- a/includes/Title.php
+++ b/includes/Title.php
@@ -3499,16 +3499,22 @@ class Title {
foreach ( $prefixes as $prefixRow ) {
$prefix = $prefixRow->cl_sortkey_prefix;
$catTo = $prefixRow->cl_to;
- $dbw->update( 'categorylinks',
- array(
- 'cl_sortkey' => Collation::singleton()->getSortKey(
- $nt->getCategorySortkey( $prefix ) ),
- 'cl_timestamp=cl_timestamp' ),
- array(
- 'cl_from' => $pageid,
- 'cl_to' => $catTo ),
- __METHOD__
- );
+ foreach ( Collation::singleton() as $collationName => $collation ) {
+ $dbw->update( 'categorylinks',
+ array(
+ 'cl_sortkey' => $collation->getSortKey(
+ $nt->getCategorySortkey( $prefix )
+ ),
+ 'cl_timestamp=cl_timestamp',
+ ),
+ array(
+ 'cl_from' => $pageid,
+ 'cl_to' => $catTo,
+ 'cl_collation' => $collationName,
+ ),
+ __METHOD__
+ );
+ }
}
$redirid = $this->getArticleID();
diff --git a/includes/api/ApiQueryCategoryMembers.php b/includes/api/ApiQueryCategoryMembers.php
index 4b19b7e..afeaace 100644
--- a/includes/api/ApiQueryCategoryMembers.php
+++ b/includes/api/ApiQueryCategoryMembers.php
@@ -52,6 +52,8 @@ class ApiQueryCategoryMembers extends ApiQueryGeneratorBase {
* @return void
*/
private function run( $resultPageSet = null ) {
+ global $wgCategoryCollation;
+
$params = $this->extractRequestParams();
$this->requireOnlyOneParameter( $params, 'title', 'pageid' );
@@ -72,6 +74,13 @@ class ApiQueryCategoryMembers extends ApiQueryGeneratorBase {
}
}
+ if ( isset( $params['collation'] ) ) {
+ $collation = $params['collation'];
+ } else if ( in_array( $this->getContext()->getUser()->getOption( 'collation' ), $wgCategoryCollation ) ) {
+ $collation = $this->getContext()->getUser()->getOption( 'collation' );
+ } else {
+ $collation = $wgCategoryCollation[0];
+ }
$prop = array_flip( $params['prop'] );
$fld_ids = isset( $prop['ids'] );
$fld_title = isset( $prop['title'] );
@@ -94,6 +103,7 @@ class ApiQueryCategoryMembers extends ApiQueryGeneratorBase {
$this->addTables( array( 'page', 'categorylinks' ) ); // must be in this order for 'USE INDEX'
$this->addWhereFld( 'cl_to', $categoryTitle->getDBkey() );
+ $this->addWhere( 'cl_collation IN (' . $this->getDB()->makeList( array( '', $collation ) ) . ')' );
$queryTypes = $params['type'];
$contWhere = false;
@@ -143,10 +153,10 @@ class ApiQueryCategoryMembers extends ApiQueryGeneratorBase {
$this->addWhereRange( 'cl_from', $dir, null, null );
} else {
$startsortkey = $params['startsortkeyprefix'] !== null ?
- Collation::singleton()->getSortkey( $params['startsortkeyprefix'] ) :
+ Collation::singleton( $collation )->getSortkey( $params['startsortkeyprefix'] ) :
$params['startsortkey'];
$endsortkey = $params['endsortkeyprefix'] !== null ?
- Collation::singleton()->getSortkey( $params['endsortkeyprefix'] ) :
+ Collation::singleton( $collation )->getSortkey( $params['endsortkeyprefix'] ) :
$params['endsortkey'];
// The below produces ORDER BY cl_sortkey, cl_from, possibly with DESC added to each of them
@@ -265,6 +275,8 @@ class ApiQueryCategoryMembers extends ApiQueryGeneratorBase {
}
public function getAllowedParams() {
+ global $wgCategoryCollation;
+
return array(
'title' => array(
ApiBase::PARAM_TYPE => 'string',
@@ -284,6 +296,9 @@ class ApiQueryCategoryMembers extends ApiQueryGeneratorBase {
'timestamp',
)
),
+ 'collation' => array(
+ ApiBase::PARAM_TYPE => $wgCategoryCollation
+ ),
'namespace' => array (
ApiBase::PARAM_ISMULTI => true,
ApiBase::PARAM_TYPE => 'namespace',
@@ -347,6 +362,7 @@ class ApiQueryCategoryMembers extends ApiQueryGeneratorBase {
' type - Adds the type that the page has been categorised as (page, subcat or file)',
' timestamp - Adds the timestamp of when the page was included',
),
+ 'collation' => 'Collation to use',
'namespace' => 'Only include pages in these namespaces',
'type' => "What type of category members to include. Ignored when {$p}sort=timestamp is set",
'sort' => 'Property to sort by',
diff --git a/includes/installer/DatabaseUpdater.php b/includes/installer/DatabaseUpdater.php
index 6ff0af9..53f1152 100644
--- a/includes/installer/DatabaseUpdater.php
+++ b/includes/installer/DatabaseUpdater.php
@@ -683,7 +683,7 @@ abstract class DatabaseUpdater {
if ( $this->db->selectField(
'categorylinks',
'COUNT(*)',
- 'cl_collation != ' . $this->db->addQuotes( $wgCategoryCollation ),
+ 'cl_collation NOT IN (' . $this->db->makeList( $wgCategoryCollation ) . ')',
__METHOD__
) == 0 ) {
$this->output( "...collations up-to-date.\n" );
diff --git a/includes/installer/MysqlUpdater.php b/includes/installer/MysqlUpdater.php
index 5e6ae7e..6914784 100644
--- a/includes/installer/MysqlUpdater.php
+++ b/includes/installer/MysqlUpdater.php
@@ -196,6 +196,7 @@ class MysqlUpdater extends DatabaseUpdater {
// 1.20
array( 'addTable', 'config', 'patch-config.sql' ),
array( 'addIndex', 'revision', 'page_user_timestamp', 'patch-revision-user-page-index.sql' ),
+ array( 'doCategorylinksCollationIndicesUpdate' ),
);
}
@@ -737,6 +738,15 @@ class MysqlUpdater extends DatabaseUpdater {
}
}
+ protected function doCategorylinksCollationIndicesUpdate() {
+ if ( !$this->indexHasField( 'categorylinks', 'cl_from', 'cl_collation' ) ||
+ !$this->indexHasField( 'categorylinks', 'cl_sortkey', 'cl_collation' )
+ ) {
+ $this->applyPatch( 'patch-categorylinks-multiple-collations.sql' );
+ $this->output( "...categorylinks collation indices updated\n" );
+ }
+ }
+
protected function doCategoryPopulation() {
if ( $this->updateRowExists( 'populate category' ) ) {
$this->output( "...category table already populated.\n" );
diff --git a/languages/messages/MessagesEn.php b/languages/messages/MessagesEn.php
index 933cff1..63f95e9 100644
--- a/languages/messages/MessagesEn.php
+++ b/languages/messages/MessagesEn.php
@@ -746,6 +746,7 @@ XHTML id names.
'category-empty' => "''This category currently contains no pages or media.''",
'hidden-categories' => '{{PLURAL:$1|Hidden category|Hidden categories}}',
'hidden-category-category' => 'Hidden categories',
+'category-collation' => 'Collation: ',
'category-subcat-count' => '{{PLURAL:$2|This category has only the following subcategory.|This category has the following {{PLURAL:$1|subcategory|$1 subcategories}}, out of $2 total.}}',
'category-subcat-count-limited' => 'This category has the following {{PLURAL:$1|subcategory|$1 subcategories}}.',
'category-article-count' => '{{PLURAL:$2|This category contains only the following page.|The following {{PLURAL:$1|page is|$1 pages are}} in this category, out of $2 total.}}',
@@ -1850,6 +1851,11 @@ This cannot be undone.',
'yourlanguage' => 'Language:',
'yourvariant' => 'Content language variant:',
'prefs-help-variant' => 'Your preferred variant or orthography to display the content pages of this wiki in.',
+'prefs-collation' => 'Collation:',
+'prefs-help-collation' => 'Your preferred way to sort pages in categories.',
+'collation-uppercase' => 'Uppercase',
+'collation-identity' => 'Identity',
+'collation-uca-default' => 'UCA (Default)',
'yournick' => 'New signature:',
'prefs-help-signature' => 'Comments on talk pages should be signed with "<nowiki>~~~~</nowiki>" which will be converted into your signature and a timestamp.',
'badsig' => 'Invalid raw signature.
diff --git a/maintenance/archives/patch-categorylinks-multiple-collations.sql b/maintenance/archives/patch-categorylinks-multiple-collations.sql
new file mode 100644
index 0000000..90b2216
--- /dev/null
+++ b/maintenance/archives/patch-categorylinks-multiple-collations.sql
@@ -0,0 +1,13 @@
+--
+-- patch-categorylinks-multiple-collations.sql
+--
+-- Allows more than one collations to be used at the same time
+--
+
+ALTER TABLE /*_*/categorylinks
+ DROP INDEX /*i*/cl_from,
+ ADD UNIQUE INDEX /*i*/cl_from(cl_from,cl_to,cl_collation);
+
+ALTER TABLE /*_*/categorylinks
+ DROP INDEX /*i*/cl_sortkey,
+ ADD INDEX /*i*/cl_sortkey(cl_to,cl_type,cl_collation,cl_sortkey,cl_from);
diff --git a/maintenance/language/messages.inc b/maintenance/language/messages.inc
index c9afbfa..eb389b2 100644
--- a/maintenance/language/messages.inc
+++ b/maintenance/language/messages.inc
@@ -147,6 +147,7 @@ $wgMessageStructure = array(
'category-empty',
'hidden-categories',
'hidden-category-category',
+ 'category-collation',
'category-subcat-count',
'category-subcat-count-limited',
'category-article-count',
@@ -1006,6 +1007,11 @@ $wgMessageStructure = array(
'yourlanguage',
'yourvariant',
'prefs-help-variant',
+ 'prefs-collation',
+ 'prefs-help-collation',
+ 'collation-uppercase',
+ 'collation-identity',
+ 'collation-uca-default',
'yournick',
'prefs-help-signature',
'badsig',
diff --git a/maintenance/tables.sql b/maintenance/tables.sql
index 60fc7fc..a9b5e50 100644
--- a/maintenance/tables.sql
+++ b/maintenance/tables.sql
@@ -537,12 +537,12 @@ CREATE TABLE /*_*/categorylinks (
cl_type ENUM('page', 'subcat', 'file') NOT NULL default 'page'
) /*$wgDBTableOptions*/;
-CREATE UNIQUE INDEX /*i*/cl_from ON /*_*/categorylinks (cl_from,cl_to);
+CREATE UNIQUE INDEX /*i*/cl_from ON /*_*/categorylinks (cl_from,cl_to,cl_collation);
-- We always sort within a given category, and within a given type. FIXME:
-- Formerly this index didn't cover cl_type (since that didn't exist), so old
-- callers won't be using an index: fix this?
-CREATE INDEX /*i*/cl_sortkey ON /*_*/categorylinks (cl_to,cl_type,cl_sortkey,cl_from);
+CREATE INDEX /*i*/cl_sortkey ON /*_*/categorylinks (cl_to,cl_type,cl_collation,cl_sortkey,cl_from);
-- Not really used?
CREATE INDEX /*i*/cl_timestamp ON /*_*/categorylinks (cl_to,cl_timestamp);
diff --git a/maintenance/updateCollation.php b/maintenance/updateCollation.php
index 6160a30..cbe8791 100644
--- a/maintenance/updateCollation.php
+++ b/maintenance/updateCollation.php
@@ -45,59 +45,43 @@ TEXT;
$this->addOption( 'force', 'Run on all rows, even if the collation is ' .
'supposed to be up-to-date.' );
- $this->addOption( 'previous-collation', 'Set the previous value of ' .
- '$wgCategoryCollation here to speed up this script, especially if your ' .
- 'categorylinks table is large. This will only update rows with that ' .
- 'collation, though, so it may miss out-of-date rows with a different, ' .
- 'even older collation.', false, true );
}
public function execute() {
- global $wgCategoryCollation, $wgMiserMode;
+ global $wgCategoryCollation;
$dbw = $this->getDB( DB_MASTER );
$force = $this->getOption( 'force' );
- $options = array( 'LIMIT' => self::BATCH_SIZE, 'STRAIGHT_JOIN' );
+ $options = array( 'LIMIT' => self::BATCH_SIZE, 'DISTINCT', 'STRAIGHT_JOIN' );
+
+ $collationConds = array();
if ( $force ) {
$options['ORDER BY'] = 'cl_from, cl_to';
- $collationConds = array();
} else {
- if ( $this->hasOption( 'previous-collation' ) ) {
- $collationConds['cl_collation'] = $this->getOption( 'previous-collation' );
- } else {
- $collationConds = array( 0 =>
- 'cl_collation != ' . $dbw->addQuotes( $wgCategoryCollation )
- );
- }
-
- if ( !$wgMiserMode ) {
- $count = $dbw->selectField(
- 'categorylinks',
- 'COUNT(*)',
- $collationConds,
- __METHOD__
- );
-
- if ( $count == 0 ) {
- $this->output( "Collations up-to-date.\n" );
- return;
- }
- $this->output( "Fixing collation for $count rows.\n" );
- }
+ $collationConds[] = '(' . $dbw->selectSQLText(
+ array( 'cli' => 'categorylinks' ),
+ 'COUNT(*)',
+ array(
+ 'cli.cl_from = clo.cl_from',
+ 'cli.cl_to = clo.cl_to',
+ 'cli.cl_collation IN (' . $dbw->makeList( $wgCategoryCollation ) . ')',
+ ),
+ __METHOD__
+ ) . ') < ' . count( $wgCategoryCollation );
}
$count = 0;
$batchCount = 0;
$batchConds = array();
do {
- $this->output( "Selecting next " . self::BATCH_SIZE . " rows..." );
+ $this->output( "Selecting next " . self::BATCH_SIZE . " pairs..." );
+
+ # Select from/to pairs that don't have enough categorylinks rows
$res = $dbw->select(
- array( 'categorylinks', 'page' ),
- array( 'cl_from', 'cl_to', 'cl_sortkey_prefix', 'cl_collation',
- 'cl_sortkey', 'page_namespace', 'page_title'
- ),
+ array( 'clo' => 'categorylinks', 'page' ),
+ array( 'cl_from', 'cl_to', 'page_namespace', 'page_title' ),
array_merge( $collationConds, $batchConds, array( 'cl_from = page_id' ) ),
__METHOD__,
$options
@@ -107,19 +91,44 @@ TEXT;
$dbw->begin( __METHOD__ );
foreach ( $res as $row ) {
$title = Title::newFromRow( $row );
- if ( !$row->cl_collation ) {
- # This is an old-style row, so the sortkey needs to be
- # converted.
- if ( $row->cl_sortkey == $title->getText()
- || $row->cl_sortkey == $title->getPrefixedText() ) {
- $prefix = '';
+ # Try to extract some data about the given pair
+ $res2 = $dbw->select(
+ 'categorylinks',
+ array( 'cl_sortkey_prefix', 'cl_collation', 'cl_sortkey', 'cl_timestamp' ),
+ array( 'cl_from' => $row->cl_from, 'cl_to' => $row->cl_to ),
+ __METHOD__
+ );
+
+ $prefix = null;
+ $prefix2 = null;
+ $timestamp = null;
+ $collations = array();
+ foreach ( $res2 as $row2 ) {
+ $collations[] = $row2->cl_collation;
+ if ( !$row2->cl_collation ) {
+ # This is an old-style row, so the sortkey needs to be
+ # converted.
+ if ( $row2->cl_sortkey == $title->getText()
+ || $row2->cl_sortkey == $title->getPrefixedText() ) {
+ $prefix = '';
+ } else {
+ # Custom sortkey, use it as a prefix
+ $prefix = $row2->cl_sortkey;
+ }
} else {
- # Custom sortkey, use it as a prefix
- $prefix = $row->cl_sortkey;
+ $prefix2 = $row2->cl_sortkey_prefix;
+ }
+ if ( isset( $timestamp ) ) {
+ # Should we compare timestamp values more carefully?
+ $timestamp = min( $timestamp, $row2->cl_timestamp );
+ } else {
+ $timestamp = $row2->cl_timestamp;
}
- } else {
- $prefix = $row->cl_sortkey_prefix;
}
+ if ( isset( $prefix2 ) ) {
+ $prefix = $prefix2;
+ }
+
# cl_type will be wrong for lots of pages if cl_collation is 0,
# so let's update it while we're here.
if ( $title->getNamespace() == NS_CATEGORY ) {
@@ -129,19 +138,52 @@ TEXT;
} else {
$type = 'page';
}
- $dbw->update(
+
+ $dbw->delete(
'categorylinks',
array(
- 'cl_sortkey' => Collation::singleton()->getSortKey(
- $title->getCategorySortkey( $prefix ) ),
- 'cl_sortkey_prefix' => $prefix,
- 'cl_collation' => $wgCategoryCollation,
- 'cl_type' => $type,
- 'cl_timestamp = cl_timestamp',
+ 'cl_from' => $row->cl_from,
+ 'cl_to' => $row->cl_to,
+ 'cl_collation NOT IN (' . $dbw->makeList( $wgCategoryCollation ) . ')',
),
- array( 'cl_from' => $row->cl_from, 'cl_to' => $row->cl_to ),
__METHOD__
);
+
+ foreach ( Collation::singleton() as $collationName => $collation ) {
+ if ( !in_array( $collationName, $collations ) ) {
+ $dbw->insert(
+ 'categorylinks',
+ array(
+ 'cl_from' => $row->cl_from,
+ 'cl_to' => $row->cl_to,
+ 'cl_sortkey' => $collation->getSortKey(
+ $title->getCategorySortkey( $prefix ) ),
+ 'cl_sortkey_prefix' => $prefix,
+ 'cl_collation' => $collationName,
+ 'cl_type' => $type,
+ 'cl_timestamp' => $timestamp,
+ ),
+ __METHOD__
+ );
+ } else if ( $force ) {
+ $dbw->update(
+ 'categorylinks',
+ array(
+ 'cl_sortkey' => $collation->getSortKey(
+ $title->getCategorySortkey( $prefix ) ),
+ 'cl_sortkey_prefix' => $prefix,
+ 'cl_type' => $type,
+ 'cl_timestamp' => $timestamp,
+ ),
+ array(
+ 'cl_from' => $row->cl_from,
+ 'cl_to' => $row->cl_to,
+ 'cl_collation' => $collationName,
+ ),
+ __METHOD__
+ );
+ }
+ }
}
$dbw->commit( __METHOD__ );
diff --git a/resources/Resources.php b/resources/Resources.php
index 4e4c90a..d1352bd 100644
--- a/resources/Resources.php
+++ b/resources/Resources.php
@@ -751,7 +751,11 @@ return array(
),
'position' => 'top',
),
-
+ 'mediawiki.page.category' => array(
+ 'scripts' => 'resources/mediawiki.page/mediawiki.page.category.js',
+ 'styles' => 'resources/mediawiki.page/mediawiki.page.category.css',
+ 'position' => 'top',
+ ),
/* MediaWiki Special pages */
diff --git a/resources/mediawiki.page/mediawiki.page.category.css b/resources/mediawiki.page/mediawiki.page.category.css
new file mode 100644
index 0000000..0d75cdf
--- /dev/null
+++ b/resources/mediawiki.page/mediawiki.page.category.css
@@ -0,0 +1,3 @@
+#mw-collation-selector {
+ float: right;
+}
diff --git a/resources/mediawiki.page/mediawiki.page.category.js b/resources/mediawiki.page/mediawiki.page.category.js
new file mode 100644
index 0000000..1eab400
--- /dev/null
+++ b/resources/mediawiki.page/mediawiki.page.category.js
@@ -0,0 +1,9 @@
+jQuery( document ).ready( function( $ ) {
+
+ $( '#mw-collation-select' ).change( function() {
+ $( '#mw-collation-selector' )[0].submit();
+ } );
+
+ $( '#mw-collation-go' ).hide();
+
+} );

File Metadata

Mime Type
text/x-diff
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
8725
Default Alt Text
multiple-collations.patch (26 KB)

Event Timeline