Index: trunk/extensions/LiquidThreads/i18n/Lqt.i18n.php |
— | — | @@ -160,6 +160,12 @@ |
161 | 161 | 'lqt_summarize_link' => 'Summarize', |
162 | 162 | 'lqt-summarize-intro' => 'Please summarize the below thread in the editing box. |
163 | 163 | You may use any wikitext in your summary. When you finish, click "{{int:savearticle}}".', |
| 164 | + 'lqt-thread-split' => 'Split to new thread', |
| 165 | + 'lqt-split-success' => 'You have successfully split off the thread $1.', |
| 166 | + 'lqt_split_thread' => 'Split a thread', |
| 167 | + 'lqt-thread-split-subject'=> 'New thread subject', |
| 168 | + 'lqt-split-submit' => 'Split', |
| 169 | + 'lqt_split_badsubject' => 'The subject you entered is invalid.', |
164 | 170 | |
165 | 171 | // Logging |
166 | 172 | 'lqt-log-name' => 'Threaded discussion log', |
Index: trunk/extensions/LiquidThreads/i18n/Lqt.alias.php |
— | — | @@ -13,6 +13,7 @@ |
14 | 14 | 'DeleteThread' => array( 'DeleteThread' ), |
15 | 15 | 'MoveThread' => array( 'MoveThread' ), |
16 | 16 | 'NewMessages' => array( 'NewMessages' ), |
| 17 | + 'SplitThread' => array( 'SplitThread' ), |
17 | 18 | ); |
18 | 19 | |
19 | 20 | /** Arabic (العربية) |
Index: trunk/extensions/LiquidThreads/pages/SpecialMoveThread.php |
— | — | @@ -2,14 +2,8 @@ |
3 | 3 | |
4 | 4 | if ( !defined( 'MEDIAWIKI' ) ) die; |
5 | 5 | |
6 | | -class SpecialMoveThread extends UnlistedSpecialPage { |
7 | | - private $user, $output, $request, $title, $thread; |
| 6 | +class SpecialMoveThread extends ThreadActionPage { |
8 | 7 | |
9 | | - function __construct() { |
10 | | - parent::__construct( 'Movethread' ); |
11 | | - $this->includable( false ); |
12 | | - } |
13 | | - |
14 | 8 | /** |
15 | 9 | * @see SpecialPage::getDescription |
16 | 10 | */ |
— | — | @@ -34,53 +28,36 @@ |
35 | 29 | ), |
36 | 30 | ); |
37 | 31 | } |
38 | | - |
39 | | - function execute( $par ) { |
| 32 | + |
| 33 | + function getPageName() { return 'MoveThread'; } |
| 34 | + |
| 35 | + function getSubmitText() { |
40 | 36 | wfLoadExtensionMessages( 'LiquidThreads' ); |
| 37 | + return wfMsg( 'lqt_move_move' ); |
| 38 | + } |
| 39 | + |
| 40 | + function buildForm() { |
| 41 | + $form = parent::buildForm(); |
41 | 42 | |
42 | | - global $wgOut; |
43 | | - |
44 | | - // Page title |
45 | | - $wgOut->setPageTitle( wfMsg( 'lqt_movethread' ) ); |
46 | | - |
47 | | - // Handle parameter |
48 | | - $this->mTarget = $par; |
49 | | - if ( $par === null || $par === "" ) { |
50 | | - wfLoadExtensionMessages( 'LiquidThreads' ); |
51 | | - $this->output->addHTML( wfMsg( 'lqt_threadrequired' ) ); |
52 | | - return; |
53 | | - } |
54 | | - $thread = Threads::withRoot( new Article( Title::newFromURL( $par ) ) ); |
55 | | - if ( !$thread ) { |
56 | | - $this->output->addHTML( wfMsg( 'lqt_nosuchthread' ) ); |
57 | | - return; |
58 | | - } |
59 | | - $this->mThread = $thread; |
60 | | - |
61 | 43 | // Generate introduction |
62 | 44 | $intro = ''; |
63 | 45 | |
64 | 46 | global $wgUser; |
65 | 47 | $sk = $wgUser->getSkin(); |
66 | | - $page = $article_name = $thread->article()->getTitle()->getPrefixedText(); |
| 48 | + $page = $article_name = $this->mThread->article()->getTitle()->getPrefixedText(); |
67 | 49 | |
68 | 50 | $edit_text = wfMsgExt( 'lqt_move_torename_edit', 'parseinline' ); |
69 | | - $edit_link = $sk->link( $thread->title(), $edit_text, array(), |
70 | | - array( 'lqt_method' => 'edit', 'lqt_operand' => $thread->id() ) ); |
| 51 | + $edit_link = $sk->link( $this->mThread->title(), $edit_text, array(), |
| 52 | + array( 'lqt_method' => 'edit', 'lqt_operand' => $this->mThread->id() ) ); |
71 | 53 | |
72 | 54 | $intro .= wfMsgExt( 'lqt_move_movingthread', 'parse', |
73 | 55 | array('[['.$this->mTarget.']]', '[['.$page.']]') ); |
74 | 56 | $intro .= wfMsgExt( 'lqt_move_torename', array( 'parse', 'replaceafter' ), |
75 | 57 | array( $edit_link ) ); |
76 | | - |
77 | | - $form = new HTMLForm( $this->getFormFields(), 'lqt-move' ); |
78 | | - |
79 | | - $form->setSubmitText( wfMsg('lqt_move_move') ); |
80 | | - $form->setTitle( SpecialPage::getTitleFor( 'MoveThread', $par ) ); |
81 | | - $form->setSubmitCallback( array( $this, 'trySubmit' ) ); |
| 58 | + |
82 | 59 | $form->setIntro( $intro ); |
83 | 60 | |
84 | | - $form->show(); |
| 61 | + return $form; |
85 | 62 | } |
86 | 63 | |
87 | 64 | function checkUserRights( $oldTitle, $newTitle ) { |
Index: trunk/extensions/LiquidThreads/pages/ThreadPermalinkView.php |
— | — | @@ -157,6 +157,8 @@ |
158 | 158 | |
159 | 159 | if ( $this->methodApplies( 'summarize' ) ) |
160 | 160 | $this->showSummarizeForm( $this->thread ); |
| 161 | + elseif ( $this->methodApplies( 'split' ) ) |
| 162 | + $this->showSplitForm( $this->thread ); |
161 | 163 | |
162 | 164 | $this->showThread( $this->thread ); |
163 | 165 | return false; |
Index: trunk/extensions/LiquidThreads/LiquidThreads.php |
— | — | @@ -57,9 +57,11 @@ |
58 | 58 | $wgHooks['LanguageGetMagic'][] = 'LiquidThreadsMagicWords::getMagicWords'; |
59 | 59 | |
60 | 60 | // Special pages |
| 61 | +#$wgSpecialPages['UndeleteThread'] = 'SpecialUndeleteThread'; |
61 | 62 | $wgSpecialPages['DeleteThread'] = 'SpecialDeleteThread'; |
62 | 63 | $wgSpecialPages['MoveThread'] = 'SpecialMoveThread'; |
63 | 64 | $wgSpecialPages['NewMessages'] = 'SpecialNewMessages'; |
| 65 | +$wgSpecialPages['SplitThread'] = 'SpecialSplitThread'; |
64 | 66 | $wgSpecialPageGroups['NewMessages'] = 'wiki'; |
65 | 67 | |
66 | 68 | // Classes |
— | — | @@ -72,7 +74,7 @@ |
73 | 75 | $wgAutoloadClasses['Threads'] = $dir . 'classes/LqtThreads.php'; |
74 | 76 | $wgAutoloadClasses['NewMessages'] = $dir . 'classes/LqtNewMessages.php'; |
75 | 77 | $wgAutoloadClasses['LiquidThreadsMagicWords'] = $dir . 'i18n/LiquidThreads.magic.php'; |
76 | | -$wgAutoloadClasses['LqtParserFunctions'] = $dir . 'classes/LqtParserFunctions.php'; // File does not exist |
| 78 | +$wgAutoloadClasses['LqtParserFunctions'] = $dir . 'classes/LqtParserFunctions.php'; |
77 | 79 | |
78 | 80 | // Page classes |
79 | 81 | $wgAutoloadClasses['TalkpageView'] = $dir . 'pages/TalkpageView.php'; |
— | — | @@ -86,10 +88,15 @@ |
87 | 89 | $wgAutoloadClasses['ThreadHistoryListingView'] = $dir . 'pages/ThreadHistoryListingView.php'; |
88 | 90 | $wgAutoloadClasses['ThreadHistoricalRevisionView'] = $dir . 'pages/ThreadHistoricalRevisionView.php'; |
89 | 91 | $wgAutoloadClasses['SummaryPageView'] = $dir . 'pages/SummaryPageView.php'; |
| 92 | +$wgAutoloadClasses['NewUserMessagesView'] = $dir . 'pages/NewUserMessagesView.php'; |
| 93 | + |
| 94 | +$wgAutoloadClasses['ThreadActionPage'] = "$dir/pages/ThreadActionPage.php"; |
| 95 | + |
| 96 | +#$wgAutoloadClasses['SpecialUndeleteThread'] = $dir . "pages/SpecialUndeleteThread.php"; |
90 | 97 | $wgAutoloadClasses['SpecialMoveThread'] = $dir . 'pages/SpecialMoveThread.php'; |
91 | 98 | $wgAutoloadClasses['SpecialDeleteThread'] = $dir . 'pages/SpecialDeleteThread.php'; |
92 | | -$wgAutoloadClasses['NewUserMessagesView'] = $dir . 'pages/NewUserMessagesView.php'; |
93 | 99 | $wgAutoloadClasses['SpecialNewMessages'] = $dir . 'pages/SpecialNewMessages.php'; |
| 100 | +$wgAutoloadClasses['SpecialSplitThread'] = "$dir/pages/SpecialSplitThread.php"; |
94 | 101 | |
95 | 102 | // Logging |
96 | 103 | $wgLogTypes[] = 'liquidthreads'; |
Index: trunk/extensions/LiquidThreads/classes/LqtThreads.php |
— | — | @@ -16,9 +16,12 @@ |
17 | 17 | const CHANGE_DELETED = 4; |
18 | 18 | const CHANGE_UNDELETED = 5; |
19 | 19 | const CHANGE_MOVED_TALKPAGE = 6; |
| 20 | + const CHANGE_SPLIT = 7; |
| 21 | + const CHANGE_EDITED_SUBJECT = 8; |
| 22 | + |
20 | 23 | static $VALID_CHANGE_TYPES = array( self::CHANGE_EDITED_SUMMARY, self::CHANGE_EDITED_ROOT, |
21 | 24 | self::CHANGE_REPLY_CREATED, self::CHANGE_NEW_THREAD, self::CHANGE_DELETED, self::CHANGE_UNDELETED, |
22 | | - self::CHANGE_MOVED_TALKPAGE ); |
| 25 | + self::CHANGE_MOVED_TALKPAGE, self::CHANGE_SPLIT, self::CHANGE_EDITED_SUBJECT ); |
23 | 26 | |
24 | 27 | // Possible values of Thread->editedness. |
25 | 28 | const EDITED_NEVER = 0; |
— | — | @@ -151,7 +154,6 @@ |
152 | 155 | $dbr = wfGetDB( DB_SLAVE ); |
153 | 156 | |
154 | 157 | $res = $dbr->select( 'thread', '*', $where, __METHOD__, $options ); |
155 | | - |
156 | 158 | $threads = Threads::loadFromResult( $res, $dbr ); |
157 | 159 | |
158 | 160 | foreach ( $threads as $thread ) { |
— | — | @@ -201,7 +203,8 @@ |
202 | 204 | if ( array_key_exists( $id, self::$cache_by_id ) ) { |
203 | 205 | return self::$cache_by_id[$id]; |
204 | 206 | } |
205 | | - $ts = Threads::where( array( 'thread.thread_id' => $id ) ); |
| 207 | + $ts = Threads::where( array( 'thread_id' => $id ) ); |
| 208 | + |
206 | 209 | return self::assertSingularity( $ts, 'thread_id', $id ); |
207 | 210 | } |
208 | 211 | |
Index: trunk/extensions/LiquidThreads/classes/LqtView.php |
— | — | @@ -562,6 +562,13 @@ |
563 | 563 | 'href' => $delete_url, |
564 | 564 | 'enabled' => true ); |
565 | 565 | } |
| 566 | + |
| 567 | + if ( !$thread->isTopmostThread() ) { |
| 568 | + $splitUrl = SpecialPage::getTitleFor( 'SplitThread', |
| 569 | + $thread->title()->getPrefixedText() )->getFullURL(); |
| 570 | + $commands['split'] = array( 'label' => wfMsgExt( 'lqt-thread-split', 'parseinline' ), |
| 571 | + 'href' => $splitUrl, 'enabled' => true ); |
| 572 | + } |
566 | 573 | |
567 | 574 | return $commands; |
568 | 575 | } |
— | — | @@ -873,7 +880,7 @@ |
874 | 881 | } |
875 | 882 | |
876 | 883 | static function anchorName( $thread ) { |
877 | | - return "lqt_thread_{$thread->id()}"; |
| 884 | + return $thread->getAnchorName(); |
878 | 885 | } |
879 | 886 | |
880 | 887 | // Gets HTML for the 'in reply to' thing if warranted. |
— | — | @@ -1085,5 +1092,4 @@ |
1086 | 1093 | function showSummary( $t ) { |
1087 | 1094 | $this->output->addHTML( $this->getSummary( $t ) ); |
1088 | 1095 | } |
1089 | | - |
1090 | 1096 | } |
Index: trunk/extensions/LiquidThreads/classes/LqtDispatch.php |
— | — | @@ -80,8 +80,7 @@ |
81 | 81 | } |
82 | 82 | else if ( $action == 'watch' || $action == 'unwatch' ) { |
83 | 83 | $viewname = self::$views['ThreadWatchView']; |
84 | | - } |
85 | | - else { |
| 84 | + } else { |
86 | 85 | $viewname = self::$views['ThreadPermalinkView']; |
87 | 86 | } |
88 | 87 | $view = new $viewname( $output, $article, $title, $user, $request ); |
Index: trunk/extensions/LiquidThreads/classes/LqtThread.php |
— | — | @@ -52,6 +52,7 @@ |
53 | 53 | protected $replies; |
54 | 54 | |
55 | 55 | static $titleCacheById = array(); |
| 56 | + static $replyCacheById = array(); |
56 | 57 | |
57 | 58 | function isHistorical() { |
58 | 59 | return false; |
— | — | @@ -217,17 +218,18 @@ |
218 | 219 | |
219 | 220 | $new_articleNamespace = $title->getNamespace(); |
220 | 221 | $new_articleTitle = $title->getDBkey(); |
| 222 | + |
| 223 | + // Update on *all* subthreads. |
| 224 | + $dbr->update( 'thread', |
| 225 | + array( |
| 226 | + 'thread_revision=thread_revision+1', |
| 227 | + 'thread_article_namespace' => $new_articleNamespace, |
| 228 | + 'thread_article_title' => $new_articleTitle, |
| 229 | + 'thread_modified' => $dbr->timestamp( wfTimestampNow() ), |
| 230 | + ), |
| 231 | + array( 'thread_ancestor' => $this->id() ), |
| 232 | + __METHOD__ ); |
221 | 233 | |
222 | | - foreach ( $this->replies() as $r ) { |
223 | | - $res = $dbr->update( 'thread', |
224 | | - /* SET */array( |
225 | | - 'thread_revision' => $r->revisionNumber() + 1, |
226 | | - 'thread_article_namespace' => $new_articleNamespace, |
227 | | - 'thread_article_title' => $new_articleTitle ), |
228 | | - /* WHERE */ array( 'thread_id' => $r->id(), ), |
229 | | - __METHOD__ ); |
230 | | - } |
231 | | - |
232 | 234 | $this->articleNamespace = $new_articleNamespace; |
233 | 235 | $this->articleTitle = $new_articleTitle; |
234 | 236 | $this->revisionNumber += 1; |
— | — | @@ -270,7 +272,7 @@ |
271 | 273 | __METHOD__ ); |
272 | 274 | |
273 | 275 | $thread = Threads::newThread( $redirectArticle, $this->double->article(), null, |
274 | | - Threads::TYPE_MOVED, $log ); |
| 276 | + Threads::TYPE_MOVED, $this->subject() ); |
275 | 277 | |
276 | 278 | # Purge old title from squid |
277 | 279 | # The new title, and links to the new title, are purged in Article::onArticleCreate() |
— | — | @@ -329,22 +331,47 @@ |
330 | 332 | $this->doLazyUpdates( $line ); |
331 | 333 | } |
332 | 334 | |
333 | | - // Load a list of threads in bulk. |
334 | | - static function bulkLoad( $rows ) { |
335 | | - $threads = array(); |
336 | | - |
337 | | - // Preload page data in one swoop. |
| 335 | + // Load a list of threads in bulk, including all subthreads. |
| 336 | + static function bulkLoad( $rows ) { |
| 337 | + // Preload subthreads |
| 338 | + $thread_ids = array(); |
338 | 339 | $pageIds = array(); |
| 340 | + $replies_by_id = array(); |
339 | 341 | |
340 | 342 | foreach( $rows as $row ) { |
| 343 | + $thread_ids[] = $row->thread_id; |
| 344 | + |
| 345 | + // Grab page data while we're here. |
341 | 346 | if ($row->thread_root) |
342 | 347 | $pageIds[] = $row->thread_root; |
343 | 348 | if ($row->thread_summary_page) |
344 | 349 | $pageIds[] = $row->thread_summary_page; |
345 | 350 | } |
346 | 351 | |
| 352 | + if ( count($thread_ids) ) { |
| 353 | + $dbr = wfGetDB( DB_SLAVE ); |
| 354 | + $res = $dbr->select( 'thread', '*', array( 'thread_ancestor' => $thread_ids ), |
| 355 | + __METHOD__ ); |
| 356 | + |
| 357 | + while( $row = $dbr->fetchObject($res) ) { |
| 358 | + // Grab page data while we're here. |
| 359 | + if ($row->thread_root) |
| 360 | + $pageIds[] = $row->thread_root; |
| 361 | + if ($row->thread_summary_page) |
| 362 | + $pageIds[] = $row->thread_summary_page; |
| 363 | + |
| 364 | + if (!isset( $replies_by_id[$row->thread_parent] ) ) { |
| 365 | + $replies_by_id[$row->thread_parent] = array(); |
| 366 | + } |
| 367 | + |
| 368 | + $replies_by_id[$row->thread_parent][] = new Thread( $row, null ); |
| 369 | + } |
| 370 | + } |
| 371 | + |
| 372 | + self::$replyCacheById = array_merge( self::$replyCacheById, $replies_by_id ); |
| 373 | + |
| 374 | + // Preload page data in one swoop. |
347 | 375 | if ( count($pageIds) ) { |
348 | | - $dbr = wfGetDB( DB_SLAVE ); |
349 | 376 | $res = $dbr->select( 'page', '*', array( 'page_id' => $pageIds ), __METHOD__ ); |
350 | 377 | while( $row = $dbr->fetchObject( $res ) ) { |
351 | 378 | $t = Title::newFromRow( $row ); |
— | — | @@ -357,8 +384,11 @@ |
358 | 385 | } |
359 | 386 | } |
360 | 387 | |
| 388 | + $threads = array(); |
| 389 | + |
361 | 390 | foreach( $rows as $row ) { |
362 | | - $threads[] = new Thread( $row, null ); |
| 391 | + $threads[] = $thread = new Thread( $row, null ); |
| 392 | + Threads::$cache_by_id[$row->thread_id] = $thread; |
363 | 393 | } |
364 | 394 | |
365 | 395 | return $threads; |
— | — | @@ -374,13 +404,17 @@ |
375 | 405 | $doingUpdates = true; |
376 | 406 | |
377 | 407 | // Fix missing ancestry information. |
| 408 | + // (there was a bug where this was not saved properly) |
378 | 409 | if ($this->parentId &&!$this->ancestorId) { |
379 | 410 | $this->fixMissingAncestor(); |
380 | 411 | } |
381 | 412 | |
| 413 | + $ancestor = $this->topmostThread(); |
| 414 | + |
382 | 415 | $set = array(); |
383 | 416 | |
384 | 417 | // Fix missing subject information |
| 418 | + // (this information only started to be added later) |
385 | 419 | if (!$this->subject) { |
386 | 420 | $detectedSubject = $this->root()->getTitle()->getText(); |
387 | 421 | $parts = self::splitIncrementFromSubject( $detectedSubject ); |
— | — | @@ -391,7 +425,16 @@ |
392 | 426 | $set['thread_subject'] = $detectedSubject; |
393 | 427 | } |
394 | 428 | |
| 429 | + // Fix inconsistent subject information |
| 430 | + // (in some intermediate versions this was not updated when the subject was changed) |
| 431 | + if ($this->subject() != $ancestor->subject()) { |
| 432 | + $set['thread_subject'] = $ancestor->subject(); |
| 433 | + |
| 434 | + $this->subject = $ancestor->subject(); |
| 435 | + } |
| 436 | + |
395 | 437 | // Fix missing authorship information |
| 438 | + // (this information only started to be added later) |
396 | 439 | if ( !$this->authorName ) { |
397 | 440 | $author = $this->root()->originalAuthor(); |
398 | 441 | |
— | — | @@ -402,6 +445,19 @@ |
403 | 446 | $set['thread_author_id'] = $this->authorId; |
404 | 447 | } |
405 | 448 | |
| 449 | + // Check for article corruption from incomplete thread moves. |
| 450 | + // (thread moves only updated this on immediate replies, not replies to replies etc) |
| 451 | + if (! $ancestor->article()->getTitle()->equals( $this->article()->getTitle() ) ) { |
| 452 | + $title = $ancestor->article()->getTitle(); |
| 453 | + $set['thread_article_namespace'] = $title->getNamespace(); |
| 454 | + $set['thread_article_title'] = $title->getDbKey(); |
| 455 | + |
| 456 | + $this->articleNamespace = $title->getNamespace(); |
| 457 | + $this->articleTitle = $title->getDbKey(); |
| 458 | + |
| 459 | + $this->article = $ancestor->article(); |
| 460 | + } |
| 461 | + |
406 | 462 | if ( count($set) ) { |
407 | 463 | $dbw = wfGetDB( DB_MASTER ); |
408 | 464 | |
— | — | @@ -467,6 +523,12 @@ |
468 | 524 | return $this->replies; |
469 | 525 | } |
470 | 526 | |
| 527 | + // Check cache |
| 528 | + if ( isset( self::$replyCacheById[$this->id()] ) ) { |
| 529 | + $this->replies = self::$replyCacheById[$this->id()]; |
| 530 | + return $this->replies; |
| 531 | + } |
| 532 | + |
471 | 533 | $this->replies = array(); |
472 | 534 | |
473 | 535 | $dbr = wfGetDB( DB_SLAVE ); |
— | — | @@ -485,6 +547,12 @@ |
486 | 548 | } |
487 | 549 | |
488 | 550 | function setSuperthread( $thread ) { |
| 551 | + if ($thread == null) { |
| 552 | + $this->parentId = null; |
| 553 | + $this->ancestorId = $this->id(); |
| 554 | + return; |
| 555 | + } |
| 556 | + |
489 | 557 | $this->parentId = $thread->id(); |
490 | 558 | |
491 | 559 | if ( $thread->isTopmostThread() ) { |
— | — | @@ -523,6 +591,14 @@ |
524 | 592 | return $thread; |
525 | 593 | } |
526 | 594 | } |
| 595 | + |
| 596 | + function setAncestor( $newAncestor ) { |
| 597 | + if ( is_object( $newAncestor ) ) { |
| 598 | + $this->ancestorId = $newAncestor->id(); |
| 599 | + } else { |
| 600 | + $this->ancestorId = $newAncestor; |
| 601 | + } |
| 602 | + } |
527 | 603 | |
528 | 604 | // Due to a bug in earlier versions, the topmost thread sometimes isn't there. |
529 | 605 | // Fix the corruption by repeatedly grabbing the parent until we hit the topmost thread. |
— | — | @@ -656,6 +732,11 @@ |
657 | 733 | |
658 | 734 | function setSubject( $subject ) { |
659 | 735 | $this->subject = $subject; |
| 736 | + |
| 737 | + foreach( $this->replies() as $reply ) { |
| 738 | + $reply->setSubject( $subject ); |
| 739 | + $reply->commitRevision( CHANGE_EDITED_SUBJECT ); |
| 740 | + } |
660 | 741 | } |
661 | 742 | |
662 | 743 | function wikilinkWithoutIncrement() { |
— | — | @@ -667,12 +748,7 @@ |
668 | 749 | } |
669 | 750 | |
670 | 751 | function hasDistinctSubject() { |
671 | | - if ( $this->hasSuperthread() ) { |
672 | | - return $this->superthread()->subjectWithoutIncrement() |
673 | | - != $this->subjectWithoutIncrement(); |
674 | | - } else { |
675 | | - return true; |
676 | | - } |
| 752 | + return $this->isTopmostThread(); |
677 | 753 | } |
678 | 754 | |
679 | 755 | function hasSubthreads() { |
— | — | @@ -799,4 +875,8 @@ |
800 | 876 | function getArchiveStartDays() { |
801 | 877 | return Threads::getArticleArchiveStartDays( $this->article() ); |
802 | 878 | } |
| 879 | + |
| 880 | + function getAnchorName() { |
| 881 | + return "lqt_thread_{$this->id()}"; |
| 882 | + } |
803 | 883 | } |