Index: branches/change-tagging/phase3/maintenance/updaters.inc |
— | — | @@ -149,6 +149,8 @@ |
150 | 150 | array( 'add_field', 'site_stats', 'ss_active_users', 'patch-ss_active_users.sql' ), |
151 | 151 | array( 'do_active_users_init' ), |
152 | 152 | array( 'add_field', 'ipblocks', 'ipb_allow_usertalk', 'patch-ipb_allow_usertalk.sql' ), |
| 153 | + array( 'add_table', 'change_tag', 'patch-change_tag.sql' ), |
| 154 | + array( 'add_table', 'tag_summary', 'patch-change_tag.sql' ), |
153 | 155 | ), |
154 | 156 | |
155 | 157 | 'sqlite' => array( |
Index: branches/change-tagging/phase3/maintenance/tables.sql |
— | — | @@ -1234,4 +1234,30 @@ |
1235 | 1235 | ul_key varchar(255) NOT NULL primary key |
1236 | 1236 | ) /*$wgDBTableOptions*/; |
1237 | 1237 | |
| 1238 | +--- A table to track tags for revisions, logs and recent changes. |
| 1239 | +CREATE TABLE /*_*/change_tag ( |
| 1240 | + ct_rc_id int NULL, |
| 1241 | + ct_log_id int NULL, |
| 1242 | + ct_rev_id int NULL, |
| 1243 | + ct_tag varchar(255) NOT NULL, |
| 1244 | + ct_params BLOB NULL, |
| 1245 | + |
| 1246 | + UNIQUE KEY (ct_rc_id,ct_tag), |
| 1247 | + UNIQUE KEY (ct_log_id,ct_tag), |
| 1248 | + UNIQUE KEY (ct_rev_id,ct_tag), |
| 1249 | + KEY (ct_tag,ct_rc_id,ct_rev_id,ct_log_id) -- Covering index, so we can pull all the info only out of the index. |
| 1250 | +) /*$wgDBTableOptions*/; |
| 1251 | + |
| 1252 | +-- Rollup table to pull a LIST of tags simply without ugly GROUP_CONCAT that only works on MySQL 4.1+ |
| 1253 | +CREATE TABLE /*_*/tag_summary ( |
| 1254 | + ts_rc_id int NULL, |
| 1255 | + ts_log_id int NULL, |
| 1256 | + ts_rev_id int NULL, |
| 1257 | + ts_tags BLOB NOT NULL, |
| 1258 | + |
| 1259 | + UNIQUE KEY (ts_rc_id), |
| 1260 | + UNIQUE KEY (ts_log_id), |
| 1261 | + UNIQUE KEY (ts_rev_id), |
| 1262 | +) /*$wgDBTableOptions*/; |
| 1263 | + |
1238 | 1264 | -- vim: sw=2 sts=2 et |
Index: branches/change-tagging/phase3/includes/ChangesList.php |
— | — | @@ -338,6 +338,7 @@ |
339 | 339 | $this->insertDateHeader( $dateheader, $rc->mAttribs['rc_timestamp'] ); |
340 | 340 | |
341 | 341 | $s = ''; |
| 342 | + $classes = array(); |
342 | 343 | // Moved pages |
343 | 344 | if( $rc->mAttribs['rc_type'] == RC_MOVE || $rc->mAttribs['rc_type'] == RC_MOVE_OVER_REDIRECT ) { |
344 | 345 | $this->insertMove( $s, $rc ); |
— | — | @@ -383,11 +384,28 @@ |
384 | 385 | $s .= ' ' . wfMsg( 'number_of_watching_users_RCview', |
385 | 386 | $wgContLang->formatNum($rc->numberofWatchingusers) ); |
386 | 387 | } |
| 388 | + # Tags, if any. |
| 389 | + if ($rc->mAttribs['ts_tags']) { |
| 390 | + $tags = explode( ',', $rc->mAttribs['ts_tags'] ); |
| 391 | + $displayTags = array(); |
| 392 | + foreach( $tags as $tag ) { |
| 393 | + if (!wfEmptyMsg( "recentchanges-tag-$tag" , wfMsg( "recentchanges-tag-$tag" ) ) ) { |
| 394 | + $displayTags[] = wfMsgExt( "recentchanges-tag-$tag", 'parseinline' ); |
| 395 | + } else { |
| 396 | + $displayTags[] = $tag; |
| 397 | + } |
| 398 | + } |
| 399 | + |
| 400 | + $s .= ' (' . implode( ', ', $displayTags ) . ')'; |
| 401 | + $classes = array_merge( $classes, $tags ); |
| 402 | + } |
387 | 403 | |
| 404 | + ## Classes |
| 405 | + $classes = implode( ' ', $classes ); |
388 | 406 | wfRunHooks( 'OldChangesListRecentChangesLine', array(&$this, &$s, $rc) ); |
389 | 407 | |
390 | 408 | wfProfileOut( __METHOD__ ); |
391 | | - return "$dateheader<li>$s</li>\n"; |
| 409 | + return "$dateheader<li class=\"$classes\">$s</li>\n"; |
392 | 410 | } |
393 | 411 | } |
394 | 412 | |
Index: branches/change-tagging/phase3/includes/specials/SpecialRecentchangeslinked.php |
— | — | @@ -82,6 +82,11 @@ |
83 | 83 | $join_conds['watchlist'] = array( 'LEFT JOIN', "wl_user={$uid} AND wl_title=rc_title AND wl_namespace=rc_namespace" ); |
84 | 84 | } |
85 | 85 | |
| 86 | + // JOIN on tag_summary |
| 87 | + $tables[] = 'tag_summary'; |
| 88 | + $select[] = 'ts_tags'; |
| 89 | + $join_conds['tag_summary'] = array( 'LEFT JOIN', 'ts_rc_id=rc_id' ); |
| 90 | + |
86 | 91 | // XXX: parent class does this, should we too? |
87 | 92 | // wfRunHooks('SpecialRecentChangesQuery', array( &$conds, &$tables, &$join_conds, $opts ) ); |
88 | 93 | |
Index: branches/change-tagging/phase3/includes/specials/SpecialNewpages.php |
— | — | @@ -235,6 +235,9 @@ |
236 | 236 | */ |
237 | 237 | public function formatRow( $result ) { |
238 | 238 | global $wgLang, $wgContLang, $wgUser; |
| 239 | + |
| 240 | + $classes = array(); |
| 241 | + |
239 | 242 | $dm = $wgContLang->getDirMark(); |
240 | 243 | |
241 | 244 | $title = Title::makeTitleSafe( $result->rc_namespace, $result->rc_title ); |
— | — | @@ -247,9 +250,30 @@ |
248 | 251 | $ulink = $this->skin->userLink( $result->rc_user, $result->rc_user_text ) . ' ' . |
249 | 252 | $this->skin->userToolLinks( $result->rc_user, $result->rc_user_text ); |
250 | 253 | $comment = $this->skin->commentBlock( $result->rc_comment ); |
251 | | - $css = $this->patrollable( $result ) ? " class='not-patrolled'" : ''; |
| 254 | + |
| 255 | + if ( $this->patrollable( $result ) ) |
| 256 | + $classes[] = 'not-patrolled'; |
252 | 257 | |
253 | | - return "<li{$css}>{$time} {$dm}{$plink} ({$hist}) {$dm}[{$length}] {$dm}{$ulink} {$comment}</li>\n"; |
| 258 | + # Tags, if any. |
| 259 | + $tagDisplay = ''; |
| 260 | + if ($result->ts_tags) { |
| 261 | + $tags = explode( ',', $result->ts_tags ); |
| 262 | + $displayTags = array(); |
| 263 | + foreach( $tags as $tag ) { |
| 264 | + if (!wfEmptyMsg( "recentchanges-tag-$tag" , wfMsg( "recentchanges-tag-$tag" ) ) ) { |
| 265 | + $displayTags[] = wfMsgExt( "recentchanges-tag-$tag", 'parseinline' ); |
| 266 | + } else { |
| 267 | + $displayTags[] = $tag; |
| 268 | + } |
| 269 | + } |
| 270 | + |
| 271 | + $tagDisplay = ' (' . implode( ', ', $displayTags ) . ')'; |
| 272 | + $classes = array_merge( $classes, $tags ); |
| 273 | + } |
| 274 | + |
| 275 | + $css = count($classes) ? ' class="'.implode( " ", $classes).'"' : ''; |
| 276 | + |
| 277 | + return "<li{$css}>{$time} {$dm}{$plink} ({$hist}) {$dm}[{$length}] {$dm}{$ulink} {$comment} {$tagDisplay}</li>\n"; |
254 | 278 | } |
255 | 279 | |
256 | 280 | /** |
— | — | @@ -378,7 +402,6 @@ |
379 | 403 | } else { |
380 | 404 | $rcIndexes = array( 'rc_timestamp' ); |
381 | 405 | } |
382 | | - $conds[] = 'page_id = rc_cur_id'; |
383 | 406 | |
384 | 407 | # $wgEnableNewpagesUserFilter - temp WMF hack |
385 | 408 | if( $wgEnableNewpagesUserFilter && $user ) { |
— | — | @@ -401,11 +424,15 @@ |
402 | 425 | } |
403 | 426 | |
404 | 427 | return array( |
405 | | - 'tables' => array( 'recentchanges', 'page' ), |
| 428 | + 'tables' => array( 'recentchanges', 'page', 'tag_summary' ), |
406 | 429 | 'fields' => 'rc_namespace,rc_title, rc_cur_id, rc_user,rc_user_text,rc_comment, |
407 | | - rc_timestamp,rc_patrolled,rc_id,page_len as length, page_latest as rev_id', |
| 430 | + rc_timestamp,rc_patrolled,rc_id,page_len as length, page_latest as rev_id, ts_tags', |
408 | 431 | 'conds' => $conds, |
409 | | - 'options' => array( 'USE INDEX' => array('recentchanges' => $rcIndexes) ) |
| 432 | + 'options' => array( 'USE INDEX' => array('recentchanges' => $rcIndexes) ), |
| 433 | + 'join_conds' => array( |
| 434 | + 'tag_summary' => array('LEFT JOIN', 'ts_rc_id=rc_id'), |
| 435 | + 'page' => array('INNER JOIN', 'page_id=rc_cur_id'), |
| 436 | + ), |
410 | 437 | ); |
411 | 438 | } |
412 | 439 | |
Index: branches/change-tagging/phase3/includes/specials/SpecialRecentchanges.php |
— | — | @@ -274,13 +274,19 @@ |
275 | 275 | $namespace = $opts['namespace']; |
276 | 276 | $invert = $opts['invert']; |
277 | 277 | |
| 278 | + $join_conds = array(); |
| 279 | + |
278 | 280 | // JOIN on watchlist for users |
279 | 281 | if( $uid ) { |
280 | 282 | $tables[] = 'watchlist'; |
281 | | - $join_conds = array( 'watchlist' => array('LEFT JOIN', |
282 | | - "wl_user={$uid} AND wl_title=rc_title AND wl_namespace=rc_namespace") ); |
| 283 | + $join_conds['watchlist'] = array('LEFT JOIN', |
| 284 | + "wl_user={$uid} AND wl_title=rc_title AND wl_namespace=rc_namespace"); |
283 | 285 | } |
284 | 286 | |
| 287 | + // JOIN on tag_summary |
| 288 | + $tables[] = 'tag_summary'; |
| 289 | + $join_conds['tag_summary'] = array( 'LEFT JOIN', 'ts_rc_id=rc_id' ); |
| 290 | + |
285 | 291 | wfRunHooks('SpecialRecentChangesQuery', array( &$conds, &$tables, &$join_conds, $opts ) ); |
286 | 292 | |
287 | 293 | // Is there either one namespace selected or excluded? |
Index: branches/change-tagging/phase3/includes/specials/SpecialContributions.php |
— | — | @@ -392,13 +392,18 @@ |
393 | 393 | |
394 | 394 | function getQueryInfo() { |
395 | 395 | list( $tables, $index, $userCond, $join_cond ) = $this->getUserCond(); |
396 | | - $conds = array_merge( array('page_id=rev_page'), $userCond, $this->getNamespaceCond() ); |
| 396 | + |
| 397 | + $tables[] = 'tag_summary'; |
| 398 | + $join_cond['tag_summary'] = array('LEFT JOIN','ts_rev_id=rev_id'); |
| 399 | + $join_cond['page'] = array( 'INNER JOIN', 'page_id=rev_page' ); |
| 400 | + |
| 401 | + $conds = array_merge( $userCond, $this->getNamespaceCond() ); |
397 | 402 | $queryInfo = array( |
398 | 403 | 'tables' => $tables, |
399 | 404 | 'fields' => array( |
400 | 405 | 'page_namespace', 'page_title', 'page_is_new', 'page_latest', 'rev_id', 'rev_page', |
401 | 406 | 'rev_text_id', 'rev_timestamp', 'rev_comment', 'rev_minor_edit', 'rev_user', |
402 | | - 'rev_user_text', 'rev_parent_id', 'rev_deleted' |
| 407 | + 'rev_user_text', 'rev_parent_id', 'rev_deleted', 'ts_tags', |
403 | 408 | ), |
404 | 409 | 'conds' => $conds, |
405 | 410 | 'options' => array( 'USE INDEX' => array('revision' => $index) ), |
— | — | @@ -464,6 +469,7 @@ |
465 | 470 | |
466 | 471 | $sk = $this->getSkin(); |
467 | 472 | $rev = new Revision( $row ); |
| 473 | + $classes = array(); |
468 | 474 | |
469 | 475 | $page = Title::makeTitle( $row->page_namespace, $row->page_title ); |
470 | 476 | $link = $sk->makeKnownLinkObj( $page ); |
— | — | @@ -520,10 +526,28 @@ |
521 | 527 | if( $rev->isDeleted( Revision::DELETED_TEXT ) ) { |
522 | 528 | $ret .= ' ' . wfMsgHtml( 'deletedrev' ); |
523 | 529 | } |
| 530 | + |
| 531 | + # Tags, if any. |
| 532 | + if ($row->ts_tags) { |
| 533 | + $tags = explode( ',', $row->ts_tags ); |
| 534 | + $displayTags = array(); |
| 535 | + foreach( $tags as $tag ) { |
| 536 | + if (!wfEmptyMsg( "recentchanges-tag-$tag" , wfMsg( "recentchanges-tag-$tag" ) ) ) { |
| 537 | + $displayTags[] = wfMsgExt( "recentchanges-tag-$tag", 'parseinline' ); |
| 538 | + } else { |
| 539 | + $displayTags[] = $tag; |
| 540 | + } |
| 541 | + } |
| 542 | + |
| 543 | + $ret .= ' (' . implode( ', ', $displayTags ) . ')'; |
| 544 | + $classes = array_merge( $classes, $tags ); |
| 545 | + } |
| 546 | + |
524 | 547 | // Let extensions add data |
525 | 548 | wfRunHooks( 'ContributionsLineEnding', array( &$this, &$ret, $row ) ); |
526 | | - |
527 | | - $ret = "<li>$ret</li>\n"; |
| 549 | + |
| 550 | + $classes = implode( ' ', $classes ); |
| 551 | + $ret = "<li class=\"$classes\">$ret</li>\n"; |
528 | 552 | wfProfileOut( __METHOD__ ); |
529 | 553 | return $ret; |
530 | 554 | } |
Index: branches/change-tagging/phase3/includes/specials/SpecialWatchlist.php |
— | — | @@ -189,12 +189,13 @@ |
190 | 190 | } |
191 | 191 | $form .= '<hr />'; |
192 | 192 | |
193 | | - $tables = array( 'recentchanges', 'watchlist', 'page' ); |
194 | | - $fields = array( "{$recentchanges}.*" ); |
| 193 | + $tables = array( 'recentchanges', 'watchlist', 'page', 'tag_summary' ); |
| 194 | + $fields = array( "{$recentchanges}.*", 'ts_tags' ); |
195 | 195 | $conds = array(); |
196 | 196 | $join_conds = array( |
197 | 197 | 'watchlist' => array('INNER JOIN',"wl_user='{$uid}' AND wl_namespace=rc_namespace AND wl_title=rc_title"), |
198 | | - 'page' => array('LEFT JOIN','rc_cur_id=page_id') |
| 198 | + 'page' => array('LEFT JOIN','rc_cur_id=page_id'), |
| 199 | + 'tag_summary' => array('LEFT JOIN', 'ts_rc_id=rc_id'), |
199 | 200 | ); |
200 | 201 | $options = array( 'ORDER BY' => 'rc_timestamp DESC' ); |
201 | 202 | if( $wgShowUpdatedMarker ) { |