r52408 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r52407‎ | r52408 | r52409 >
Date:19:27, 25 June 2009
Author:werdna
Status:deferred
Tags:
Comment:
LQT updates:
* Store thread owner and subject information in the thread table, rather than relying on properties of the root.
* Change title structure, now includes the talk page and user in permalinks, disambiguating with numbers only when necessary.
* Reimplement TalkpageView as a paged setup. Instead of having threads artificially disappear when they're archived, they now naturally drop off the bottom of the page.
Modified paths:
  • /trunk/extensions/LiquidThreads/classes/LqtThread.php (modified) (history)
  • /trunk/extensions/LiquidThreads/classes/LqtThreads.php (modified) (history)
  • /trunk/extensions/LiquidThreads/classes/LqtView.php (modified) (history)
  • /trunk/extensions/LiquidThreads/lqt-schema-change-1.sql (deleted) (history)
  • /trunk/extensions/LiquidThreads/lqt-schema-change-2.sql (deleted) (history)
  • /trunk/extensions/LiquidThreads/lqt-schema-change-3.sql (deleted) (history)
  • /trunk/extensions/LiquidThreads/lqt-schema-change-4.sql (deleted) (history)
  • /trunk/extensions/LiquidThreads/lqt-schema-change-5.sql (deleted) (history)
  • /trunk/extensions/LiquidThreads/lqt-schema-change-6.sql (deleted) (history)
  • /trunk/extensions/LiquidThreads/lqt.sql (modified) (history)
  • /trunk/extensions/LiquidThreads/pages/TalkpageView.php (modified) (history)
  • /trunk/extensions/LiquidThreads/schema-changes (added) (history)
  • /trunk/extensions/LiquidThreads/schema-changes/lqt-schema-change-1.sql (added) (history)
  • /trunk/extensions/LiquidThreads/schema-changes/lqt-schema-change-2.sql (added) (history)
  • /trunk/extensions/LiquidThreads/schema-changes/lqt-schema-change-3.sql (added) (history)
  • /trunk/extensions/LiquidThreads/schema-changes/lqt-schema-change-4.sql (added) (history)
  • /trunk/extensions/LiquidThreads/schema-changes/lqt-schema-change-5.sql (added) (history)
  • /trunk/extensions/LiquidThreads/schema-changes/lqt-schema-change-6.sql (added) (history)
  • /trunk/extensions/LiquidThreads/schema-changes/lqt-schema-change-thread_summary.sql (added) (history)

Diff [purge]

Index: trunk/extensions/LiquidThreads/lqt-schema-change-3.sql
@@ -1,13 +0,0 @@
2 -alter table thread add column thread_ancestor int(8) unsigned not null;
3 -alter table thread add column thread_parent int(8) unsigned null;
4 -alter table thread add index thread_ancestor (thread_ancestor);
5 -
6 -update thread set thread_ancestor = substring_index(thread_path, ".", 1),
7 - thread_parent = substring_index(substring_index(thread_path, ".", -2), ".", 1 )
8 -where locate(".", thread_path) != 0;
9 -
10 -update thread set thread_ancestor = substring_index(thread_path, ".", 1),
11 - thread_parent = null
12 -where locate(".", thread_path) = 0;
13 -
14 -alter table thread drop column thread_path;
Index: trunk/extensions/LiquidThreads/lqt-schema-change-4.sql
@@ -1,4 +0,0 @@
2 -alter table thread change thread_timestamp thread_modified char(14) binary NOT NULL default '';
3 -alter table thread add column thread_created char(14) binary NOT NULL default '';
4 -update thread set thread_created = thread_modified;
5 -alter table thread add index thread_created (thread_created);
Index: trunk/extensions/LiquidThreads/lqt-schema-change-5.sql
@@ -1,13 +0,0 @@
2 -alter table thread add column thread_editedness int(1) NOT NULL default 0;
3 -
4 -update thread join thread as child on child.thread_parent = thread.thread_id set thread.thread_editedness = 1;
5 -
6 -create temporary table counts ( thread_id int(8) unsigned, revision_count int(8) unsigned, author_count int(8) unsigned, rev_user int(8) unsigned );
7 -
8 -insert into counts (thread_id, revision_count, author_count, rev_user) select thread_id, count(thread_id), count(distinct rev_user), rev_user from thread join revision on rev_page = thread_root group by thread_id;
9 -
10 -update thread join counts on thread.thread_id = counts.thread_id set thread_editedness = 2 where revision_count > 1;
11 -
12 -update thread join counts on thread.thread_id = counts.thread_id set thread_editedness = 3 where author_count > 1 or (rev_user = 0 and revision_count > 1);
13 -
14 -drop table counts;
Index: trunk/extensions/LiquidThreads/lqt-schema-change-6.sql
@@ -1 +0,0 @@
2 -alter table thread add index thread_summary_page (thread_summary_page);
Index: trunk/extensions/LiquidThreads/lqt-schema-change-1.sql
@@ -1,5 +0,0 @@
2 -update thread, page set thread_article_title=page_title, thread_article_namespace=page_namespace where page_id=thread_article and thread_article is not null and thread_article != 0;
3 -
4 -alter table thread drop column thread_article;
5 -alter table thread modify thread_article_namespace not null;
6 -alter table thread modify thread_article_title varchar(255) binary not null;
Index: trunk/extensions/LiquidThreads/lqt-schema-change-2.sql
@@ -1,4 +0,0 @@
2 -update page set page_namespace=90 where page_namespace=16;
3 -update page set page_namespace=91 where page_namespace=17;
4 -update page set page_namespace=92 where page_namespace=18;
5 -update page set page_namespace=93 where page_namespace=19;
Index: trunk/extensions/LiquidThreads/pages/TalkpageView.php
@@ -4,7 +4,7 @@
55
66 class TalkpageView extends LqtView {
77 /* Added to SkinTemplateTabs hook in TalkpageView::show(). */
8 - function customizeTabs( $skintemplate, $content_actions ) {
 8+ function customizeTabs( $skintemplate, &$content_actions ) {
99 // The arguments are passed in by reference.
1010 unset( $content_actions['edit'] );
1111 unset( $content_actions['viewsource'] );
@@ -23,15 +23,6 @@
2424 return true;
2525 }
2626
27 - function permalinksForThreads( $threads, $method = null, $operand = null ) {
28 - $permalinks = array();
29 - foreach ( $threads as $t ) {
30 - $l = $t->subjectWithoutIncrement();
31 - $permalinks[] = self::permalink( $t, $l, $method, $operand );
32 - }
33 - return $permalinks;
34 - }
35 -
3627 function showHeader() {
3728 /* Show the contents of the actual talkpage article if it exists. */
3829
@@ -111,7 +102,7 @@
112103 $subject = Xml::tags( 'a', array( 'href' => $anchor ), $subject );
113104 $row .= Xml::tags( 'td', null, $subject );
114105
115 - $author = $thread->root()->originalAuthor();
 106+ $author = $thread->author();
116107 $authorLink = $sk->userLink( $author->getID(), $author->getName() );
117108 $row .= Xml::tags( 'td', null, $authorLink );
118109
@@ -140,23 +131,13 @@
141132 return $html;
142133 }
143134
144 - function getArchiveWidget( $threads ) {
 135+ function getArchiveWidget( ) {
145136 wfLoadExtensionMessages( 'LiquidThreads' );
146 -
147 - $threadlinks = self::permalinksForThreads( $threads );
148 -
149 - if ( count( $threadlinks ) > 0 ) {
150 - $url = $this->talkpageUrl( $this->title, 'talkpage_archive' );
151 -
152 - $html = '';
153 - $html = Xml::tags( 'h2', array( 'class' => 'lqt_recently_archived' ),
154 - wfMsgExt( 'lqt_recently_archived', 'parseinline' ) );
155 - $html .= $this->getList( 'ul', '', '', $threadlinks );
156 - $html = Xml::tags( 'div', array( 'class' => 'lqt_archive_teaser' ), $html );
157 - return $html;
158 - }
159 -
160 - return '';
 137+ $url = $this->talkpageUrl( $this->title, 'talkpage_archive' );
 138+
 139+ $html = '';
 140+ $html = Xml::tags( 'div', array( 'class' => 'lqt_archive_teaser' ), $html );
 141+ return $html;
161142 }
162143
163144 function showTalkpageViewOptions( $article ) {
@@ -186,7 +167,7 @@
187168 $html .= Xml::label( wfMsg( 'lqt_sorting_order' ), 'lqt_sort_select' ) . ' ';
188169
189170 $sortOrderSelect =
190 - new XmlSelect( 'lqt_order', 'lqt_sort_select', $this->sort_order );
 171+ new XmlSelect( 'lqt_order', 'lqt_sort_select', $this->getSortType() );
191172
192173 $sortOrderSelect->setAttribute( 'class', 'lqt_sort_select' );
193174 $sortOrderSelect->addOption( wfMsg( 'lqt_sort_newest_changes' ),
@@ -223,7 +204,22 @@
224205
225206 $this->output->addHTML( $html );
226207 }
 208+ }
 209+
 210+ function getArchiveTeaser() {
 211+ $archiveBrowseLink = $this->talkpageLink( $this->title,
 212+ wfMsgExt( 'lqt_browse_archive_without_recent', 'parseinline' ),
 213+ 'talkpage_archive' );
 214+ $archiveBrowseLink = Xml::tags( 'div', array( 'class' => 'lqt_browse_archive' ),
 215+ $archiveBrowseLink );
 216+ $archiveBrowseLink = Xml::tags( 'div', array( 'class' => 'lqt_archive_teaser_empty' ),
 217+ $archiveBrowseLink );
 218+
 219+ $archiveWidget = $this->getArchiveWidget( $recently_archived_threads );
227220
 221+ $html = Xml::tags( 'div', array( 'class' => 'lqt_toc_archive_wrapper' ),
 222+ $archiveBrowseLink . $toc .
 223+ $archiveWidget );
228224 }
229225
230226 function show() {
@@ -253,40 +249,204 @@
254250 $this->output->addHTML( Xml::tags( 'strong', null, $newThreadLink ) );
255251 }
256252
257 - $queryType =
258 - $wgRequest->getBool( 'lqt_show_deleted_threads' )
259 - ? 'fresh' : 'fresh-undeleted';
260 - $threads = $this->queries->query( $queryType );
261 -
262 - $archiveBrowseLink = $this->talkpageLink( $this->title,
263 - wfMsgExt( 'lqt_browse_archive_without_recent', 'parseinline' ),
264 - 'talkpage_archive' );
265 - $archiveBrowseLink = Xml::tags( 'div', array( 'class' => 'lqt_browse_archive' ),
266 - $archiveBrowseLink );
267 - $archiveBrowseLink = Xml::tags( 'div', array( 'class' => 'lqt_archive_teaser_empty' ),
268 - $archiveBrowseLink );
 253+ $pager = $this->getPager();
269254
270 - $recently_archived_threads = $this->queries->query( 'recently-archived' );
 255+ $threads = $this->getPageThreads( $pager );
271256
 257+// $html .= $this->getArchiveWidget();
 258+
272259 $toc = '';
273 - if ( count( $threads ) > 1 || count( $recently_archived_threads ) > 0 ) {
 260+ if ( count( $threads ) > 1 ) {
274261 $toc = $this->getTOC( $threads );
275262 }
276263
277 - $archiveWidget = $this->getArchiveWidget( $recently_archived_threads );
278 -
279 - $html = Xml::tags( 'div', array( 'class' => 'lqt_toc_archive_wrapper' ),
280 - $archiveBrowseLink . $toc .
281 - $archiveWidget );
282 -
283264 $html .= Xml::element( 'br', array( 'style' => 'clear: both;' ) );
284265
 266+ $html .= $pager->getNavigationBar();
 267+
285268 $this->output->addHTML( $html );
286269
287270 foreach ( $threads as $t ) {
288271 $this->showThread( $t );
289272 }
290273
 274+ $this->output->addHTML( $pager->getNavigationBar() );
 275+
291276 return false;
292277 }
 278+
 279+ function getPager() {
 280+ $showDeleted = $this->request->getBool( 'lqt_show_deleted_threads' );
 281+ $showDeleted = $showDeleted && $this->user->isAllowed( 'deletedhistory' );
 282+
 283+ $sortType = $this->getSortType();
 284+ return new LqtDiscussionPager( $this->article, $sortType, $showDeleted );
 285+ }
 286+
 287+ function getPageThreads( $pager ) {
 288+ $rows = $pager->getRows();
 289+
 290+ return Thread::bulkLoad( $rows );
 291+ }
 292+
 293+ function getSortType() {
 294+ // Determine sort order
 295+ if ( $this->methodApplies( 'talkpage_sort_order' ) ) {
 296+ // Sort order is explicitly specified through UI
 297+ $lqt_order = $this->request->getVal( 'lqt_order' );
 298+ switch( $lqt_order ) {
 299+ case 'nc':
 300+ return LQT_NEWEST_CHANGES;
 301+ case 'nt':
 302+ return LQT_NEWEST_THREADS;
 303+ case 'ot':
 304+ return LQT_OLDEST_THREADS;
 305+ }
 306+ } else {
 307+ // Sort order set in user preferences overrides default
 308+ $user_order = $this->user->getOption( 'lqt_sort_order' ) ;
 309+ if ( $user_order ) {
 310+ return $user_order;
 311+ }
 312+ }
 313+
 314+ // Default
 315+ return LQT_NEWEST_CHANGES;
 316+ }
293317 }
 318+
 319+class LqtDiscussionPager extends IndexPager {
 320+
 321+ function __construct( $article, $orderType, $showDeleted ) {
 322+ $this->article = $article;
 323+ $this->orderType = $orderType;
 324+ $this->showDeleted = $showDeleted;
 325+
 326+ parent::__construct();
 327+ }
 328+
 329+ function getQueryInfo() {
 330+ $queryInfo =
 331+ array(
 332+ 'tables' => array( 'thread' ),
 333+ 'fields' => '*',
 334+ 'conds' =>
 335+ array(
 336+ Threads::articleClause( $this->article ),
 337+ Threads::topLevelClause(),
 338+ ),
 339+ );
 340+
 341+ if ( !$this->showDeleted ) {
 342+ $queryInfo['where']['thread_deleted'] = 0;
 343+ }
 344+
 345+ return $queryInfo;
 346+ }
 347+
 348+ // Adapted from getBody().
 349+ function getRows() {
 350+ if ( !$this->mQueryDone ) {
 351+ $this->doQuery();
 352+ }
 353+
 354+ # Don't use any extra rows returned by the query
 355+ $numRows = min( $this->mResult->numRows(), $this->mLimit );
 356+
 357+ $rows = array();
 358+
 359+ if ( $numRows ) {
 360+ if ( $this->mIsBackwards ) {
 361+ for ( $i = $numRows - 1; $i >= 0; $i-- ) {
 362+ $this->mResult->seek( $i );
 363+ $row = $this->mResult->fetchObject();
 364+ $rows[] = $row;
 365+ }
 366+ } else {
 367+ $this->mResult->seek( 0 );
 368+ for ( $i = 0; $i < $numRows; $i++ ) {
 369+ $row = $this->mResult->fetchObject();
 370+ $rows[] = $row;
 371+ }
 372+ }
 373+ }
 374+
 375+ return $rows;
 376+ }
 377+
 378+ function formatRow( $row ) {
 379+ // No-op, we get the list of rows from getRows()
 380+ }
 381+
 382+ function getIndexField() {
 383+ switch( $this->orderType ) {
 384+ case LQT_NEWEST_CHANGES:
 385+ return 'thread_modified';
 386+ case LQT_OLDEST_THREADS:
 387+ case LQT_NEWEST_THREADS:
 388+ return 'thread_created';
 389+ default:
 390+ throw new MWException( "Unknown sort order ".$this->orderType );
 391+ }
 392+ }
 393+
 394+ function getDefaultDirections() {
 395+ switch( $this->orderType ) {
 396+ case LQT_NEWEST_CHANGES:
 397+ case LQT_NEWEST_THREADS:
 398+ return true; // Descending
 399+ case LQT_OLDEST_THREADS:
 400+ return false; // Ascending
 401+ default:
 402+ throw new MWException( "Unknown sort order ".$this->orderType );
 403+ }
 404+ }
 405+
 406+ /**
 407+ * A navigation bar with images
 408+ * Stolen from TablePager because it's pretty.
 409+ */
 410+ function getNavigationBar() {
 411+ global $wgStylePath, $wgContLang;
 412+
 413+ if ( !$this->isNavigationBarShown() ) return '';
 414+
 415+ $path = "$wgStylePath/common/images";
 416+ $labels = array(
 417+ 'first' => 'table_pager_first',
 418+ 'prev' => 'table_pager_prev',
 419+ 'next' => 'table_pager_next',
 420+ 'last' => 'table_pager_last',
 421+ );
 422+ $images = array(
 423+ 'first' => $wgContLang->isRTL() ? 'arrow_last_25.png' : 'arrow_first_25.png',
 424+ 'prev' => $wgContLang->isRTL() ? 'arrow_right_25.png' : 'arrow_left_25.png',
 425+ 'next' => $wgContLang->isRTL() ? 'arrow_left_25.png' : 'arrow_right_25.png',
 426+ 'last' => $wgContLang->isRTL() ? 'arrow_first_25.png' : 'arrow_last_25.png',
 427+ );
 428+ $disabledImages = array(
 429+ 'first' => $wgContLang->isRTL() ? 'arrow_disabled_last_25.png' : 'arrow_disabled_first_25.png',
 430+ 'prev' => $wgContLang->isRTL() ? 'arrow_disabled_right_25.png' : 'arrow_disabled_left_25.png',
 431+ 'next' => $wgContLang->isRTL() ? 'arrow_disabled_left_25.png' : 'arrow_disabled_right_25.png',
 432+ 'last' => $wgContLang->isRTL() ? 'arrow_disabled_first_25.png' : 'arrow_disabled_last_25.png',
 433+ );
 434+
 435+ $linkTexts = array();
 436+ $disabledTexts = array();
 437+ foreach ( $labels as $type => $label ) {
 438+ $msgLabel = wfMsgHtml( $label );
 439+ $linkTexts[$type] = "<img src=\"$path/{$images[$type]}\" alt=\"$msgLabel\"/><br/>$msgLabel";
 440+ $disabledTexts[$type] = "<img src=\"$path/{$disabledImages[$type]}\" alt=\"$msgLabel\"/><br/>$msgLabel";
 441+ }
 442+ $links = $this->getPagingLinks( $linkTexts, $disabledTexts );
 443+
 444+ $navClass = htmlspecialchars( $this->getNavClass() );
 445+ $s = "<table class=\"$navClass\" align=\"center\" cellpadding=\"3\"><tr>\n";
 446+ $cellAttrs = 'valign="top" align="center" width="' . 100 / count( $links ) . '%"';
 447+ foreach ( $labels as $type => $label ) {
 448+ $s .= "<td $cellAttrs>{$links[$type]}</td>\n";
 449+ }
 450+ $s .= "</tr></table>\n";
 451+ return $s;
 452+ }
 453+}
Index: trunk/extensions/LiquidThreads/schema-changes/lqt-schema-change-3.sql
@@ -0,0 +1,13 @@
 2+alter table thread add column thread_ancestor int(8) unsigned not null;
 3+alter table thread add column thread_parent int(8) unsigned null;
 4+alter table thread add index thread_ancestor (thread_ancestor);
 5+
 6+update thread set thread_ancestor = substring_index(thread_path, ".", 1),
 7+ thread_parent = substring_index(substring_index(thread_path, ".", -2), ".", 1 )
 8+where locate(".", thread_path) != 0;
 9+
 10+update thread set thread_ancestor = substring_index(thread_path, ".", 1),
 11+ thread_parent = null
 12+where locate(".", thread_path) = 0;
 13+
 14+alter table thread drop column thread_path;
Property changes on: trunk/extensions/LiquidThreads/schema-changes/lqt-schema-change-3.sql
___________________________________________________________________
Name: svn:eol-style
115 + native
Index: trunk/extensions/LiquidThreads/schema-changes/lqt-schema-change-4.sql
@@ -0,0 +1,4 @@
 2+alter table thread change thread_timestamp thread_modified char(14) binary NOT NULL default '';
 3+alter table thread add column thread_created char(14) binary NOT NULL default '';
 4+update thread set thread_created = thread_modified;
 5+alter table thread add index thread_created (thread_created);
Property changes on: trunk/extensions/LiquidThreads/schema-changes/lqt-schema-change-4.sql
___________________________________________________________________
Name: svn:eol-style
16 + native
Index: trunk/extensions/LiquidThreads/schema-changes/lqt-schema-change-5.sql
@@ -0,0 +1,13 @@
 2+alter table thread add column thread_editedness int(1) NOT NULL default 0;
 3+
 4+update thread join thread as child on child.thread_parent = thread.thread_id set thread.thread_editedness = 1;
 5+
 6+create temporary table counts ( thread_id int(8) unsigned, revision_count int(8) unsigned, author_count int(8) unsigned, rev_user int(8) unsigned );
 7+
 8+insert into counts (thread_id, revision_count, author_count, rev_user) select thread_id, count(thread_id), count(distinct rev_user), rev_user from thread join revision on rev_page = thread_root group by thread_id;
 9+
 10+update thread join counts on thread.thread_id = counts.thread_id set thread_editedness = 2 where revision_count > 1;
 11+
 12+update thread join counts on thread.thread_id = counts.thread_id set thread_editedness = 3 where author_count > 1 or (rev_user = 0 and revision_count > 1);
 13+
 14+drop table counts;
Property changes on: trunk/extensions/LiquidThreads/schema-changes/lqt-schema-change-5.sql
___________________________________________________________________
Name: svn:eol-style
115 + native
Index: trunk/extensions/LiquidThreads/schema-changes/lqt-schema-change-thread_summary.sql
@@ -0,0 +1,5 @@
 2+-- Schema change to add thread subject to the thread table.
 3+
 4+ALTER TABLE /*_*/thread add column thread_subject varchar(255) NULL;
 5+ALTER TABLE /*_*/thread add column thread_author_id int unsigned NULL;
 6+ALTER TABLE /*_*/thread add column thread_author_name varchar(255) NULL;
Index: trunk/extensions/LiquidThreads/schema-changes/lqt-schema-change-6.sql
@@ -0,0 +1 @@
 2+alter table thread add index thread_summary_page (thread_summary_page);
Property changes on: trunk/extensions/LiquidThreads/schema-changes/lqt-schema-change-6.sql
___________________________________________________________________
Name: svn:eol-style
13 + native
Index: trunk/extensions/LiquidThreads/schema-changes/lqt-schema-change-1.sql
@@ -0,0 +1,5 @@
 2+update thread, page set thread_article_title=page_title, thread_article_namespace=page_namespace where page_id=thread_article and thread_article is not null and thread_article != 0;
 3+
 4+alter table thread drop column thread_article;
 5+alter table thread modify thread_article_namespace not null;
 6+alter table thread modify thread_article_title varchar(255) binary not null;
Property changes on: trunk/extensions/LiquidThreads/schema-changes/lqt-schema-change-1.sql
___________________________________________________________________
Name: svn:eol-style
17 + native
Index: trunk/extensions/LiquidThreads/schema-changes/lqt-schema-change-2.sql
@@ -0,0 +1,4 @@
 2+update page set page_namespace=90 where page_namespace=16;
 3+update page set page_namespace=91 where page_namespace=17;
 4+update page set page_namespace=92 where page_namespace=18;
 5+update page set page_namespace=93 where page_namespace=19;
Property changes on: trunk/extensions/LiquidThreads/schema-changes/lqt-schema-change-2.sql
___________________________________________________________________
Name: svn:eol-style
16 + native
Index: trunk/extensions/LiquidThreads/classes/LqtThreads.php
@@ -32,7 +32,8 @@
3333 /** static cache of per-page archivestartdays setting */
3434 static $archiveStartDays;
3535
36 - static function newThread( $root, $article, $superthread = null, $type = self::TYPE_NORMAL ) {
 36+ static function newThread( $root, $article, $superthread = null,
 37+ $type = self::TYPE_NORMAL, $subject = '' ) {
3738 // SCHEMA changes must be reflected here.
3839 // TODO: It's dumb that the commitRevision code isn't used here.
3940
@@ -48,25 +49,28 @@
4950 $change_type = self::CHANGE_NEW_THREAD;
5051 }
5152
52 - global $wgUser; // TODO global.
 53+ global $wgUser;
5354
5455 $timestamp = wfTimestampNow();
5556
5657 // TODO PG support
5758 $newid = $dbw->nextSequenceValue( 'thread_thread_id' );
5859
59 - $row = array( 'thread_root' => $root->getID(),
60 - 'thread_parent' => $superthread ? $superthread->id() : null,
61 - 'thread_article_namespace' => $article->getTitle()->getNamespace(),
62 - 'thread_article_title' => $article->getTitle()->getDBkey(),
63 - 'thread_modified' => $timestamp,
64 - 'thread_created' => $timestamp,
65 - 'thread_change_type' => $change_type,
66 - 'thread_change_comment' => "", // TODO
67 - 'thread_change_user' => $wgUser->getID(),
68 - 'thread_change_user_text' => $wgUser->getName(),
69 - 'thread_type' => $type,
70 - 'thread_editedness' => self::EDITED_NEVER );
 60+ $row = array(
 61+ 'thread_root' => $root->getID(),
 62+ 'thread_parent' => $superthread ? $superthread->id() : null,
 63+ 'thread_article_namespace' => $article->getTitle()->getNamespace(),
 64+ 'thread_article_title' => $article->getTitle()->getDBkey(),
 65+ 'thread_modified' => $timestamp,
 66+ 'thread_created' => $timestamp,
 67+ 'thread_change_type' => $change_type,
 68+ 'thread_change_comment' => "", // TODO
 69+ 'thread_change_user' => $wgUser->getID(),
 70+ 'thread_change_user_text' => $wgUser->getName(),
 71+ 'thread_type' => $type,
 72+ 'thread_editedness' => self::EDITED_NEVER,
 73+ 'thread_subject' => $subject,
 74+ );
7175
7276 if ( $superthread ) {
7377 $row['thread_ancestor'] = $superthread->ancestorId();
@@ -99,9 +103,6 @@
100104 // We just created the thread, it won't have any children.
101105 $newthread = new Thread( $rowObj, array() );
102106
103 - if ( !$newthread )
104 - throw new MWException( "No new thread with ID $newid\n" );
105 -
106107 if ( $superthread ) {
107108 $superthread->addReply( $newthread );
108109 }
@@ -302,7 +303,7 @@
303304
304305 $arr = array( 'thread_ancestor=thread_id', 'thread_parent' => null );
305306
306 - return $dbr->makeList( $arr, LIST_AND );
 307+ return $dbr->makeList( $arr, LIST_OR );
307308 }
308309
309310 static function getArticleArchiveStartDays( $article ) {
Index: trunk/extensions/LiquidThreads/classes/LqtView.php
@@ -47,31 +47,6 @@
4848 }
4949
5050 function initializeQueries() {
51 -
52 - // Determine sort order
53 - if ( $this->methodApplies( 'talkpage_sort_order' ) ) {
54 - // Sort order is explicitly specified through UI
55 - global $wgRequest;
56 - $lqt_order = $wgRequest->getVal( 'lqt_order' );
57 - switch( $lqt_order ) {
58 - case 'nc':
59 - $this->sort_order = LQT_NEWEST_CHANGES;
60 - break;
61 - case 'nt':
62 - $this->sort_order = LQT_NEWEST_THREADS;
63 - break;
64 - case 'ot':
65 - $this->sort_order = LQT_OLDEST_THREADS;
66 - break;
67 - }
68 - } else {
69 - // Sort order set in user preferences overrides default
70 - global $wgUser;
71 - $user_order = $wgUser->getOption( 'lqt_sort_order' ) ;
72 - if ( $user_order ) {
73 - $this->sort_order = $user_order;
74 - }
75 - }
7651
7752 // Create query group
7853 global $wgOut, $wgLqtThreadArchiveStartDays, $wgLqtThreadArchiveInactiveDays;
@@ -427,7 +402,7 @@
428403 $timestamp = $edit_applies_to->created();
429404 $fTime = $wgContLang->time($timestamp);
430405 $fDate = $wgContLang->date($timestamp);
431 - $user = $thread_article->originalAuthor()->getName();
 406+ $user = $edit_applies_to->author()->getName();
432407
433408 $quoteIntro = wfMsgForContent( 'lqt-quote-intro', $user, $fTime, $fDate );
434409 $quote_text = "$quoteIntro\n<blockquote>\n$quote_text\n</blockquote>\n";
@@ -444,24 +419,33 @@
445420 // For replies and new posts, insert the associated thread object into the DB.
446421 if ( $edit_type != 'editExisting' && $edit_type != 'summarize' && $e->didSave ) {
447422 if ( $edit_type == 'reply' ) {
448 - $thread = Threads::newThread( $article, $this->article, $edit_applies_to, $e->summary );
449 - $edit_applies_to->commitRevision( Threads::CHANGE_REPLY_CREATED, $thread, $e->summary );
 423+ $subject = $edit_applies_to->subject();
 424+
 425+ $thread = Threads::newThread( $article, $this->article, $edit_applies_to,
 426+ Threads::TYPE_NORMAL, $subject );
 427+
 428+ $edit_applies_to->commitRevision( Threads::CHANGE_REPLY_CREATED, $thread,
 429+ $e->summary );
450430 } else {
451 - $thread = Threads::newThread( $article, $this->article, null, $e->summary );
 431+ $thread = Threads::newThread( $article, $this->article, null,
 432+ Threads::TYPE_NORMAL, $subject);
452433 }
453434 }
454435
455436 if ( $edit_type == 'summarize' && $e->didSave ) {
456437 $edit_applies_to->setSummary( $article );
457 - $edit_applies_to->commitRevision( Threads::CHANGE_EDITED_SUMMARY, $edit_applies_to, $e->summary );
 438+ $edit_applies_to->commitRevision( Threads::CHANGE_EDITED_SUMMARY,
 439+ $edit_applies_to, $e->summary );
458440 }
459441
460442 // Move the thread and replies if subject changed.
461443 if ( $edit_type == 'editExisting' && $e->didSave ) {
462444 $subject = $this->request->getVal( 'lqt_subject_field', '' );
463445 if ( $subject && $subject != $thread->subjectWithoutIncrement() ) {
464 -
465 - $this->renameThread( $thread, $subject, $e->summary );
 446+ $thread->setSubject( $subject );
 447+
 448+ // Disabled page-moving for now.
 449+ // $this->renameThread( $thread, $subject, $e->summary );
466450 }
467451 // this is unrelated to the subject change and is for all edits:
468452 $thread->setRootRevision( Revision::newFromTitle( $thread->root()->getTitle() ) );
@@ -482,6 +466,7 @@
483467 function renameThread( $t, $s, $reason ) {
484468 $this->simplePageMove( $t->root()->getTitle(), $s, $reason );
485469 // TODO here create a redirect from old page to new.
 470+
486471 foreach ( $t->subthreads() as $st ) {
487472 $this->renameThread( $st, $s, $reason );
488473 }
@@ -491,22 +476,38 @@
492477 $token = md5( uniqid( rand(), true ) );
493478 return Title::newFromText( "Thread:$token" );
494479 }
 480+
495481 function newScratchTitle( $subject ) {
496482 wfLoadExtensionMessages( 'LiquidThreads' );
497 - return $this->incrementedTitle( $subject ? $subject:wfMsg( 'lqt_nosubject' ), NS_LQT_THREAD );
 483+ $subject = $subject ? $subject : wfMsg( 'lqt_nosubject' );
 484+
 485+ $base = $this->article->getTitle()->getPrefixedText() . "/$subject";
 486+
 487+ return $this->incrementedTitle( $base, NS_LQT_THREAD );
498488 }
 489+
499490 function newSummaryTitle( $t ) {
500 - return $this->incrementedTitle( $t->subject(), NS_LQT_SUMMARY );
 491+ return $this->incrementedTitle( $t->title()->getText(), NS_LQT_SUMMARY );
501492 }
 493+
502494 function newReplyTitle( $s, $t ) {
503 - return $this->incrementedTitle( $t->subjectWithoutIncrement(), NS_LQT_THREAD );
 495+ $topThread = $t->topMostThread();
 496+
 497+ $base = $t->title()->getText() . '/' . $this->user->getName();
 498+
 499+ return $this->incrementedTitle( $base, NS_LQT_THREAD );
504500 }
 501+
505502 /** Keep trying titles starting with $basename until one is unoccupied. */
506503 public static function incrementedTitle( $basename, $namespace ) {
507 - $i = 1; do {
508 - $t = Title::newFromText( $basename . '_(' . $i . ')', $namespace );
 504+ $i = 2;
 505+
 506+ $t = Title::makeTitleSafe( $namespace, $basename );
 507+ while ( $t->exists() ||
 508+ in_array( $t->getPrefixedDBkey(), self::$occupied_titles ) ) {
 509+ $t = Title::makeTitleSafe( $namespace, $basename . ' (' . $i . ')' );
509510 $i++;
510 - } while ( $t->exists() || in_array( $t->getPrefixedDBkey(), self::$occupied_titles ) );
 511+ }
511512 return $t;
512513 }
513514
@@ -524,16 +525,9 @@
525526
526527 self::$occupied_titles[] = $nt->getPrefixedDBkey();
527528
528 - # don't allow moving to pages with # in
529 - if ( !$nt || $nt->getFragment() != '' ) {
530 - echo "malformed title"; // TODO real error reporting.
531 - return false;
532 - }
533 -
534529 $error = $ot->moveTo( $nt, true, "Changed thread subject: $reason" );
535530 if ( $error !== true ) {
536 - var_dump( $error );
537 - echo "something bad happened trying to rename the thread."; // TODO
 531+ throw new MWException( "Got error $error trying to move pages." );
538532 return false;
539533 }
540534
@@ -675,14 +669,6 @@
676670
677671 return $parserOutput->getText();
678672 }
679 -
680 - function colorTest() {
681 - $this->output->addHTML( '<div class="lqt_footer"><li class="lqt_footer_sig">' );
682 - for ( $i = 1; $i <= self::number_of_user_colors; $i++ ) {
683 - $this->output->addHTML( "<span class=\"lqt_post_color_{$i}\"><a href=\"foo\">DavidMcCabe</a></span>" );
684 - }
685 - $this->output->addHTML( '</li></div>' );
686 - }
687673
688674 function showThreadHeader( $thread ) {
689675 global $wgLang;
@@ -693,7 +679,7 @@
694680 $infoElements = array();
695681
696682 // Author name.
697 - $author = $thread->root()->originalAuthor();
 683+ $author = $thread->author();
698684 $signature = $sk->userLink( $author->getId(), $author->getName() );
699685 $signature = Xml::tags( 'span', array( 'class' => 'lqt-thread-header-author' ),
700686 $signature );
@@ -904,7 +890,7 @@
905891 $replyLink = Xml::tags( 'a', array( 'href' => '#'.$this->anchorName( $tmp ) ),
906892 $tmp->subject() );
907893 $msg = wfMsgExt( 'lqt_in_response_to', array( 'parseinline', 'replaceafter' ),
908 - array( $replyLink, $tmp->root()->originalAuthor()->getName() ) );
 894+ array( $replyLink, $tmp->author()->getName() ) );
909895
910896 return Xml::tags( 'span', array( 'class' => 'lqt_nonindent_message' ),
911897 "&larr; $msg" );
@@ -916,14 +902,16 @@
917903 // Display a moved thread
918904 function showMovedThread( $thread ) {
919905 global $wgLang;
 906+
 907+ $sk = $this->user->getSkin();
920908
921909 // Grab target thread
922910 $article = new Article( $thread->title() );
923 - $target = Title::newFromRedirect( $article->getText() );
 911+ $target = Title::newFromRedirect( $article->getContent() );
924912 $t_thread = Threads::withRoot( new Article( $target ) );
925913
926914 // Grab data about the new post.
927 - $author = $thread->root()->originalAuthor();
 915+ $author = $thread->author();
928916 $sig = $sk->userLink( $author->getID(), $author->getName() ) .
929917 $sk->userToolLinks( $author->getID(), $author->getName() );
930918
@@ -940,6 +928,7 @@
941929
942930 /** Shows a deleted thread. Returns true to show the thread body */
943931 function showDeletedThread( $thread ) {
 932+ $sk = $this->user->getSkin();
944933 if ( $this->user->isAllowed( 'deletedhistory' ) ) {
945934 $this->output->addWikiMsg( 'lqt_thread_deleted_for_sysops' );
946935 return true;
Index: trunk/extensions/LiquidThreads/classes/LqtThread.php
@@ -28,6 +28,9 @@
2929 protected $id;
3030 protected $revisionNumber;
3131 protected $type;
 32+ protected $subject;
 33+ protected $authorId;
 34+ protected $authorName;
3235
3336 /* Flag about who has edited or replied to this thread. */
3437 protected $editedness;
@@ -117,16 +120,20 @@
118121 self::setChangeOnDescendents( $r, $change_type, $change_object );
119122 return $thread;
120123 }
 124+
 125+ function getDouble() {
 126+ if (!$this->double) {
 127+ $this->double = clone $this;
 128+ }
 129+
 130+ return $this->double;
 131+ }
121132
122133 function commitRevision( $change_type, $change_object = null, $reason = "" ) {
123 - global $wgUser; // TODO global.
124 - /*
125 - $this->changeComment = $reason;
126 - $this->changeUser = $wgUser->getID();
127 - $this->changeUserText = $wgUser->getName();
128 - */
 134+ global $wgUser;
 135+
129136 // TODO open a transaction.
130 - HistoricalThread::create( $this->double, $change_type, $change_object );
 137+ HistoricalThread::create( $this->getDouble(), $change_type, $change_object );
131138
132139 $this->bumpRevisionsOnAncestors( $change_type, $change_object, $reason, wfTimestampNow() );
133140 self::setChangeOnDescendents( $this->topmostThread(), $change_type, $change_object );
@@ -136,7 +143,7 @@
137144 $this->editedness = Threads::EDITED_HAS_REPLY;
138145 }
139146 else if ( $change_type == Threads::CHANGE_EDITED_ROOT ) {
140 - $originalAuthor = $this->root()->originalAuthor();
 147+ $originalAuthor = $this->author();
141148 if ( ( $wgUser->getId() == 0 && $originalAuthor->getName() != $wgUser->getName() )
142149 || $wgUser->getId() != $originalAuthor->getId() ) {
143150 $this->editedness = Threads::EDITED_BY_OTHERS;
@@ -153,6 +160,9 @@
154161 'thread_ancestor' => $this->ancestorId,
155162 'thread_parent' => $this->parentId,
156163 'thread_type' => $this->type,
 164+ 'thread_subject' => $this->subject,
 165+ 'thread_author_id' => $this->authorId,
 166+ 'thread_author_name' => $this->authorName,
157167 'thread_summary_page' => $this->summaryId,
158168 'thread_article_namespace' => $this->articleNamespace,
159169 'thread_article_title' => $this->articleTitle,
@@ -160,11 +170,27 @@
161171 ),
162172 /* WHERE */ array( 'thread_id' => $this->id, ),
163173 __METHOD__ );
 174+
 175+ // Touch the root
 176+ $this->root()->getTitle()->invalidateCache();
164177
165178 if ( $change_type == Threads::CHANGE_EDITED_ROOT ) {
166179 NewMessages::writeMessageStateForUpdatedThread( $this, $change_type, $wgUser );
167180 }
168181 }
 182+
 183+ function author() {
 184+ $this->doLazyUpdates();
 185+
 186+ if ($this->authorId) {
 187+ return User::newFromId( $this->authorId );
 188+ } else {
 189+ $u = new User;
 190+ $u->mName = $this->authorName;
 191+
 192+ return $u;
 193+ }
 194+ }
169195
170196 function delete( $reason ) {
171197 $this->type = Threads::TYPE_DELETED;
@@ -172,6 +198,7 @@
173199 $this->commitRevision( Threads::CHANGE_DELETED, $this, $reason );
174200 /* TODO: mark thread as read by all users, or we get blank thingies in New Messages. */
175201 }
 202+
176203 function undelete( $reason ) {
177204 $this->type = Threads::TYPE_NORMAL;
178205 $this->revisionNumber += 1;
@@ -187,7 +214,7 @@
188215 $new_articleNamespace = $title->getNamespace();
189216 $new_articleTitle = $title->getDBkey();
190217
191 - foreach ( $this->replies as $r ) {
 218+ foreach ( $this->replies() as $r ) {
192219 $res = $dbr->update( 'thread',
193220 /* SET */array(
194221 'thread_revision' => $r->revisionNumber() + 1,
@@ -268,10 +295,12 @@
269296 'thread_change_comment' => 'changeComment',
270297 'thread_change_user' => 'changeUser',
271298 'thread_change_user_text' => 'changeUserText',
272 - 'thread_editedness' => 'editedness'
 299+ 'thread_editedness' => 'editedness',
 300+ 'thread_subject' => 'subject',
 301+ 'thread_author_id' => 'authorId',
 302+ 'thread_author_name' => 'authorName',
273303 );
274304
275 -
276305 foreach( $dataLoads as $db_field => $member_field ) {
277306 if ( isset($line->$db_field) ) {
278307 $this->$member_field = $line->$db_field;
@@ -288,7 +317,68 @@
289318 }
290319
291320 $this->rootRevision = $this->root->mLatest;
 321+
 322+ $this->doLazyUpdates( $line );
292323 }
 324+
 325+ // Load a list of threads in bulk.
 326+ static function bulkLoad( $rows ) {
 327+ $threads = array();
 328+
 329+ foreach( $rows as $row ) {
 330+ $threads[] = new Thread( $row, null );
 331+ }
 332+
 333+ return $threads;
 334+ }
 335+
 336+ // Lazy updates done whenever a thread is loaded.
 337+ // Much easier than running a long-running maintenance script.
 338+ function doLazyUpdates( ) {
 339+ // This is an invocation guard to avoid infinite recursion when fixing a
 340+ // missing ancestor.
 341+ static $doingUpdates = false;
 342+ if ($doingUpdates) return;
 343+ $doingUpdates = true;
 344+
 345+ // Fix missing ancestry information.
 346+ if ($this->parentId &&!$this->ancestorId) {
 347+ $this->fixMissingAncestor();
 348+ }
 349+
 350+ $set = array();
 351+
 352+ // Fix missing subject information
 353+ if (!$this->subject) {
 354+ $detectedSubject = $this->root()->getTitle()->getText();
 355+ $parts = self::splitIncrementFromSubject( $detectedSubject );
 356+
 357+ $this->subject = $detectedSubject = $parts[1];
 358+
 359+ // Update in the DB
 360+ $set['thread_subject'] = $detectedSubject;
 361+ }
 362+
 363+ // Fix missing authorship information
 364+ if ( !$this->authorName ) {
 365+ $author = $this->root()->originalAuthor();
 366+
 367+ $this->authorId = $author->getId();
 368+ $this->authorName = $author->getName();
 369+
 370+ $set['thread_author_name'] = $this->authorName;
 371+ $set['thread_author_id'] = $this->authorId;
 372+ }
 373+
 374+ if ( count($set) ) {
 375+ $dbw = wfGetDB( DB_MASTER );
 376+
 377+ $dbw->update( 'thread', $set, array( 'thread_id' => $this->id() ), __METHOD__ );
 378+ }
 379+
 380+ // Done
 381+ $doingUpdates = false;
 382+ }
293383
294384 function initWithReplies( $children ) {
295385
@@ -319,7 +409,11 @@
320410 // historical thread, duh. Why were we doing this?
321411 // $this->replies[] = $thread;
322412 }
 413+
323414 function removeReplyWithId( $id ) {
 415+ // Force load
 416+ $this->replies();
 417+
324418 $target = null;
325419 foreach ( $this->replies as $k => $r ) {
326420 if ( $r->id() == $id ) {
@@ -334,6 +428,24 @@
335429 }
336430 }
337431 function replies() {
 432+ if ( !is_null($this->replies) ) {
 433+ return $this->replies;
 434+ }
 435+
 436+ $this->replies = array();
 437+
 438+ $dbr = wfGetDB( DB_SLAVE );
 439+
 440+ $res = $dbr->select( 'thread', '*',
 441+ array( 'thread_parent' => $this->id() ), __METHOD__ );
 442+
 443+ $rows = array();
 444+ while ( $row = $dbr->fetchObject($res) ) {
 445+ $rows[] = $row;
 446+ }
 447+
 448+ $this->replies = Thread::bulkLoad( $rows );
 449+
338450 return $this->replies;
339451 }
340452
@@ -500,27 +612,21 @@
501613 }
502614
503615 function subject() {
504 - return $this->root()->getTitle()->getText();
 616+ return $this->subject;
505617 }
 618+
 619+ function setSubject( $subject ) {
 620+ $this->subject = $subject;
 621+ }
506622
507623 function wikilinkWithoutIncrement() {
508 - $tmp = self::splitIncrementFromSubject( $this->wikilink() );
509 -
510 - return $tmp[1];
 624+ return $this->wikilink();
511625 }
512626
513627 function subjectWithoutIncrement() {
514 - $tmp = self::splitIncrementFromSubject( $this->subject() );
515 -
516 - return $tmp[1];
 628+ return $this->subject();
517629 }
518630
519 - function increment() {
520 - $tmp = self::splitIncrementFromSubject( $this->subject() );
521 -
522 - return $tmp[2];
523 - }
524 -
525631 function hasDistinctSubject() {
526632 if ( $this->hasSuperthread() ) {
527633 return $this->superthread()->subjectWithoutIncrement()
@@ -531,11 +637,11 @@
532638 }
533639
534640 function hasSubthreads() {
535 - return count( $this->replies ) != 0;
 641+ return count( $this->replies() ) != 0;
536642 }
537643
538644 function subthreads() {
539 - return $this->replies;
 645+ return $this->replies();
540646 }
541647
542648 function modified() {
@@ -556,7 +662,7 @@
557663
558664 private function replyWithId( $id ) {
559665 if ( $this->id == $id ) return $this;
560 - foreach ( $this->replies as $r ) {
 666+ foreach ( $this->replies() as $r ) {
561667 if ( $r->id() == $id ) return $r;
562668 else {
563669 $s = $r->replyWithId( $id );
Index: trunk/extensions/LiquidThreads/lqt.sql
@@ -4,6 +4,9 @@
55 thread_ancestor int(8) unsigned NOT NULL,
66 thread_parent int(8) unsigned NULL,
77 thread_summary_page int(8) unsigned NULL,
 8+ thread_subject varchar(255) NULL,
 9+ thread_author_id int unsigned NULL,
 10+ thread_author_name varchar(255) NULL,
811
912 thread_modified char(14) binary NOT NULL default '',
1013 thread_created char(14) binary NOT NULL default '',
@@ -25,11 +28,12 @@
2629
2730 PRIMARY KEY thread_id (thread_id),
2831 UNIQUE INDEX thread_id (thread_id),
29 - INDEX thread_ancestor (thread_ancestor),
 32+ INDEX thread_ancestor (thread_ancestor, thread_parent),
3033 INDEX thread_article_title (thread_article_namespace, thread_article_title),
3134 INDEX thread_modified (thread_modified),
3235 INDEX thread_created (thread_created),
33 - INDEX thread_summary_page (thread_summary_page)
 36+ INDEX thread_summary_page (thread_summary_page),
 37+ INDEX thread_root (thread_root)
3438 ) /*$wgDBTableOptions*/;
3539
3640 CREATE TABLE /*$wgDBprefix*/historical_thread (

Status & tagging log