Index: branches/wmf/1.17wmf1/extensions/FlaggedRevs/specialpages/UnreviewedPages_body.php |
— | — | @@ -272,14 +272,6 @@ |
273 | 273 | $fields[] = 'cl_sortkey'; |
274 | 274 | $conds['cl_to'] = $this->category; |
275 | 275 | $conds[] = 'cl_from = page_id'; |
276 | | - # Note: single NS always specified |
277 | | - if( $this->namespace == NS_FILE ) { |
278 | | - $conds['cl_type'] = 'file'; |
279 | | - } elseif( $this->namespace == NS_CATEGORY ) { |
280 | | - $conds['cl_type'] = 'subcat'; |
281 | | - } else { |
282 | | - $conds['cl_type'] = 'page'; |
283 | | - } |
284 | 276 | $this->mIndexField = 'cl_sortkey'; |
285 | 277 | $useIndex = array( 'categorylinks' => 'cl_sortkey' ); |
286 | 278 | $groupBy = 'cl_sortkey,cl_from'; |
Index: branches/wmf/1.17wmf1/extensions/Collection/Collection.body.php |
— | — | @@ -631,10 +631,10 @@ |
632 | 632 | } |
633 | 633 | $db = wfGetDB( DB_SLAVE ); |
634 | 634 | $tables = array( 'page', 'categorylinks' ); |
635 | | - $fields = array( 'page_namespace', 'page_title' ); |
| 635 | + $fields = array( 'cl_from', 'cl_sortkey', 'page_namespace', 'page_title' ); |
636 | 636 | $options = array( |
637 | 637 | 'USE INDEX' => 'cl_sortkey', |
638 | | - 'ORDER BY' => 'cl_type, cl_sortkey', |
| 638 | + 'ORDER BY' => 'cl_sortkey', |
639 | 639 | 'LIMIT' => $limit + 1, |
640 | 640 | ); |
641 | 641 | $where = array( |
Index: branches/wmf/1.17wmf1/extensions/intersection/DynamicPageList.php |
— | — | @@ -497,7 +497,7 @@ |
498 | 498 | $sSqlSort = 'page_id'; # Since they're never reused and increasing |
499 | 499 | break; |
500 | 500 | case 'categorysortkey': |
501 | | - $sSqlSort = "c1.cl_type $sSqlOrder, c1.cl_sortkey"; |
| 501 | + $sSqlSort = 'c1.cl_sortkey'; |
502 | 502 | break; |
503 | 503 | case 'popularity': |
504 | 504 | $sSqlSort = 'page_counter'; |
Index: branches/wmf/1.17wmf1/extensions/CategoryTree/CategoryTreeFunctions.php |
— | — | @@ -427,7 +427,7 @@ |
428 | 428 | 'cl_from' ); |
429 | 429 | $where = array(); |
430 | 430 | $joins = array(); |
431 | | - $options = array( 'ORDER BY' => 'cl_type, cl_sortkey', 'LIMIT' => $wgCategoryTreeMaxChildren ); |
| 431 | + $options = array( 'ORDER BY' => 'cl_sortkey', 'LIMIT' => $wgCategoryTreeMaxChildren ); |
432 | 432 | |
433 | 433 | if ( $inverse ) { |
434 | 434 | $joins['categorylinks'] = array( 'RIGHT JOIN', 'cl_to = page_title AND page_namespace = ' . NS_CATEGORY ); |
— | — | @@ -443,9 +443,9 @@ |
444 | 444 | $where['page_namespace'] = $namespaces; |
445 | 445 | } elseif ( $mode != CT_MODE_ALL ) { |
446 | 446 | if ( $mode == CT_MODE_PAGES ) { |
447 | | - $where['cl_type'] = array( 'page', 'subcat' ); |
| 447 | + $where = array_merge( $where, array( 'page_namespace != ' . NS_IMAGE ) ); |
448 | 448 | } else { |
449 | | - $where['cl_type'] = 'subcat'; |
| 449 | + $where['page_namespace'] = NS_CATEGORY; |
450 | 450 | } |
451 | 451 | } |
452 | 452 | } |
Index: branches/wmf/1.17wmf1/includes/CategoryPage.php |
— | — | @@ -1,41 +1,33 @@ |
2 | 2 | <?php |
3 | 3 | /** |
4 | | - * Special handling for category description pages. |
5 | | - * Modelled after ImagePage.php. |
| 4 | + * Special handling for category description pages |
| 5 | + * Modelled after ImagePage.php |
6 | 6 | * |
7 | | - * @file |
8 | 7 | */ |
9 | 8 | |
10 | 9 | if ( !defined( 'MEDIAWIKI' ) ) |
11 | 10 | die( 1 ); |
12 | 11 | |
13 | 12 | /** |
14 | | - * Special handling for category description pages, showing pages, |
15 | | - * subcategories and file that belong to the category |
16 | 13 | */ |
17 | 14 | class CategoryPage extends Article { |
18 | | - # Subclasses can change this to override the viewer class. |
19 | | - protected $mCategoryViewerClass = 'CategoryViewer'; |
20 | | - |
21 | 15 | function view() { |
22 | 16 | global $wgRequest, $wgUser; |
23 | 17 | |
24 | 18 | $diff = $wgRequest->getVal( 'diff' ); |
25 | 19 | $diffOnly = $wgRequest->getBool( 'diffonly', $wgUser->getOption( 'diffonly' ) ); |
26 | 20 | |
27 | | - if ( isset( $diff ) && $diffOnly ) { |
28 | | - return parent::view(); |
29 | | - } |
| 21 | + if ( isset( $diff ) && $diffOnly ) |
| 22 | + return Article::view(); |
30 | 23 | |
31 | | - if ( !wfRunHooks( 'CategoryPageView', array( &$this ) ) ) { |
| 24 | + if ( !wfRunHooks( 'CategoryPageView', array( &$this ) ) ) |
32 | 25 | return; |
33 | | - } |
34 | 26 | |
35 | 27 | if ( NS_CATEGORY == $this->mTitle->getNamespace() ) { |
36 | 28 | $this->openShowCategory(); |
37 | 29 | } |
38 | 30 | |
39 | | - parent::view(); |
| 31 | + Article::view(); |
40 | 32 | |
41 | 33 | if ( NS_CATEGORY == $this->mTitle->getNamespace() ) { |
42 | 34 | $this->closeShowCategory(); |
— | — | @@ -60,14 +52,10 @@ |
61 | 53 | |
62 | 54 | function closeShowCategory() { |
63 | 55 | global $wgOut, $wgRequest; |
| 56 | + $from = $wgRequest->getVal( 'from' ); |
| 57 | + $until = $wgRequest->getVal( 'until' ); |
64 | 58 | |
65 | | - $from = $until = array(); |
66 | | - foreach ( array( 'page', 'subcat', 'file' ) as $type ) { |
67 | | - $from[$type] = $wgRequest->getVal( "{$type}from" ); |
68 | | - $until[$type] = $wgRequest->getVal( "{$type}until" ); |
69 | | - } |
70 | | - |
71 | | - $viewer = new $this->mCategoryViewerClass( $this->mTitle, $from, $until, $wgRequest->getValues() ); |
| 59 | + $viewer = new CategoryViewer( $this->mTitle, $from, $until ); |
72 | 60 | $wgOut->addHTML( $viewer->getHTML() ); |
73 | 61 | } |
74 | 62 | } |
— | — | @@ -77,32 +65,27 @@ |
78 | 66 | $articles, $articles_start_char, |
79 | 67 | $children, $children_start_char, |
80 | 68 | $showGallery, $gallery, |
81 | | - $imgsNoGalley, $imgsNoGallery_start_char, |
82 | | - $skin, $collation; |
83 | | - # Category object for this page |
| 69 | + $skin; |
| 70 | + /** Category object for this page */ |
84 | 71 | private $cat; |
85 | | - # The original query array, to be used in generating paging links. |
86 | | - private $query; |
87 | 72 | |
88 | | - function __construct( $title, $from = '', $until = '', $query = array() ) { |
| 73 | + function __construct( $title, $from = '', $until = '' ) { |
89 | 74 | global $wgCategoryPagingLimit; |
90 | 75 | $this->title = $title; |
91 | 76 | $this->from = $from; |
92 | 77 | $this->until = $until; |
93 | 78 | $this->limit = $wgCategoryPagingLimit; |
94 | 79 | $this->cat = Category::newFromTitle( $title ); |
95 | | - $this->query = $query; |
96 | | - $this->collation = Collation::singleton(); |
97 | | - unset( $this->query['title'] ); |
98 | 80 | } |
99 | 81 | |
100 | 82 | /** |
101 | 83 | * Format the category data list. |
102 | 84 | * |
103 | 85 | * @return string HTML output |
| 86 | + * @private |
104 | 87 | */ |
105 | | - public function getHTML() { |
106 | | - global $wgOut, $wgCategoryMagicGallery, $wgContLang; |
| 88 | + function getHTML() { |
| 89 | + global $wgOut, $wgCategoryMagicGallery, $wgCategoryPagingLimit, $wgContLang; |
107 | 90 | wfProfileIn( __METHOD__ ); |
108 | 91 | |
109 | 92 | $this->showGallery = $wgCategoryMagicGallery && !$wgOut->mNoGallery; |
— | — | @@ -145,9 +128,6 @@ |
146 | 129 | if ( $this->showGallery ) { |
147 | 130 | $this->gallery = new ImageGallery(); |
148 | 131 | $this->gallery->setHideBadImages(); |
149 | | - } else { |
150 | | - $this->imgsNoGallery = array(); |
151 | | - $this->imgsNoGallery_start_char = array(); |
152 | 132 | } |
153 | 133 | } |
154 | 134 | |
— | — | @@ -162,29 +142,26 @@ |
163 | 143 | /** |
164 | 144 | * Add a subcategory to the internal lists, using a Category object |
165 | 145 | */ |
166 | | - function addSubcategoryObject( Category $cat, $sortkey, $pageLength ) { |
167 | | - // Subcategory; strip the 'Category' namespace from the link text. |
| 146 | + function addSubcategoryObject( $cat, $sortkey, $pageLength ) { |
168 | 147 | $title = $cat->getTitle(); |
169 | | - |
170 | | - $link = $this->getSkin()->link( $title, $title->getText() ); |
171 | | - if ( $title->isRedirect() ) { |
172 | | - // This didn't used to add redirect-in-category, but might |
173 | | - // as well be consistent with the rest of the sections |
174 | | - // on a category page. |
175 | | - $link = '<span class="redirect-in-category">' . $link . '</span>'; |
176 | | - } |
177 | | - $this->children[] = $link; |
178 | | - |
179 | | - $this->children_start_char[] = |
180 | | - $this->getSubcategorySortChar( $cat->getTitle(), $sortkey ); |
| 148 | + $this->addSubcategory( $title, $sortkey, $pageLength ); |
181 | 149 | } |
182 | 150 | |
183 | 151 | /** |
184 | 152 | * Add a subcategory to the internal lists, using a title object |
185 | 153 | * @deprecated kept for compatibility, please use addSubcategoryObject instead |
186 | 154 | */ |
187 | | - function addSubcategory( Title $title, $sortkey, $pageLength ) { |
188 | | - $this->addSubcategoryObject( Category::newFromTitle( $title ), $sortkey, $pageLength ); |
| 155 | + function addSubcategory( $title, $sortkey, $pageLength ) { |
| 156 | + // Subcategory; strip the 'Category' namespace from the link text. |
| 157 | + $this->children[] = $this->getSkin()->link( |
| 158 | + $title, |
| 159 | + null, |
| 160 | + array(), |
| 161 | + array(), |
| 162 | + array( 'known', 'noclasses' ) |
| 163 | + ); |
| 164 | + |
| 165 | + $this->children_start_char[] = $this->getSubcategorySortChar( $title, $sortkey ); |
189 | 166 | } |
190 | 167 | |
191 | 168 | /** |
— | — | @@ -198,13 +175,11 @@ |
199 | 176 | global $wgContLang; |
200 | 177 | |
201 | 178 | if ( $title->getPrefixedText() == $sortkey ) { |
202 | | - $word = $title->getDBkey(); |
| 179 | + $firstChar = $wgContLang->firstChar( $title->getDBkey() ); |
203 | 180 | } else { |
204 | | - $word = $sortkey; |
| 181 | + $firstChar = $wgContLang->firstChar( $sortkey ); |
205 | 182 | } |
206 | 183 | |
207 | | - $firstChar = $this->collation->getFirstLetter( $word ); |
208 | | - |
209 | 184 | return $wgContLang->convert( $firstChar ); |
210 | 185 | } |
211 | 186 | |
— | — | @@ -212,25 +187,14 @@ |
213 | 188 | * Add a page in the image namespace |
214 | 189 | */ |
215 | 190 | function addImage( Title $title, $sortkey, $pageLength, $isRedirect = false ) { |
216 | | - global $wgContLang; |
217 | 191 | if ( $this->showGallery ) { |
218 | | - $flip = $this->flip['file']; |
219 | | - if ( $flip ) { |
| 192 | + if ( $this->flip ) { |
220 | 193 | $this->gallery->insert( $title ); |
221 | 194 | } else { |
222 | 195 | $this->gallery->add( $title ); |
223 | 196 | } |
224 | 197 | } else { |
225 | | - $link = $this->getSkin()->link( $title ); |
226 | | - if ( $isRedirect ) { |
227 | | - // This seems kind of pointless given 'mw-redirect' class, |
228 | | - // but keeping for back-compatibility with user css. |
229 | | - $link = '<span class="redirect-in-category">' . $link . '</span>'; |
230 | | - } |
231 | | - $this->imgsNoGallery[] = $link; |
232 | | - |
233 | | - $this->imgsNoGallery_start_char[] = $wgContLang->convert( |
234 | | - $this->collation->getFirstLetter( $sortkey ) ); |
| 198 | + $this->addPage( $title, $sortkey, $pageLength, $isRedirect ); |
235 | 199 | } |
236 | 200 | } |
237 | 201 | |
— | — | @@ -239,96 +203,74 @@ |
240 | 204 | */ |
241 | 205 | function addPage( $title, $sortkey, $pageLength, $isRedirect = false ) { |
242 | 206 | global $wgContLang; |
243 | | - |
244 | | - $link = $this->getSkin()->link( $title ); |
245 | | - if ( $isRedirect ) { |
246 | | - // This seems kind of pointless given 'mw-redirect' class, |
247 | | - // but keeping for back-compatiability with user css. |
248 | | - $link = '<span class="redirect-in-category">' . $link . '</span>'; |
249 | | - } |
250 | | - $this->articles[] = $link; |
251 | | - |
252 | | - $this->articles_start_char[] = $wgContLang->convert( |
253 | | - $this->collation->getFirstLetter( $sortkey ) ); |
| 207 | + $this->articles[] = $isRedirect |
| 208 | + ? '<span class="redirect-in-category">' . |
| 209 | + $this->getSkin()->link( |
| 210 | + $title, |
| 211 | + null, |
| 212 | + array(), |
| 213 | + array(), |
| 214 | + array( 'known', 'noclasses' ) |
| 215 | + ) . '</span>' |
| 216 | + : $this->getSkin()->makeSizeLinkObj( $pageLength, $title ); |
| 217 | + $this->articles_start_char[] = $wgContLang->convert( $wgContLang->firstChar( $sortkey ) ); |
254 | 218 | } |
255 | 219 | |
256 | 220 | function finaliseCategoryState() { |
257 | | - if ( $this->flip['subcat'] ) { |
| 221 | + if ( $this->flip ) { |
258 | 222 | $this->children = array_reverse( $this->children ); |
259 | 223 | $this->children_start_char = array_reverse( $this->children_start_char ); |
260 | | - } |
261 | | - if ( $this->flip['page'] ) { |
262 | 224 | $this->articles = array_reverse( $this->articles ); |
263 | 225 | $this->articles_start_char = array_reverse( $this->articles_start_char ); |
264 | 226 | } |
265 | | - if ( !$this->showGallery && $this->flip['file'] ) { |
266 | | - $this->imgsNoGallery = array_reverse( $this->imgsNoGallery ); |
267 | | - $this->imgsNoGallery_start_char = array_reverse( $this->imgsNoGallery_start_char ); |
268 | | - } |
269 | 227 | } |
270 | 228 | |
271 | 229 | function doCategoryQuery() { |
272 | 230 | $dbr = wfGetDB( DB_SLAVE, 'category' ); |
| 231 | + if ( $this->from != '' ) { |
| 232 | + $pageCondition = 'cl_sortkey >= ' . $dbr->addQuotes( $this->from ); |
| 233 | + $this->flip = false; |
| 234 | + } elseif ( $this->until != '' ) { |
| 235 | + $pageCondition = 'cl_sortkey < ' . $dbr->addQuotes( $this->until ); |
| 236 | + $this->flip = true; |
| 237 | + } else { |
| 238 | + $pageCondition = '1 = 1'; |
| 239 | + $this->flip = false; |
| 240 | + } |
273 | 241 | |
274 | | - $this->nextPage = array( |
275 | | - 'page' => null, |
276 | | - 'subcat' => null, |
277 | | - 'file' => null, |
| 242 | + $res = $dbr->select( |
| 243 | + array( 'page', 'categorylinks', 'category' ), |
| 244 | + array( 'page_title', 'page_namespace', 'page_len', 'page_is_redirect', 'cl_sortkey', |
| 245 | + 'cat_id', 'cat_title', 'cat_subcats', 'cat_pages', 'cat_files' ), |
| 246 | + array( $pageCondition, 'cl_to' => $this->title->getDBkey() ), |
| 247 | + __METHOD__, |
| 248 | + array( 'ORDER BY' => $this->flip ? 'cl_sortkey DESC' : 'cl_sortkey', |
| 249 | + 'USE INDEX' => array( 'categorylinks' => 'cl_sortkey' ), |
| 250 | + 'LIMIT' => $this->limit + 1 ), |
| 251 | + array( 'categorylinks' => array( 'INNER JOIN', 'cl_from = page_id' ), |
| 252 | + 'category' => array( 'LEFT JOIN', 'cat_title = page_title AND page_namespace = ' . NS_CATEGORY ) ) |
278 | 253 | ); |
279 | | - $this->flip = array( 'page' => false, 'subcat' => false, 'file' => false ); |
280 | 254 | |
281 | | - foreach ( array( 'page', 'subcat', 'file' ) as $type ) { |
282 | | - # Get the sortkeys for start/end, if applicable. Note that if |
283 | | - # the collation in the database differs from the one |
284 | | - # set in $wgCategoryCollation, pagination might go totally haywire. |
285 | | - $extraConds = array( 'cl_type' => $type ); |
286 | | - if ( $this->from[$type] !== null ) { |
287 | | - $extraConds[] = 'cl_sortkey >= ' |
288 | | - . $dbr->addQuotes( $this->collation->getSortKey( $this->from[$type] ) ); |
289 | | - } elseif ( $this->until[$type] !== null ) { |
290 | | - $extraConds[] = 'cl_sortkey < ' |
291 | | - . $dbr->addQuotes( $this->collation->getSortKey( $this->until[$type] ) ); |
292 | | - $this->flip[$type] = true; |
| 255 | + $count = 0; |
| 256 | + $this->nextPage = null; |
| 257 | + |
| 258 | + while ( $x = $dbr->fetchObject ( $res ) ) { |
| 259 | + if ( ++$count > $this->limit ) { |
| 260 | + // We've reached the one extra which shows that there are |
| 261 | + // additional pages to be had. Stop here... |
| 262 | + $this->nextPage = $x->cl_sortkey; |
| 263 | + break; |
293 | 264 | } |
294 | 265 | |
295 | | - $res = $dbr->select( |
296 | | - array( 'page', 'categorylinks', 'category' ), |
297 | | - array( 'page_id', 'page_title', 'page_namespace', 'page_len', |
298 | | - 'page_is_redirect', 'cl_sortkey', 'cat_id', 'cat_title', |
299 | | - 'cat_subcats', 'cat_pages', 'cat_files', 'cl_sortkey_prefix' ), |
300 | | - array( 'cl_to' => $this->title->getDBkey() ) + $extraConds, |
301 | | - __METHOD__, |
302 | | - array( |
303 | | - 'USE INDEX' => array( 'categorylinks' => 'cl_sortkey' ), |
304 | | - 'LIMIT' => $this->limit + 1, |
305 | | - 'ORDER BY' => $this->flip[$type] ? 'cl_sortkey DESC' : 'cl_sortkey', |
306 | | - ), |
307 | | - array( |
308 | | - 'categorylinks' => array( 'INNER JOIN', 'cl_from = page_id' ), |
309 | | - 'category' => array( 'LEFT JOIN', 'cat_title = page_title AND page_namespace = ' . NS_CATEGORY ) |
310 | | - ) |
311 | | - ); |
| 266 | + $title = Title::makeTitle( $x->page_namespace, $x->page_title ); |
312 | 267 | |
313 | | - $count = 0; |
314 | | - foreach ( $res as $row ) { |
315 | | - $title = Title::newFromRow( $row ); |
316 | | - $rawSortkey = $title->getCategorySortkey( $row->cl_sortkey_prefix ); |
317 | | - |
318 | | - if ( ++$count > $this->limit ) { |
319 | | - # We've reached the one extra which shows that there |
320 | | - # are additional pages to be had. Stop here... |
321 | | - $this->nextPage[$type] = $rawSortkey; |
322 | | - break; |
323 | | - } |
324 | | - |
325 | | - if ( $title->getNamespace() == NS_CATEGORY ) { |
326 | | - $cat = Category::newFromRow( $row, $title ); |
327 | | - $this->addSubcategoryObject( $cat, $rawSortkey, $row->page_len ); |
328 | | - } elseif ( $title->getNamespace() == NS_FILE ) { |
329 | | - $this->addImage( $title, $rawSortkey, $row->page_len, $row->page_is_redirect ); |
330 | | - } else { |
331 | | - $this->addPage( $title, $rawSortkey, $row->page_len, $row->page_is_redirect ); |
332 | | - } |
| 268 | + if ( $title->getNamespace() == NS_CATEGORY ) { |
| 269 | + $cat = Category::newFromRow( $x, $title ); |
| 270 | + $this->addSubcategoryObject( $cat, $x->cl_sortkey, $x->page_len ); |
| 271 | + } elseif ( $this->showGallery && $title->getNamespace() == NS_FILE ) { |
| 272 | + $this->addImage( $title, $x->cl_sortkey, $x->page_len, $x->page_is_redirect ); |
| 273 | + } else { |
| 274 | + $this->addPage( $title, $x->cl_sortkey, $x->page_len, $x->page_is_redirect ); |
333 | 275 | } |
334 | 276 | } |
335 | 277 | } |
— | — | @@ -352,9 +294,7 @@ |
353 | 295 | $r .= "<div id=\"mw-subcategories\">\n"; |
354 | 296 | $r .= '<h2>' . wfMsg( 'subcategories' ) . "</h2>\n"; |
355 | 297 | $r .= $countmsg; |
356 | | - $r .= $this->getSectionPagingLinks( 'subcat' ); |
357 | 298 | $r .= $this->formatList( $this->children, $this->children_start_char ); |
358 | | - $r .= $this->getSectionPagingLinks( 'subcat' ); |
359 | 299 | $r .= "\n</div>"; |
360 | 300 | } |
361 | 301 | return $r; |
— | — | @@ -378,57 +318,36 @@ |
379 | 319 | $r = "<div id=\"mw-pages\">\n"; |
380 | 320 | $r .= '<h2>' . wfMsg( 'category_header', $ti ) . "</h2>\n"; |
381 | 321 | $r .= $countmsg; |
382 | | - $r .= $this->getSectionPagingLinks( 'page' ); |
383 | 322 | $r .= $this->formatList( $this->articles, $this->articles_start_char ); |
384 | | - $r .= $this->getSectionPagingLinks( 'page' ); |
385 | 323 | $r .= "\n</div>"; |
386 | 324 | } |
387 | 325 | return $r; |
388 | 326 | } |
389 | 327 | |
390 | 328 | function getImageSection() { |
391 | | - $r = ''; |
392 | | - $rescnt = $this->showGallery ? $this->gallery->count() : count( $this->imgsNoGallery ); |
393 | | - if ( $rescnt > 0 ) { |
| 329 | + if ( $this->showGallery && ! $this->gallery->isEmpty() ) { |
394 | 330 | $dbcnt = $this->cat->getFileCount(); |
| 331 | + $rescnt = $this->gallery->count(); |
395 | 332 | $countmsg = $this->getCountMessage( $rescnt, $dbcnt, 'file' ); |
396 | 333 | |
397 | | - $r .= "<div id=\"mw-category-media\">\n"; |
398 | | - $r .= '<h2>' . wfMsg( 'category-media-header', htmlspecialchars( $this->title->getText() ) ) . "</h2>\n"; |
399 | | - $r .= $countmsg; |
400 | | - $r .= $this->getSectionPagingLinks( 'file' ); |
401 | | - if ( $this->showGallery ) { |
402 | | - $r .= $this->gallery->toHTML(); |
403 | | - } else { |
404 | | - $r .= $this->formatList( $this->imgsNoGallery, $this->imgsNoGallery_start_char ); |
405 | | - } |
406 | | - $r .= $this->getSectionPagingLinks( 'file' ); |
407 | | - $r .= "\n</div>"; |
| 334 | + return "<div id=\"mw-category-media\">\n" . |
| 335 | + '<h2>' . wfMsg( 'category-media-header', htmlspecialchars( $this->title->getText() ) ) . "</h2>\n" . |
| 336 | + $countmsg . $this->gallery->toHTML() . "\n</div>"; |
| 337 | + } else { |
| 338 | + return ''; |
408 | 339 | } |
409 | | - return $r; |
410 | 340 | } |
411 | 341 | |
412 | | - /** |
413 | | - * Get the paging links for a section (subcats/pages/files), to go at the top and bottom |
414 | | - * of the output. |
415 | | - * |
416 | | - * @param $type String: 'page', 'subcat', or 'file' |
417 | | - * @return String: HTML output, possibly empty if there are no other pages |
418 | | - */ |
419 | | - private function getSectionPagingLinks( $type ) { |
420 | | - if ( $this->until[$type] !== null ) { |
421 | | - return $this->pagingLinks( $this->nextPage[$type], $this->until[$type], $type ); |
422 | | - } elseif ( $this->nextPage[$type] !== null || $this->from[$type] !== null ) { |
423 | | - return $this->pagingLinks( $this->from[$type], $this->nextPage[$type], $type ); |
| 342 | + function getCategoryBottom() { |
| 343 | + if ( $this->until != '' ) { |
| 344 | + return $this->pagingLinks( $this->title, $this->nextPage, $this->until, $this->limit ); |
| 345 | + } elseif ( $this->nextPage != '' || $this->from != '' ) { |
| 346 | + return $this->pagingLinks( $this->title, $this->from, $this->nextPage, $this->limit ); |
424 | 347 | } else { |
425 | 348 | return ''; |
426 | 349 | } |
427 | 350 | } |
428 | 351 | |
429 | | - function getCategoryBottom() { |
430 | | - return ''; |
431 | | - } |
432 | | - |
433 | 352 | /** |
434 | 353 | * Format a list of articles chunked by letter, either as a |
435 | 354 | * bullet list or a columnar format, depending on the length. |
— | — | @@ -441,10 +360,10 @@ |
442 | 361 | */ |
443 | 362 | function formatList( $articles, $articles_start_char, $cutoff = 6 ) { |
444 | 363 | if ( count ( $articles ) > $cutoff ) { |
445 | | - return self::columnList( $articles, $articles_start_char ); |
| 364 | + return $this->columnList( $articles, $articles_start_char ); |
446 | 365 | } elseif ( count( $articles ) > 0 ) { |
447 | 366 | // for short lists of articles in categories. |
448 | | - return self::shortList( $articles, $articles_start_char ); |
| 367 | + return $this->shortList( $articles, $articles_start_char ); |
449 | 368 | } |
450 | 369 | return ''; |
451 | 370 | } |
— | — | @@ -464,7 +383,7 @@ |
465 | 384 | * @return String |
466 | 385 | * @private |
467 | 386 | */ |
468 | | - static function columnList( $articles, $articles_start_char ) { |
| 387 | + function columnList( $articles, $articles_start_char ) { |
469 | 388 | $columns = array_combine( $articles, $articles_start_char ); |
470 | 389 | # Split into three columns |
471 | 390 | $columns = array_chunk( $columns, ceil( count( $columns ) / 3 ), true /* preserve keys */ ); |
— | — | @@ -516,7 +435,7 @@ |
517 | 436 | * @return String |
518 | 437 | * @private |
519 | 438 | */ |
520 | | - static function shortList( $articles, $articles_start_char ) { |
| 439 | + function shortList( $articles, $articles_start_char ) { |
521 | 440 | $r = '<h3>' . htmlspecialchars( $articles_start_char[0] ) . "</h3>\n"; |
522 | 441 | $r .= '<ul><li>' . $articles[0] . '</li>'; |
523 | 442 | for ( $index = 1; $index < count( $articles ); $index++ ) |
— | — | @@ -533,27 +452,26 @@ |
534 | 453 | } |
535 | 454 | |
536 | 455 | /** |
537 | | - * Create paging links, as a helper method to getSectionPagingLinks(). |
538 | | - * |
539 | | - * @param $first String The 'until' parameter for the generated URL |
540 | | - * @param $last String The 'from' parameter for the genererated URL |
541 | | - * @param $type String A prefix for parameters, 'page' or 'subcat' or |
542 | | - * 'file' |
543 | | - * @return String HTML |
| 456 | + * @param $title Title object |
| 457 | + * @param $first String |
| 458 | + * @param $last String |
| 459 | + * @param $limit Int |
| 460 | + * @param $query Array: additional query options to pass |
| 461 | + * @return String |
| 462 | + * @private |
544 | 463 | */ |
545 | | - private function pagingLinks( $first, $last, $type = '' ) { |
| 464 | + function pagingLinks( $title, $first, $last, $limit, $query = array() ) { |
546 | 465 | global $wgLang; |
547 | 466 | $sk = $this->getSkin(); |
548 | | - $limitText = $wgLang->formatNum( $this->limit ); |
| 467 | + $limitText = $wgLang->formatNum( $limit ); |
549 | 468 | |
550 | 469 | $prevLink = wfMsgExt( 'prevn', array( 'escape', 'parsemag' ), $limitText ); |
551 | 470 | |
552 | 471 | if ( $first != '' ) { |
553 | | - $prevQuery = $this->query; |
554 | | - $prevQuery["{$type}until"] = $first; |
555 | | - unset( $prevQuery["{$type}from"] ); |
| 472 | + $prevQuery = $query; |
| 473 | + $prevQuery['until'] = $first; |
556 | 474 | $prevLink = $sk->linkKnown( |
557 | | - $this->title, |
| 475 | + $title, |
558 | 476 | $prevLink, |
559 | 477 | array(), |
560 | 478 | $prevQuery |
— | — | @@ -563,11 +481,10 @@ |
564 | 482 | $nextLink = wfMsgExt( 'nextn', array( 'escape', 'parsemag' ), $limitText ); |
565 | 483 | |
566 | 484 | if ( $last != '' ) { |
567 | | - $lastQuery = $this->query; |
568 | | - $lastQuery["{$type}from"] = $last; |
569 | | - unset( $lastQuery["{$type}until"] ); |
| 485 | + $lastQuery = $query; |
| 486 | + $lastQuery['from'] = $last; |
570 | 487 | $nextLink = $sk->linkKnown( |
571 | | - $this->title, |
| 488 | + $title, |
572 | 489 | $nextLink, |
573 | 490 | array(), |
574 | 491 | $lastQuery |
— | — | @@ -579,8 +496,8 @@ |
580 | 497 | |
581 | 498 | /** |
582 | 499 | * What to do if the category table conflicts with the number of results |
583 | | - * returned? This function says what. Each type is considered independantly |
584 | | - * of the other types. |
| 500 | + * returned? This function says what. It works the same whether the |
| 501 | + * things being counted are articles, subcategories, or files. |
585 | 502 | * |
586 | 503 | * Note for grepping: uses the messages category-article-count, |
587 | 504 | * category-article-count-limited, category-subcat-count, |
— | — | @@ -603,28 +520,15 @@ |
604 | 521 | # than $this->limit and there's no offset. In this case we still |
605 | 522 | # know the right figure. |
606 | 523 | # 3) We have no idea. |
| 524 | + $totalrescnt = count( $this->articles ) + count( $this->children ) + |
| 525 | + ( $this->showGallery ? $this->gallery->count() : 0 ); |
607 | 526 | |
608 | | - # Check if there's a "from" or "until" for anything |
609 | | - |
610 | | - // This is a little ugly, but we seem to use different names |
611 | | - // for the paging types then for the messages. |
612 | | - if ( $type === 'article' ) { |
613 | | - $pagingType = 'page'; |
614 | | - } else { |
615 | | - $pagingType = $type; |
616 | | - } |
617 | | - |
618 | | - $fromOrUntil = false; |
619 | | - if ( $this->from[$pagingType] !== null || $this->until[$pagingType] !== null ) { |
620 | | - $fromOrUntil = true; |
621 | | - } |
622 | | - |
623 | | - if ( $dbcnt == $rescnt || ( ( $rescnt == $this->limit || $fromOrUntil ) |
624 | | - && $dbcnt > $rescnt ) ) |
| 527 | + if ( $dbcnt == $rescnt || ( ( $totalrescnt == $this->limit || $this->from |
| 528 | + || $this->until ) && $dbcnt > $rescnt ) ) |
625 | 529 | { |
626 | 530 | # Case 1: seems sane. |
627 | 531 | $totalcnt = $dbcnt; |
628 | | - } elseif ( $rescnt < $this->limit && !$fromOrUntil ) { |
| 532 | + } elseif ( $totalrescnt < $this->limit && !$this->from && !$this->until ) { |
629 | 533 | # Case 2: not sane, but salvageable. Use the number of results. |
630 | 534 | # Since there are fewer than 200, we can also take this opportunity |
631 | 535 | # to refresh the incorrect category table entry -- which should be |
Index: branches/wmf/1.17wmf1/includes/parser/Parser.php |
— | — | @@ -4996,19 +4996,15 @@ |
4997 | 4997 | |
4998 | 4998 | /** |
4999 | 4999 | * Accessor for $mDefaultSort |
5000 | | - * Will use the empty string if none is set. |
| 5000 | + * Will use the title/prefixed title if none is set |
5001 | 5001 | * |
5002 | | - * This value is treated as a prefix, so the |
5003 | | - * empty string is equivalent to sorting by |
5004 | | - * page name. |
5005 | | - * |
5006 | 5002 | * @return string |
5007 | 5003 | */ |
5008 | 5004 | public function getDefaultSort() { |
5009 | 5005 | if ( $this->mDefaultSort !== false ) { |
5010 | 5006 | return $this->mDefaultSort; |
5011 | 5007 | } else { |
5012 | | - return ''; |
| 5008 | + return $this->mTitle->getCategorySortkey(); |
5013 | 5009 | } |
5014 | 5010 | } |
5015 | 5011 | |
Property changes on: branches/wmf/1.17wmf1/includes/parser/Parser.php |
___________________________________________________________________ |
Modified: svn:mergeinfo |
5016 | 5012 | Reverse-merged /trunk/phase3/includes/parser/Parser.php:r81554 |
Index: branches/wmf/1.17wmf1/includes/api/ApiQueryCategoryMembers.php |
— | — | @@ -65,28 +65,28 @@ |
66 | 66 | $fld_ids = isset( $prop['ids'] ); |
67 | 67 | $fld_title = isset( $prop['title'] ); |
68 | 68 | $fld_sortkey = isset( $prop['sortkey'] ); |
69 | | - $fld_sortkeyprefix = isset( $prop['sortkeyprefix'] ); |
70 | 69 | $fld_timestamp = isset( $prop['timestamp'] ); |
71 | | - $fld_type = isset( $prop['type'] ); |
72 | 70 | |
73 | 71 | if ( is_null( $resultPageSet ) ) { |
74 | | - $this->addFields( array( 'cl_from', 'page_namespace', 'page_title' ) ); |
| 72 | + $this->addFields( array( 'cl_from', 'cl_sortkey', 'page_namespace', 'page_title' ) ); |
75 | 73 | $this->addFieldsIf( 'page_id', $fld_ids ); |
76 | | - $this->addFieldsIf( 'cl_sortkey_prefix', $fld_sortkeyprefix ); |
77 | | - $this->addFieldsIf( 'cl_sortkey', $fld_sortkey ); |
78 | 74 | } else { |
79 | 75 | $this->addFields( $resultPageSet->getPageTableFields() ); // will include page_ id, ns, title |
80 | 76 | $this->addFields( array( 'cl_from', 'cl_sortkey' ) ); |
81 | 77 | } |
82 | 78 | |
83 | 79 | $this->addFieldsIf( 'cl_timestamp', $fld_timestamp || $params['sort'] == 'timestamp' ); |
84 | | - $this->addFieldsIf( 'cl_type', $fld_type ); |
85 | | - |
86 | 80 | $this->addTables( array( 'page', 'categorylinks' ) ); // must be in this order for 'USE INDEX' |
| 81 | + // Not needed after bug 10280 is applied to servers |
| 82 | + if ( $params['sort'] == 'timestamp' ) { |
| 83 | + $this->addOption( 'USE INDEX', 'cl_timestamp' ); |
| 84 | + } else { |
| 85 | + $this->addOption( 'USE INDEX', 'cl_sortkey' ); |
| 86 | + } |
87 | 87 | |
| 88 | + $this->addWhere( 'cl_from=page_id' ); |
| 89 | + $this->setContinuation( $params['continue'], $params['dir'] ); |
88 | 90 | $this->addWhereFld( 'cl_to', $categoryTitle->getDBkey() ); |
89 | | - $this->addWhereFld( 'cl_type', $params['type'] ); |
90 | | - |
91 | 91 | // Scanning large datasets for rare categories sucks, and I already told |
92 | 92 | // how to have efficient subcategory access :-) ~~~~ (oh well, domas) |
93 | 93 | global $wgMiserMode; |
— | — | @@ -96,35 +96,18 @@ |
97 | 97 | } else { |
98 | 98 | $this->addWhereFld( 'page_namespace', $params['namespace'] ); |
99 | 99 | } |
100 | | - |
101 | | - $dir = $params['dir'] == 'asc' ? 'newer' : 'older'; |
102 | | - |
103 | 100 | if ( $params['sort'] == 'timestamp' ) { |
104 | | - $this->addWhereRange( 'cl_timestamp', |
105 | | - $dir, |
106 | | - $params['start'], |
107 | | - $params['end'] ); |
108 | | - |
109 | | - $this->addOption( 'USE INDEX', 'cl_timestamp' ); |
| 101 | + $this->addWhereRange( 'cl_timestamp', ( $params['dir'] == 'asc' ? 'newer' : 'older' ), $params['start'], $params['end'] ); |
110 | 102 | } else { |
111 | | - // The below produces ORDER BY cl_type, cl_sortkey, cl_from, possibly with DESC added to each of them |
112 | | - $this->addWhereRange( 'cl_type', $dir, null, null ); |
113 | | - $this->addWhereRange( 'cl_sortkey', |
114 | | - $dir, |
115 | | - $params['startsortkey'], |
116 | | - $params['endsortkey'] ); |
117 | | - $this->addWhereRange( 'cl_from', $dir, null, null ); |
118 | | - $this->addOption( 'USE INDEX', 'cl_sortkey' ); |
| 103 | + $this->addWhereRange( 'cl_sortkey', ( $params['dir'] == 'asc' ? 'newer' : 'older' ), $params['startsortkey'], $params['endsortkey'] ); |
| 104 | + $this->addWhereRange( 'cl_from', ( $params['dir'] == 'asc' ? 'newer' : 'older' ), null, null ); |
119 | 105 | } |
120 | 106 | |
121 | | - $this->setContinuation( $params['continue'], $params['dir'] ); |
122 | | - |
123 | | - $this->addWhere( 'cl_from=page_id' ); |
124 | | - |
125 | 107 | $limit = $params['limit']; |
126 | 108 | $this->addOption( 'LIMIT', $limit + 1 ); |
127 | 109 | |
128 | 110 | $count = 0; |
| 111 | + $lastSortKey = null; |
129 | 112 | $res = $this->select( __METHOD__ ); |
130 | 113 | foreach ( $res as $row ) { |
131 | 114 | if ( ++ $count > $limit ) { |
— | — | @@ -133,7 +116,7 @@ |
134 | 117 | if ( $params['sort'] == 'timestamp' ) { |
135 | 118 | $this->setContinueEnumParameter( 'start', wfTimestamp( TS_ISO_8601, $row->cl_timestamp ) ); |
136 | 119 | } else { |
137 | | - $this->setContinueEnumParameter( 'continue', $row->cl_from ); |
| 120 | + $this->setContinueEnumParameter( 'continue', $this->getContinueStr( $row, $lastSortKey ) ); |
138 | 121 | } |
139 | 122 | break; |
140 | 123 | } |
— | — | @@ -158,12 +141,6 @@ |
159 | 142 | if ( $fld_sortkey ) { |
160 | 143 | $vals['sortkey'] = $row->cl_sortkey; |
161 | 144 | } |
162 | | - if ( $fld_sortkeyprefix ) { |
163 | | - $vals['sortkeyprefix'] = $row->cl_sortkey_prefix; |
164 | | - } |
165 | | - if ( $fld_type ) { |
166 | | - $vals['type'] = $row->cl_type; |
167 | | - } |
168 | 145 | if ( $fld_timestamp ) { |
169 | 146 | $vals['timestamp'] = wfTimestamp( TS_ISO_8601, $row->cl_timestamp ); |
170 | 147 | } |
— | — | @@ -173,13 +150,14 @@ |
174 | 151 | if ( $params['sort'] == 'timestamp' ) { |
175 | 152 | $this->setContinueEnumParameter( 'start', wfTimestamp( TS_ISO_8601, $row->cl_timestamp ) ); |
176 | 153 | } else { |
177 | | - $this->setContinueEnumParameter( 'continue', $row->cl_from ); |
| 154 | + $this->setContinueEnumParameter( 'continue', $this->getContinueStr( $row, $lastSortKey ) ); |
178 | 155 | } |
179 | 156 | break; |
180 | 157 | } |
181 | 158 | } else { |
182 | 159 | $resultPageSet->processDbRow( $row ); |
183 | 160 | } |
| 161 | + $lastSortKey = $row->cl_sortkey; // detect duplicate sortkeys |
184 | 162 | } |
185 | 163 | |
186 | 164 | if ( is_null( $resultPageSet ) ) { |
— | — | @@ -188,6 +166,14 @@ |
189 | 167 | } |
190 | 168 | } |
191 | 169 | |
| 170 | + private function getContinueStr( $row, $lastSortKey ) { |
| 171 | + $ret = $row->cl_sortkey . '|'; |
| 172 | + if ( $row->cl_sortkey == $lastSortKey ) { // duplicate sort key, add cl_from |
| 173 | + $ret .= $row->cl_from; |
| 174 | + } |
| 175 | + return $ret; |
| 176 | + } |
| 177 | + |
192 | 178 | /** |
193 | 179 | * Add DB WHERE clause to continue previous query based on 'continue' parameter |
194 | 180 | */ |
— | — | @@ -196,11 +182,26 @@ |
197 | 183 | return; // This is not a continuation request |
198 | 184 | } |
199 | 185 | |
200 | | - $encFrom = $this->getDB()->addQuotes( intval( $continue ) ); |
| 186 | + $pos = strrpos( $continue, '|' ); |
| 187 | + $sortkey = substr( $continue, 0, $pos ); |
| 188 | + $fromstr = substr( $continue, $pos + 1 ); |
| 189 | + $from = intval( $fromstr ); |
201 | 190 | |
202 | | - $op = ( $dir == 'desc' ? '<=' : '>=' ); |
| 191 | + if ( $from == 0 && strlen( $fromstr ) > 0 ) { |
| 192 | + $this->dieUsage( 'Invalid continue param. You should pass the original value returned by the previous query', 'badcontinue' ); |
| 193 | + } |
203 | 194 | |
204 | | - $this->addWhere( "cl_from $op $encFrom" ); |
| 195 | + $encSortKey = $this->getDB()->addQuotes( $sortkey ); |
| 196 | + $encFrom = $this->getDB()->addQuotes( $from ); |
| 197 | + |
| 198 | + $op = ( $dir == 'desc' ? '<' : '>' ); |
| 199 | + |
| 200 | + if ( $from != 0 ) { |
| 201 | + // Duplicate sort key continue |
| 202 | + $this->addWhere( "cl_sortkey$op$encSortKey OR (cl_sortkey=$encSortKey AND cl_from$op=$encFrom)" ); |
| 203 | + } else { |
| 204 | + $this->addWhere( "cl_sortkey$op=$encSortKey" ); |
| 205 | + } |
205 | 206 | } |
206 | 207 | |
207 | 208 | public function getAllowedParams() { |
— | — | @@ -216,8 +217,6 @@ |
217 | 218 | 'ids', |
218 | 219 | 'title', |
219 | 220 | 'sortkey', |
220 | | - 'sortkeyprefix', |
221 | | - 'type', |
222 | 221 | 'timestamp', |
223 | 222 | ) |
224 | 223 | ), |
— | — | @@ -225,15 +224,6 @@ |
226 | 225 | ApiBase::PARAM_ISMULTI => true, |
227 | 226 | ApiBase::PARAM_TYPE => 'namespace', |
228 | 227 | ), |
229 | | - 'type' => array( |
230 | | - ApiBase::PARAM_ISMULTI => true, |
231 | | - ApiBase::PARAM_DFLT => 'page|subcat|file', |
232 | | - ApiBase::PARAM_TYPE => array( |
233 | | - 'page', |
234 | | - 'subcat', |
235 | | - 'file' |
236 | | - ) |
237 | | - ), |
238 | 228 | 'continue' => null, |
239 | 229 | 'limit' => array( |
240 | 230 | ApiBase::PARAM_TYPE => 'limit', |
— | — | @@ -274,15 +264,12 @@ |
275 | 265 | 'title' => 'Which category to enumerate (required). Must include Category: prefix', |
276 | 266 | 'prop' => array( |
277 | 267 | 'What pieces of information to include', |
278 | | - ' ids - Adds the page ID', |
279 | | - ' title - Adds the title and namespace ID of the page', |
280 | | - ' sortkey - Adds the sortkey used for sorting in the category (may not be human-readble)', |
281 | | - ' sortkeyprefix - Adds the sortkey prefix used for sorting in the category (human-readable part of the sortkey)', |
282 | | - ' type - Adds the type that the page has been categorised as (page, subcat or file)', |
283 | | - ' timestamp - Adds the timestamp of when the page was included', |
| 268 | + ' ids - Adds the page id', |
| 269 | + ' title - Adds the title and namespace id of the page', |
| 270 | + ' sortkey - Adds the sortkey used for the category', |
| 271 | + ' timestamp - Adds the timestamp of when the page was included', |
284 | 272 | ), |
285 | 273 | 'namespace' => 'Only include pages in these namespaces', |
286 | | - 'type' => 'What type of category members to include', |
287 | 274 | 'sort' => 'Property to sort by', |
288 | 275 | 'dir' => 'In which direction to sort', |
289 | 276 | 'start' => "Timestamp to start listing from. Can only be used with {$p}sort=timestamp", |
Index: branches/wmf/1.17wmf1/includes/LinksUpdate.php |
— | — | @@ -72,11 +72,10 @@ |
73 | 73 | # it truncated by DB, and then doesn't get |
74 | 74 | # matched when comparing existing vs current |
75 | 75 | # categories, causing bug 25254. |
76 | | - # Also. substr behaves weird when given "". |
77 | | - if ( $sortkey !== '' ) { |
78 | | - $sortkey = substr( $sortkey, 0, 255 ); |
79 | | - } |
| 76 | + $sortkey = substr( $sortkey, 0, 255 ); |
80 | 77 | } |
| 78 | + var_dump( $this->mCategories ); |
| 79 | + |
81 | 80 | |
82 | 81 | $this->mRecursive = $recursive; |
83 | 82 | |
— | — | @@ -435,39 +434,20 @@ |
436 | 435 | * @private |
437 | 436 | */ |
438 | 437 | function getCategoryInsertions( $existing = array() ) { |
439 | | - global $wgContLang, $wgCategoryCollation; |
| 438 | + global $wgContLang; |
440 | 439 | $diffs = array_diff_assoc( $this->mCategories, $existing ); |
441 | 440 | $arr = array(); |
442 | | - foreach ( $diffs as $name => $prefix ) { |
| 441 | + foreach ( $diffs as $name => $sortkey ) { |
443 | 442 | $nt = Title::makeTitleSafe( NS_CATEGORY, $name ); |
444 | 443 | $wgContLang->findVariantLink( $name, $nt, true ); |
445 | | - |
446 | | - if ( $this->mTitle->getNamespace() == NS_CATEGORY ) { |
447 | | - $type = 'subcat'; |
448 | | - } elseif ( $this->mTitle->getNamespace() == NS_FILE ) { |
449 | | - $type = 'file'; |
450 | | - } else { |
451 | | - $type = 'page'; |
452 | | - } |
453 | | - |
454 | | - # Treat custom sortkeys as a prefix, so that if multiple |
455 | | - # things are forced to sort as '*' or something, they'll |
456 | | - # sort properly in the category rather than in page_id |
457 | | - # order or such. |
458 | | - $sortkey = Collation::singleton()->getSortKey( |
459 | | - $this->mTitle->getCategorySortkey( $prefix ) ); |
460 | | - |
461 | 444 | $arr[] = array( |
462 | 445 | 'cl_from' => $this->mId, |
463 | 446 | 'cl_to' => $name, |
464 | 447 | 'cl_sortkey' => $sortkey, |
465 | | - 'cl_timestamp' => $this->mDb->timestamp(), |
466 | | - 'cl_sortkey_prefix' => $prefix, |
467 | | - 'cl_collation' => $wgCategoryCollation, |
468 | | - 'cl_type' => $type, |
| 448 | + 'cl_timestamp' => $this->mDb->timestamp() |
469 | 449 | ); |
470 | 450 | } |
471 | | - return $arr; |
| 451 | + return $arr; |
472 | 452 | } |
473 | 453 | |
474 | 454 | /** |
— | — | @@ -687,13 +667,14 @@ |
688 | 668 | * @private |
689 | 669 | */ |
690 | 670 | function getExistingCategories() { |
691 | | - $res = $this->mDb->select( 'categorylinks', array( 'cl_to', 'cl_sortkey_prefix' ), |
| 671 | + $res = $this->mDb->select( 'categorylinks', array( 'cl_to', 'cl_sortkey' ), |
692 | 672 | array( 'cl_from' => $this->mId ), __METHOD__, $this->mOptions ); |
693 | 673 | $arr = array(); |
694 | | - foreach ( $res as $row ) { |
695 | | - $arr[$row->cl_to] = $row->cl_sortkey_prefix; |
| 674 | + while ( $row = $this->mDb->fetchObject( $res ) ) { |
| 675 | + $arr[$row->cl_to] = $row->cl_sortkey; |
696 | 676 | } |
697 | | - return $arr; |
| 677 | + $this->mDb->freeResult( $res ); |
| 678 | + return $arr; |
698 | 679 | } |
699 | 680 | |
700 | 681 | /** |
Index: branches/wmf/1.17wmf1/includes/Title.php |
— | — | @@ -3102,22 +3102,27 @@ |
3103 | 3103 | } |
3104 | 3104 | $redirid = $this->getArticleID(); |
3105 | 3105 | |
3106 | | - // Refresh the sortkey for this row. Be careful to avoid resetting |
3107 | | - // cl_timestamp, which may disturb time-based lists on some sites. |
3108 | | - $prefix = $dbw->selectField( |
3109 | | - 'categorylinks', |
3110 | | - 'cl_sortkey_prefix', |
3111 | | - array( 'cl_from' => $pageid ), |
3112 | | - __METHOD__ |
3113 | | - ); |
| 3106 | + // Category memberships include a sort key which may be customized. |
| 3107 | + // If it's left as the default (the page title), we need to update |
| 3108 | + // the sort key to match the new title. |
| 3109 | + // |
| 3110 | + // Be careful to avoid resetting cl_timestamp, which may disturb |
| 3111 | + // time-based lists on some sites. |
| 3112 | + // |
| 3113 | + // Warning -- if the sort key is *explicitly* set to the old title, |
| 3114 | + // we can't actually distinguish it from a default here, and it'll |
| 3115 | + // be set to the new title even though it really shouldn't. |
| 3116 | + // It'll get corrected on the next edit, but resetting cl_timestamp. |
3114 | 3117 | $dbw->update( 'categorylinks', |
3115 | 3118 | array( |
3116 | | - 'cl_sortkey' => Collation::singleton()->getSortKey( |
3117 | | - $nt->getCategorySortkey( $prefix ) ), |
| 3119 | + 'cl_sortkey' => $nt->getPrefixedText(), |
3118 | 3120 | 'cl_timestamp=cl_timestamp' ), |
3119 | | - array( 'cl_from' => $pageid ), |
| 3121 | + array( |
| 3122 | + 'cl_from' => $pageid, |
| 3123 | + 'cl_sortkey' => $this->getPrefixedText() ), |
3120 | 3124 | __METHOD__ ); |
3121 | 3125 | |
| 3126 | + |
3122 | 3127 | if ( $protected ) { |
3123 | 3128 | # Protect the redirect title as the title used to be... |
3124 | 3129 | $dbw->insertSelect( 'page_restrictions', 'page_restrictions', |