Index: trunk/extensions/LiquidThreads/i18n/Lqt.i18n.php |
— | — | @@ -147,6 +147,13 @@ |
148 | 148 | 'lqt_rc_ellipsis' => ' ...', |
149 | 149 | 'lqt_rc_author_original' => '(original author)', |
150 | 150 | 'lqt_rc_author_others' => '(not the author)', |
| 151 | + 'lqt-newmessages-context' => 'Full thread', |
| 152 | + 'lqt-thread-created' => 'Created', |
| 153 | + 'lqt-archive-subtitle' => 'Discussion archive', |
| 154 | + 'lqt-archive-intro' => 'This is the discussion archive for [[$1]].', |
| 155 | + 'lqt-history-time' => 'Time', |
| 156 | + 'lqt-history-user' => 'User', |
| 157 | + 'lqt-history-action' => 'Activity', |
151 | 158 | |
152 | 159 | // Logging |
153 | 160 | 'lqt-log-name' => 'Threaded discussion log', |
Index: trunk/extensions/LiquidThreads/lqt.css |
— | — | @@ -460,3 +460,9 @@ |
461 | 461 | .lqt_toc td { |
462 | 462 | border-bottom: 1px solid #aaaaaa; |
463 | 463 | } |
| 464 | + |
| 465 | +.lqt-newmessages-left { |
| 466 | + padding-right: 1em; |
| 467 | + vertical-align: top; |
| 468 | + padding-top: 1em; |
| 469 | +} |
Index: trunk/extensions/LiquidThreads/classes/LqtThreads.php |
— | — | @@ -28,6 +28,9 @@ |
29 | 29 | |
30 | 30 | static $cache_by_root = array(); |
31 | 31 | static $cache_by_id = array(); |
| 32 | + |
| 33 | + /** static cache of per-page archivestartdays setting */ |
| 34 | + static $archiveStartDays; |
32 | 35 | |
33 | 36 | static function newThread( $root, $article, $superthread = null, $type = self::TYPE_NORMAL ) { |
34 | 37 | // SCHEMA changes must be reflected here. |
— | — | @@ -148,7 +151,6 @@ |
149 | 152 | $tables = ""; |
150 | 153 | } |
151 | 154 | |
152 | | - |
153 | 155 | $selection_sql = <<< SQL |
154 | 156 | SELECT DISTINCT thread.* FROM ($tables {$wgDBprefix}thread thread) |
155 | 157 | $joins |
— | — | @@ -169,6 +171,8 @@ |
170 | 172 | } // List comprehensions, how I miss thee. |
171 | 173 | $ancestor_clause = join( ', ', $ancestor_conds ); |
172 | 174 | $selection_clause = join( ', ', $selection_conds ); |
| 175 | + |
| 176 | + // TODO uses a subquery, unsupported on Wikimedia |
173 | 177 | |
174 | 178 | $children_sql = <<< SQL |
175 | 179 | SELECT DISTINCT thread.*, page.*, |
— | — | @@ -262,30 +266,91 @@ |
263 | 267 | } |
264 | 268 | |
265 | 269 | /** |
266 | | - * Horrible, horrible! |
267 | | - * List of months in which there are >0 threads, suitable for threadsOfArticleInMonth. */ |
| 270 | + * Horrible, horrible! |
| 271 | + * List of months in which there are >0 threads, suitable for threadsOfArticleInMonth. |
| 272 | + * Returned as an array of months in the format yyyymm |
| 273 | + */ |
268 | 274 | static function monthsWhereArticleHasThreads( $article ) { |
| 275 | + // FIXME this probably performs absolutely horribly for pages with lots of threads. |
| 276 | + |
269 | 277 | $threads = Threads::where( Threads::articleClause( $article ) ); |
270 | 278 | $months = array(); |
| 279 | + |
271 | 280 | foreach ( $threads as $t ) { |
272 | | - $m = substr( $t->modified(), 0, 6 ); |
273 | | - if ( !array_key_exists( $m, $months ) ) { |
274 | | - if ( !in_array( $m, $months ) ) $months[] = $m; |
275 | | - } |
| 281 | + $month = substr( $t->modified(), 0, 6 ); |
| 282 | + |
| 283 | + $months[$month] = true; |
276 | 284 | } |
277 | | - return $months; |
| 285 | + |
| 286 | + // Some code seems to assume that it's sorted by month, make sure it's true. |
| 287 | + ksort( $months ); |
| 288 | + |
| 289 | + return array_keys($months); |
278 | 290 | } |
279 | 291 | |
280 | 292 | static function articleClause( $article ) { |
281 | 293 | $dbr = wfGetDB( DB_SLAVE ); |
282 | | - $q_article = $dbr->addQuotes( $article->getTitle()->getDBkey() ); |
283 | | - return <<<SQL |
284 | | -(thread.thread_article_title = $q_article |
285 | | - AND thread.thread_article_namespace = {$article->getTitle()->getNamespace()}) |
286 | | -SQL; |
| 294 | + |
| 295 | + $arr = array( 'thread_article_title' => $article->getTitle()->getDBKey(), |
| 296 | + 'thread_article_namespace' => $article->getTitle()->getNamespace() ); |
| 297 | + |
| 298 | + return $dbr->makeList( $arr, LIST_AND ); |
287 | 299 | } |
288 | 300 | |
289 | 301 | static function topLevelClause() { |
290 | | - return 'thread.thread_parent is null'; |
| 302 | + $dbr = wfGetDB( DB_SLAVE ); |
| 303 | + |
| 304 | + $arr = array( 'thread_ancestor=thread_id', 'thread_parent' => null ); |
| 305 | + |
| 306 | + return $dbr->makeList( $arr, LIST_AND ); |
291 | 307 | } |
| 308 | + |
| 309 | + static function getArticleArchiveStartDays( $article ) { |
| 310 | + global $wgLqtThreadArchiveStartDays; |
| 311 | + |
| 312 | + $article = $article->getId(); |
| 313 | + |
| 314 | + // Instance cache |
| 315 | + if ( isset( self::$archiveStartDays[$article] ) ) { |
| 316 | + $cacheVal = self::$archiveStartDays[$article]; |
| 317 | + if ( !is_null( $cacheVal ) ) { |
| 318 | + return $cacheVal; |
| 319 | + } else { |
| 320 | + return $wgLqtThreadArchiveStartDays; |
| 321 | + } |
| 322 | + } |
| 323 | + |
| 324 | + // Memcached: It isn't clear that this is needed yet, but since I already wrote the |
| 325 | + // code, I might as well leave it commented out instead of deleting it. |
| 326 | + // Main reason I've left this commented out is because it isn't obvious how to |
| 327 | + // purge the cache when necessary. |
| 328 | +// global $wgMemc; |
| 329 | +// $key = wfMemcKey( 'lqt-archive-start-days', $article ); |
| 330 | +// $cacheVal = $wgMemc->get( $key ); |
| 331 | +// if ($cacheVal != false) { |
| 332 | +// if ( $cacheVal != -1 ) { |
| 333 | +// return $cacheVal; |
| 334 | +// } else { |
| 335 | +// return $wgLqtThreadArchiveStartDays; |
| 336 | +// } |
| 337 | +// } |
| 338 | + |
| 339 | + // Load from the database. |
| 340 | + $dbr = wfGetDB( DB_SLAVE ); |
| 341 | + |
| 342 | + $dbVal = $dbr->selectField( 'page_props', 'pp_value', |
| 343 | + array( 'pp_propname' => 'lqt-archivestartdays', |
| 344 | + 'pp_page' => $article ), __METHOD__ ); |
| 345 | + |
| 346 | + if ($dbVal) { |
| 347 | + self::$archiveStartDays[$article] = $dbVal; |
| 348 | +# $wgMemc->set( $key, $dbVal, 1800 ); |
| 349 | + return $dbVal; |
| 350 | + } else { |
| 351 | + // Negative caching. |
| 352 | + self::$archiveStartDays[$article] = null; |
| 353 | +# $wgMemc->set( $key, -1, 86400 ); |
| 354 | + return $wgLqtThreadArchiveStartDays; |
| 355 | + } |
| 356 | + } |
292 | 357 | } |
Index: trunk/extensions/LiquidThreads/classes/LqtView.php |
— | — | @@ -131,15 +131,6 @@ |
132 | 132 | * (2) figuring out what page you're on and what you need to do. |
133 | 133 | *************************/ |
134 | 134 | |
135 | | - static function queryStringFromArray( $vars ) { |
136 | | - $q = ''; |
137 | | - if ( $vars && count( $vars ) != 0 ) { |
138 | | - foreach ( $vars as $name => $value ) |
139 | | - $q .= "$name=$value&"; |
140 | | - } |
141 | | - return $q; |
142 | | - } |
143 | | - |
144 | 135 | function methodAppliesToThread( $method, $thread ) { |
145 | 136 | return $this->request->getVal( 'lqt_method' ) == $method && |
146 | 137 | $this->request->getVal( 'lqt_operand' ) == $thread->id(); |
— | — | @@ -148,9 +139,12 @@ |
149 | 140 | return $this->request->getVal( 'lqt_method' ) == $method; |
150 | 141 | } |
151 | 142 | |
152 | | - static function permalinkUrl( $thread, $method = null, $operand = null ) { |
| 143 | + static function permalinkUrl( $thread, $method = null, $operand = null, |
| 144 | + $uquery = array() ) { |
153 | 145 | list ($title, $query) = self::permalinkData( $thread, $method, $operand ); |
154 | 146 | |
| 147 | + $query = array_merge( $query, $uquery ); |
| 148 | + |
155 | 149 | $queryString = wfArrayToCGI( $query ); |
156 | 150 | |
157 | 151 | return $title->getFullUrl( $queryString ); |
— | — | @@ -173,12 +167,15 @@ |
174 | 168 | /* This is used for action=history so that the history tab works, which is |
175 | 169 | why we break the lqt_method paradigm. */ |
176 | 170 | static function permalinkUrlWithQuery( $thread, $query ) { |
177 | | - if ( is_array( $query ) ) $query = self::queryStringFromArray( $query ); |
178 | | - return $thread->root()->getTitle()->getFullUrl( $query ); |
| 171 | + if ( !is_array($query) ) { |
| 172 | + $query = wfCGIToArray( $query ); |
| 173 | + } |
| 174 | + |
| 175 | + return self::permalinkUrl( $thread, null, null, $query ); |
179 | 176 | } |
180 | 177 | |
181 | 178 | static function permalink( $thread, $text = null, $method = null, $operand = null, |
182 | | - $sk = null, $attribs = array() ) { |
| 179 | + $sk = null, $attribs = array(), $uquery = array() ) { |
183 | 180 | if ( is_null($sk) ) { |
184 | 181 | global $wgUser; |
185 | 182 | $sk = $wgUser->getSkin(); |
— | — | @@ -186,50 +183,105 @@ |
187 | 184 | |
188 | 185 | list( $title, $query ) = self::permalinkData( $thread, $method, $operand ); |
189 | 186 | |
| 187 | + $query = array_merge( $query, $uquery ); |
| 188 | + |
190 | 189 | return $sk->link( $title, $text, $attribs, $query ); |
191 | 190 | } |
192 | | - |
193 | | - static function permalinkUrlWithDiff( $thread ) { |
| 191 | + |
| 192 | + static function diffQuery( $thread ) { |
194 | 193 | $changed_thread = $thread->changeObject(); |
195 | 194 | $curr_rev_id = $changed_thread->rootRevision(); |
196 | 195 | $curr_rev = Revision::newFromTitle( $changed_thread->root()->getTitle(), $curr_rev_id ); |
197 | 196 | $prev_rev = $curr_rev->getPrevious(); |
198 | 197 | $oldid = $prev_rev ? $prev_rev->getId() : ""; |
199 | | - return self::permalinkUrlWithQuery( $changed_thread, array( 'lqt_method' => 'diff', 'diff' => $curr_rev_id, 'oldid' => $oldid ) ); |
| 198 | + |
| 199 | + $query = array( 'lqt_method' => 'diff', |
| 200 | + 'diff' => $curr_rev_id, |
| 201 | + 'oldid' => $oldid ); |
| 202 | + |
| 203 | + return $query; |
200 | 204 | } |
201 | 205 | |
202 | | - static function talkpageUrl( $title, $method = null, $operand = null, $includeFragment = true ) { |
203 | | - global $wgRequest; // TODO global + ugly hack. |
204 | | - $query = $method ? "lqt_method=$method" : ""; |
205 | | - $query = $operand ? "$query&lqt_operand={$operand->id()}" : $query; |
206 | | - $oldid = $wgRequest->getVal( 'oldid', null ); if ( $oldid !== null ) { |
| 206 | + static function permalinkUrlWithDiff( $thread ) { |
| 207 | + $query = self::diffQuery( $thread ); |
| 208 | + return $this->permalinkUrl( $thread->changeObject(), null, null, $query ); |
| 209 | + } |
| 210 | + |
| 211 | + static function diffPermalink( $thread, $text ) { |
| 212 | + $query = self::diffQuery( $thread ); |
| 213 | + return $this->permalink( $thread, $text, null, null, null, array(), $query ); |
| 214 | + } |
| 215 | + |
| 216 | + static function talkpageLink( $title, $text = null , $method=null, $operand=null, |
| 217 | + $includeFragment=true, $attribs = array() ) { |
| 218 | + list( $title, $query ) = self::talkpageLinkData( $title, $method, $operand, |
| 219 | + $includeFragment ); |
| 220 | + |
| 221 | + global $wgUser; |
| 222 | + $sk = $wgUser->getSkin(); |
| 223 | + |
| 224 | + return $sk->link( $title, $text, $attribs, $query ); |
| 225 | + } |
| 226 | + |
| 227 | + static function talkpageLinkData( $title, $method = null, $operand = null, |
| 228 | + $includeFragment = true ) { |
| 229 | + global $wgRequest; |
| 230 | + $query = array(); |
| 231 | + |
| 232 | + if ($method) { |
| 233 | + $query['lqt_method'] = $method; |
| 234 | + } |
| 235 | + |
| 236 | + if ($operand) { |
| 237 | + $query['lqt_operand'] = $operand->id(); |
| 238 | + } |
| 239 | + |
| 240 | + $oldid = $wgRequest->getVal( 'oldid', null ); |
| 241 | + |
| 242 | + if ( $oldid !== null ) { |
207 | 243 | // this is an immensely ugly hack to make editing old revisions work. |
208 | | - $query = "$query&oldid=$oldid"; |
| 244 | + $query['oldid'] = $oldid; |
209 | 245 | } |
210 | | - return $title->getFullURL( $query ) . ( $operand && $includeFragment ? "#lqt_thread_{$operand->id()}" : "" ); |
| 246 | + |
| 247 | + // Add fragment if appropriate. |
| 248 | + if ($operand && $includeFragment) { |
| 249 | + $title->mFragment = 'lqt_thread_'.$operand->id(); |
| 250 | + } |
| 251 | + |
| 252 | + return array( $title, $query ); |
211 | 253 | } |
212 | 254 | |
| 255 | + static function talkpageUrl( $title, $method = null, $operand = null, |
| 256 | + $includeFragment = true ) { |
| 257 | + global $wgUser; |
| 258 | + $sk = $wgUser->getSkin(); |
| 259 | + |
| 260 | + list( $title, $query ) = |
| 261 | + self::talkpageLinkData( $title, $method, $operand, $includeFragment ); |
| 262 | + |
| 263 | + return $title->getLinkUrl( $query ); |
| 264 | + } |
213 | 265 | |
| 266 | + |
214 | 267 | /** |
215 | 268 | * Return a URL for the current page, including Title and query vars, |
216 | 269 | * with the given replacements made. |
217 | 270 | * @param $repls array( 'name'=>new_value, ... ) |
218 | 271 | */ |
219 | | - function queryReplace( $repls ) { |
220 | | - $vs = $this->request->getValues(); |
221 | | - $rs = array(); |
222 | | -/* foreach ($vs as $k => $v) { |
223 | | - if ( array_key_exists( $k, $repls ) ) { |
224 | | - $rs[$k] = $repls[$k]; |
225 | | - } else { |
226 | | - $rs[$k] = $vs[$k]; |
227 | | - } |
| 272 | + function queryReplaceLink( $repls ) { |
| 273 | + $query = $this->getReplacedQuery( $repls ); |
| 274 | + |
| 275 | + return $this->title->getFullURL( wfArrayToCGI( $vs ) ); |
| 276 | + } |
| 277 | + |
| 278 | + function getReplacedQuery( $replacements ) { |
| 279 | + $values = $this->request->getValues(); |
| 280 | + |
| 281 | + foreach ( $replacements as $k => $v ) { |
| 282 | + $values[$k] = $v; |
228 | 283 | } |
229 | | -*/ |
230 | | - foreach ( $repls as $k => $v ) { |
231 | | - $vs[$k] = $v; |
232 | | - } |
233 | | - return $this->title->getFullURL( self::queryStringFromArray( $vs ) ); |
| 284 | + |
| 285 | + return $values; |
234 | 286 | } |
235 | 287 | |
236 | 288 | /************************************************************* |
— | — | @@ -510,7 +562,8 @@ |
511 | 563 | |
512 | 564 | $user_can_edit = $thread->root()->getTitle()->quickUserCan( 'edit' ); |
513 | 565 | |
514 | | - $commands[] = array( 'label' => $user_can_edit ? wfMsg( 'edit' ) : wfMsg( 'viewsource' ), |
| 566 | + $commands[] = array( 'label' => $user_can_edit |
| 567 | + ? wfMsg( 'edit' ) : wfMsg( 'viewsource' ), |
515 | 568 | 'href' => $this->talkpageUrl( $this->title, 'edit', $thread ), |
516 | 569 | 'enabled' => true ); |
517 | 570 | |
— | — | @@ -594,43 +647,17 @@ |
595 | 648 | $wgOut->addScript( $s ); |
596 | 649 | } |
597 | 650 | |
598 | | - /* @return False if the article and revision do not exist and we didn't show it, true if we did. */ |
| 651 | + /* @return False if the article and revision do not exist. The HTML of the page to |
| 652 | + * display if it exists. Note that this impacts the state out OutputPage by adding |
| 653 | + * all the other relevant parts of the parser output. If you don't want this, call |
| 654 | + * $post->getParserOutput. */ |
599 | 655 | function showPostBody( $post, $oldid = null ) { |
600 | | - /* Why isn't this all encapsulated in Article somewhere? TODO */ |
601 | | - global $wgEnableParserCache; |
602 | | - |
603 | | - // Should the parser cache be used? |
604 | | - $pcache = $wgEnableParserCache && |
605 | | - intval( $this->user->getOption( 'stubthreshold' ) ) == 0 && |
606 | | - $post->exists() && |
607 | | - $oldid === null; |
608 | | - wfDebug( 'LqtView::showPostBody using parser cache: ' . ( $pcache ? 'yes' : 'no' ) . "\n" ); |
609 | | - if ( $this->user->getOption( 'stubthreshold' ) ) { |
610 | | - wfIncrStats( 'pcache_miss_stub' ); |
611 | | - } |
612 | | - |
613 | | - $outputDone = false; |
614 | | - if ( $pcache ) { |
615 | | - $outputDone = $this->output->tryParserCache( $post, $this->user ); |
616 | | - } |
617 | | - |
618 | | - if ( !$outputDone ) { |
619 | | - // Cache miss; parse and output it. |
620 | | - $rev = Revision::newFromTitle( $post->getTitle(), $oldid ); |
621 | | - if ( $rev && $oldid ) { |
622 | | - // don't save oldids in the parser cache. |
623 | | - $this->output->addWikiText( $rev->getText() ); |
624 | | - return true; |
625 | | - } |
626 | | - else if ( $rev ) { |
627 | | - $post->outputWikiText( $rev->getText(), true ); |
628 | | - return true; |
629 | | - } else { |
630 | | - return false; |
631 | | - } |
632 | | - } else { |
633 | | - return true; |
634 | | - } |
| 656 | + global $wgOut; |
| 657 | + |
| 658 | + $parserOutput = $post->getParserOutput( $oldid ); |
| 659 | + $wgOut->addParserOutputNoText( $parserOutput ); |
| 660 | + |
| 661 | + return $parserOutput->getText(); |
635 | 662 | } |
636 | 663 | |
637 | 664 | function colorTest() { |
— | — | @@ -677,7 +704,7 @@ |
678 | 705 | |
679 | 706 | $html = Xml::tags( 'ul', array( 'class' => 'lqt_footer' ), $html ); |
680 | 707 | |
681 | | - $this->output->addHTML( $html ); |
| 708 | + return $html; |
682 | 709 | } |
683 | 710 | |
684 | 711 | function listItemsForCommands( $commands ) { |
— | — | @@ -709,6 +736,8 @@ |
710 | 737 | // or from oldid (which is a page rev). But oldid only applies to the |
711 | 738 | // thread being requested, not any replies. TODO: eliminate the need |
712 | 739 | // for article-level histories. |
| 740 | + $divClass = $this->postDivClass( $thread ); |
| 741 | + $html = Xml::openElement( 'div', array( 'class' => $divClass ) ); |
713 | 742 | $page_rev = $this->request->getVal( 'oldid', null ); |
714 | 743 | if ( $page_rev !== null && $this->title->equals( $thread->root()->getTitle() ) ) { |
715 | 744 | $oldid = $page_rev; |
— | — | @@ -716,22 +745,30 @@ |
717 | 746 | $oldid = $thread->isHistorical() ? $thread->rootRevision() : null; |
718 | 747 | } |
719 | 748 | |
720 | | - $this->openDiv( $this->postDivClass( $thread ) ); |
721 | | - |
722 | 749 | if ( $this->methodAppliesToThread( 'edit', $thread ) ) { |
| 750 | + $this->output->addHTML( $html ); |
| 751 | + $html = ''; |
| 752 | + |
| 753 | + // No way am I refactoring EditForm to send its output as HTML. |
| 754 | + // so I'm just flushing the HTML and displaying it as-is. |
723 | 755 | $this->showPostEditingForm( $thread ); |
724 | 756 | } else { |
725 | | - $this->showPostBody( $post, $oldid ); |
726 | | - $this->showThreadFooter( $thread ); |
| 757 | + $html .= $this->showPostBody( $post, $oldid ); |
| 758 | + $html .= $this->showThreadFooter( $thread ); |
727 | 759 | } |
728 | 760 | |
729 | | - $this->closeDiv(); |
| 761 | + // wish I didn't have to use this open/closeElement cruft. |
| 762 | + $html .= Xml::closeElement( 'div' ); |
730 | 763 | |
731 | 764 | if ( $this->methodAppliesToThread( 'reply', $thread ) ) { |
732 | | - $this->indent( $thread ); |
| 765 | + // As with above, flush HTML to avoid refactoring EditPage. |
| 766 | + $html .= $this->indent( $thread ); |
| 767 | + $this->output->addHTML( $html ); |
733 | 768 | $this->showReplyForm( $thread ); |
734 | | - $this->unindent( $thread ); |
| 769 | + $html = $this->unindent( $thread ); |
735 | 770 | } |
| 771 | + |
| 772 | + $this->output->addHTML( $html ); |
736 | 773 | |
737 | 774 | $popts->setEditSection( $previous_editsection ); |
738 | 775 | $this->output->parserOptions( $popts ); |
— | — | @@ -753,8 +790,10 @@ |
754 | 791 | $html = Xml::tags( 'h'.$this->headerLevel, array( 'class' => 'lqt_header' ), |
755 | 792 | $html ) . $commands_html; |
756 | 793 | |
757 | | - $this->output->addHTML( $html ); |
| 794 | + return $html; |
758 | 795 | } |
| 796 | + |
| 797 | + return ''; |
759 | 798 | } |
760 | 799 | |
761 | 800 | function postDivClass( $thread ) { |
— | — | @@ -766,130 +805,169 @@ |
767 | 806 | } |
768 | 807 | |
769 | 808 | function showThread( $thread ) { |
770 | | - global $wgLang; # TODO global. |
| 809 | + global $wgLang; |
| 810 | + |
| 811 | + $sk = $this->user->getSkin(); |
| 812 | + |
| 813 | + $html = ''; |
771 | 814 | |
772 | 815 | // Safeguard |
773 | 816 | if ( $thread->type() == Threads::TYPE_DELETED |
774 | | - && ! $this->request->getBool( 'lqt_show_deleted_threads' ) ) |
775 | | - return; |
| 817 | + && ! ($this->request->getBool( 'lqt_show_deleted_threads' ) |
| 818 | + && $this->user->isAllowed( 'deletedhistory' ) ) ) { |
| 819 | + return; |
| 820 | + } |
776 | 821 | |
777 | 822 | if ( $this->lastUnindentedSuperthread ) { |
778 | 823 | wfLoadExtensionMessages( 'LiquidThreads' ); |
779 | 824 | $tmp = $this->lastUnindentedSuperthread; |
780 | | - $msg = wfMsg( 'lqt_in_response_to', |
781 | | - '<a href="#lqt_thread_' . $tmp->id() . '">' . $tmp->title()->getText() . '</a>', |
782 | | - $tmp->root()->originalAuthor()->getName() ); |
783 | | - $this->output->addHTML( '<span class="lqt_nonindent_message">←' . $msg . '</span>' ); |
| 825 | + $replyLink = Xml::tags( 'a', array( 'href' => '#'.$this->anchorName( $tmp ) ), |
| 826 | + $tmp->subject() ); |
| 827 | + $msg = wfMsgExt( 'lqt_in_response_to', array( 'parseinline', 'replaceafter' ), |
| 828 | + array( $replyLink, $tmp->root()->originalAuthor()->getName() ) ); |
| 829 | + |
| 830 | + $html .= Xml::tags( 'span', array( 'class' => 'lqt_nonindent_message' ), |
| 831 | + "← $msg" ); |
784 | 832 | } |
785 | 833 | |
786 | 834 | |
787 | | - $this->showThreadHeading( $thread ); |
| 835 | + $html .= $this->showThreadHeading( $thread ); |
788 | 836 | |
789 | | - $this->output->addHTML( "<a name=\"{$this->anchorName($thread)}\" ></a>" ); |
| 837 | + $html .= Xml::element( 'a', array( 'name' => $this->anchorName($thread) ), ' ' ); |
790 | 838 | |
791 | 839 | if ( $thread->type() == Threads::TYPE_MOVED ) { |
792 | 840 | wfLoadExtensionMessages( 'LiquidThreads' ); |
| 841 | + |
793 | 842 | $revision = Revision::newFromTitle( $thread->title() ); |
794 | 843 | $target = Title::newFromRedirect( $revision->getText() ); |
795 | 844 | $t_thread = Threads::withRoot( new Article( $target ) ); |
796 | 845 | $author = $thread->root()->originalAuthor(); |
797 | | - $sig = $this->user->getSkin()->userLink( $author->getID(), $author->getName() ) . |
798 | | - $this->user->getSkin()->userToolLinks( $author->getID(), $author->getName() ); |
799 | | - $this->output->addHTML( wfMsg( 'lqt_move_placeholder', |
800 | | - '<a href="' . $target->getFullURL() . '">' . $target->getText() . '</a>', |
801 | | - $sig, |
802 | | - $wgLang->date( $thread->modified() ), |
803 | | - $wgLang->time( $thread->modified() ) |
804 | | - ) ); |
805 | | - return; |
| 846 | + $sig = $sk->userLink( $author->getID(), $author->getName() ) . |
| 847 | + $sk->userToolLinks( $author->getID(), $author->getName() ); |
| 848 | + |
| 849 | + $html .= |
| 850 | + wfMsgExt( 'lqt_move_placeholder', array( 'parseinline', 'replaceafter' ), |
| 851 | + $sk->link( $target ), |
| 852 | + $sig, |
| 853 | + $wgLang->date( $thread->modified() ), |
| 854 | + $wgLang->time( $thread->modified() ) |
| 855 | + ); |
| 856 | + return $html; |
806 | 857 | } |
807 | 858 | |
808 | 859 | if ( $thread->type() == Threads::TYPE_DELETED ) { |
809 | 860 | wfLoadExtensionMessages( 'LiquidThreads' ); |
810 | 861 | if ( in_array( 'deletedhistory', $this->user->getRights() ) ) { |
811 | | - $this->output->addHTML( '<p>' . wfMsg( 'lqt_thread_deleted_for_sysops' ) . '</p>' ); |
| 862 | + $html .= wfMsgExt( 'lqt_thread_deleted_for_sysops', 'parse' ); |
812 | 863 | } |
813 | 864 | else { |
814 | | - $this->output->addHTML( '<p><em>' . wfMsg( 'lqt_thread_deleted' ) . '</em></p>' ); |
815 | | - return; |
| 865 | + $msg = wfMsgExt( 'lqt_thread_deleted', 'parseinline' ); |
| 866 | + $msg = Xml::tags( 'em', null, $msg ); |
| 867 | + $msg = Xml::tags( 'p', null, $msg ); |
| 868 | + $html .= $msg; |
| 869 | + return $html; |
816 | 870 | } |
817 | 871 | } |
818 | 872 | if ( $thread->summary() ) { |
819 | | - $this->showSummary( $thread ); |
| 873 | + $html .= $this->showPostBody( $thread->summary() ); |
820 | 874 | } elseif( $thread->isArchiveEligible() ) |
821 | 875 | { |
822 | 876 | wfLoadExtensionMessages( 'LiquidThreads' ); |
823 | 877 | |
824 | 878 | $permalink_text = wfMsgNoTrans( 'lqt_summary_notice_link' ); |
825 | 879 | $permalink = $this->permalink( $thread, $permalink_text ); |
826 | | - $html = wfMsgExt( 'lqt_summary_notice', array('parseinline', 'replaceafter'), |
| 880 | + $msg = wfMsgExt( 'lqt_summary_notice', array('parseinline', 'replaceafter'), |
827 | 881 | array( $permalink, $thread->getArchiveStartDays() ) ); |
828 | | - $html = Xml::tags( 'p', array( 'class' => 'lqt_summary_notice' ), $html ); |
| 882 | + $msg = Xml::tags( 'p', array( 'class' => 'lqt_summary_notice' ), $msg ); |
829 | 883 | |
830 | | - $this->output->addHTML( $html ); |
| 884 | + $html .= $msg; |
831 | 885 | } |
832 | 886 | |
833 | | - $this->openDiv( 'lqt_thread', "lqt_thread_id_{$thread->id()}" ); |
| 887 | + // Sigh. |
| 888 | + $html .= Xml::openElement( 'div', array( 'class' => 'lqt_thread', |
| 889 | + 'id' => 'lqt_thread_id_'. $thread->id() ) ); |
| 890 | + |
| 891 | + // Unfortunately, I can't rewrite showRootPost() to pass back HTML |
| 892 | + // as it would involve rewriting EditPage, which I do NOT intend to do. |
834 | 893 | |
| 894 | + $this->output->addHTML( $html ); |
| 895 | + |
835 | 896 | $this->showRootPost( $thread ); |
836 | 897 | |
837 | | - if ( $thread->hasSubthreads() ) $this->indent( $thread ); |
838 | | - foreach ( $thread->subthreads() as $st ) { |
839 | | - $this->showThread( $st ); |
| 898 | + if ( $thread->hasSubthreads() ) { |
| 899 | + $this->output->addHTML( $this->indent( $thread ) ); |
| 900 | + |
| 901 | + foreach ( $thread->subthreads() as $st ) { |
| 902 | + $this->showThread( $st ); |
| 903 | + } |
| 904 | + |
| 905 | + $this->output->addHTML( $this->unindent( $thread ) ); |
840 | 906 | } |
841 | | - if ( $thread->hasSubthreads() ) $this->unindent( $thread ); |
842 | 907 | |
843 | | - $this->closeDiv(); |
| 908 | + $this->output->addHTML( Xml::closeElement( 'div' ) ); |
844 | 909 | } |
845 | 910 | |
| 911 | + // FIXME does indentation need rethinking? |
846 | 912 | function indent( $thread ) { |
| 913 | + $result = ''; |
847 | 914 | if ( $this->headerLevel <= $this->maxIndentationLevel ) { |
848 | | - $this->output->addHTML( '<dl class="lqt_replies"><dd>' ); |
| 915 | + $result = '<dl class="lqt_replies"><dd>'; |
849 | 916 | } else { |
850 | | - $this->output->addHTML( '<div class="lqt_replies_without_indent">' ); |
| 917 | + $result = '<div class="lqt_replies_without_indent">'; |
851 | 918 | } |
852 | 919 | $this->lastUnindentedSuperthread = null; |
853 | 920 | $this->headerLevel += 1; |
| 921 | + |
| 922 | + return $result; |
854 | 923 | } |
| 924 | + |
855 | 925 | function unindent( $thread ) { |
| 926 | + $result = ''; |
856 | 927 | if ( $this->headerLevel <= $this->maxIndentationLevel + 1 ) { |
857 | | - $this->output->addHTML( '</dd></dl>' ); |
| 928 | + $result = '</dd></dl>'; |
858 | 929 | } else { |
859 | | - $this->output->addHTML( '</div>' ); |
| 930 | + $result = '</div>'; |
860 | 931 | } |
861 | 932 | // See the beginning of showThread(). |
862 | 933 | $this->lastUnindentedSuperthread = $thread->superthread(); |
863 | 934 | $this->headerLevel -= 1; |
| 935 | + |
| 936 | + return $result; |
864 | 937 | } |
865 | 938 | |
866 | | - function openDiv( $class = '', $id = '' ) { |
867 | | - $this->output->addHTML( Xml::openElement( 'div', array( 'class' => $class, 'id' => $id ) ) ); |
868 | | - } |
869 | | - |
870 | | - function closeDiv() { |
871 | | - $this->output->addHTML( Xml::closeElement( 'div' ) ); |
872 | | - } |
873 | | - |
874 | | - function showSummary( $t ) { |
| 939 | + function getSummary( $t ) { |
875 | 940 | if ( !$t->summary() ) return; |
876 | 941 | wfLoadExtensionMessages( 'LiquidThreads' ); |
877 | | - $label = wfMsg( 'lqt_summary_label' ); |
878 | | - $edit = strtolower( wfMsg( 'edit' ) ); |
879 | | - $link = strtolower( wfMsg( 'lqt_permalink' ) ); |
880 | | - $this->output->addHTML( <<<HTML |
881 | | - <div class='lqt_thread_permalink_summary'> |
882 | | - <span class="lqt_thread_permalink_summary_title"> |
883 | | - $label |
884 | | - </span><span class="lqt_thread_permalink_summary_edit"> |
885 | | - [<a href="{$t->summary()->getTitle()->getFullURL()}">$link</a>] |
886 | | - [<a href="{$this->permalinkUrl($t,'summarize')}">$edit</a>] |
887 | | - </span> |
888 | | -HTML |
889 | | - ); |
890 | | - $this->openDiv( 'lqt_thread_permalink_summary_body' ); |
891 | | - $this->showPostBody( $t->summary() ); |
892 | | - $this->closeDiv(); |
893 | | - $this->closeDiv(); |
| 942 | + global $wgUser; |
| 943 | + $sk = $wgUser->getSkin(); |
| 944 | + |
| 945 | + $label = wfMsgExt( 'lqt_summary_label', 'parseinline' ); |
| 946 | + $edit_text = wfMsgExt( 'edit', 'parseinline' ); |
| 947 | + $link_text = wfMsg( 'lqt_permalink', 'parseinline' ); |
| 948 | + |
| 949 | + $html = ''; |
| 950 | + |
| 951 | + $html .= Xml::tags( 'span', |
| 952 | + array( 'class' => 'lqt_thread_permalink_summary_title' ), |
| 953 | + $label ); |
| 954 | + |
| 955 | + $link = $sk->link( $t->summary()->getTitle(), $link_text ); |
| 956 | + $edit_link = $this->permalink( $t, $edit_text, 'summarize' ); |
| 957 | + $links = "[$link]\n[$edit_link]"; |
| 958 | + $html .= Xml::tags( 'span', array( 'class' => 'lqt_thread_permalink_summary_edit' ), |
| 959 | + $links ); |
| 960 | + |
| 961 | + $summary_body = $this->showPostBody( $t->summary() ); |
| 962 | + $html .= Xml::tags( 'div', array( 'class' => 'lqt_thread_permalink_summary_body' ), |
| 963 | + $summary_body ); |
| 964 | + |
| 965 | + $html = Xml::tags( 'div', array( 'class' => 'lqt_thread_permalink_summary' ), $html ); |
| 966 | + |
| 967 | + return $html; |
894 | 968 | } |
| 969 | + |
| 970 | + function showSummary( $t ) { |
| 971 | + $this->output->addHTML( $this->getSummary( $t ) ); |
| 972 | + } |
895 | 973 | |
896 | 974 | } |
Index: trunk/extensions/LiquidThreads/classes/LqtNewMessages.php |
— | — | @@ -47,15 +47,12 @@ |
48 | 48 | |
49 | 49 | $dbw =& wfGetDB( DB_MASTER ); |
50 | 50 | |
51 | | - $talkpage_t = $t->article()->getTitle()->getSubjectPage(); |
| 51 | + $tpTitle = $t->article()->getTitle(); |
52 | 52 | $root_t = $t->root()->getTitle(); |
53 | 53 | |
54 | | - $q_talkpage_t = $dbw->addQuotes( $talkpage_t->getDBkey() ); |
55 | | - $q_root_t = $dbw->addQuotes( $root_t->getDBkey() ); |
56 | | - |
57 | 54 | // Select any applicable watchlist entries for the thread. |
58 | | - $talkpageWhere = array( 'wl_namespace' => $talkpage_t->getNamespace(), |
59 | | - 'wl_title' => $talkpage_t->getDBkey() ); |
| 55 | + $talkpageWhere = array( 'wl_namespace' => $tpTitle->getNamespace(), |
| 56 | + 'wl_title' => $tpTitle->getDBkey() ); |
60 | 57 | $rootWhere = array( 'wl_namespace' => $root_t->getNamespace(), |
61 | 58 | 'wl_title' => $root_t->getDBkey() ); |
62 | 59 | |
— | — | @@ -64,9 +61,6 @@ |
65 | 62 | |
66 | 63 | $where_clause = $dbw->makeList( array( $talkpageWhere, $rootWhere ), LIST_OR ); |
67 | 64 | |
68 | | - // it sucks to not have 'on duplicate key update'. first update users who already have a ums for this thread |
69 | | - // and who have already read it, by setting their state to unread. |
70 | | - |
71 | 65 | // Pull users to update the message state for, including whether or not a |
72 | 66 | // user_message_state row exists for them, and whether or not to send an email |
73 | 67 | // notification. |
— | — | @@ -126,7 +120,6 @@ |
127 | 121 | $notify_users[] = $user->getId(); |
128 | 122 | } |
129 | 123 | } |
130 | | - |
131 | 124 | } |
132 | 125 | |
133 | 126 | // Do the actual updates |
— | — | @@ -216,7 +209,7 @@ |
217 | 210 | return Threads::where( array( 'ums_read_timestamp is null', |
218 | 211 | 'ums_user' => $user->getID(), |
219 | 212 | 'ums_thread = thread.thread_id', |
220 | | - 'NOT (' . Threads::articleClause( new Article( $user->getUserPage() ) ) . ')' ), |
| 213 | + 'NOT (' . Threads::articleClause( new Article( $user->getTalkPage() ) ) . ')' ), |
221 | 214 | array(), array( 'user_message_state' ) ); |
222 | 215 | } |
223 | 216 | } |
Index: trunk/extensions/LiquidThreads/classes/LqtThread.php |
— | — | @@ -47,9 +47,6 @@ |
48 | 48 | protected $double; |
49 | 49 | |
50 | 50 | protected $replies; |
51 | | - |
52 | | - /** static cache of per-page archivestartdays setting */ |
53 | | - static $archiveStartDays; |
54 | 51 | |
55 | 52 | function isHistorical() { |
56 | 53 | return false; |
— | — | @@ -400,6 +397,7 @@ |
401 | 398 | return $this->ancestorId; |
402 | 399 | } |
403 | 400 | |
| 401 | + // The 'root' is the page in the Thread namespace corresponding to this thread. |
404 | 402 | function root() { |
405 | 403 | if ( !$this->rootId ) return null; |
406 | 404 | if ( !$this->root ) $this->root = new Post( Title::newFromID( $this->rootId ), |
— | — | @@ -457,7 +455,7 @@ |
458 | 456 | return $this->root()->getTitle(); |
459 | 457 | } |
460 | 458 | |
461 | | - private function splitIncrementFromSubject( $subject_string ) { |
| 459 | + static function splitIncrementFromSubject( $subject_string ) { |
462 | 460 | preg_match( '/^(.*) \((\d+)\)$/', $subject_string, $matches ); |
463 | 461 | if ( count( $matches ) != 3 ) |
464 | 462 | throw new MWException( __METHOD__ . ": thread subject has no increment: " . $subject_string ); |
— | — | @@ -474,15 +472,21 @@ |
475 | 473 | } |
476 | 474 | |
477 | 475 | function wikilinkWithoutIncrement() { |
478 | | - $tmp = $this->splitIncrementFromSubject( $this->wikilink() ); return $tmp[1]; |
| 476 | + $tmp = self::splitIncrementFromSubject( $this->wikilink() ); |
| 477 | + |
| 478 | + return $tmp[1]; |
479 | 479 | } |
480 | 480 | |
481 | 481 | function subjectWithoutIncrement() { |
482 | | - $tmp = $this->splitIncrementFromSubject( $this->subject() ); return $tmp[1]; |
| 482 | + $tmp = self::splitIncrementFromSubject( $this->subject() ); |
| 483 | + |
| 484 | + return $tmp[1]; |
483 | 485 | } |
484 | 486 | |
485 | 487 | function increment() { |
486 | | - $tmp = $this->splitIncrementFromSubject( $this->subject() ); return $tmp[2]; |
| 488 | + $tmp = self::splitIncrementFromSubject( $this->subject() ); |
| 489 | + |
| 490 | + return $tmp[2]; |
487 | 491 | } |
488 | 492 | |
489 | 493 | function hasDistinctSubject() { |
— | — | @@ -616,51 +620,6 @@ |
617 | 621 | } |
618 | 622 | |
619 | 623 | function getArchiveStartDays() { |
620 | | - global $wgLqtThreadArchiveStartDays; |
621 | | - |
622 | | - $article = $this->article()->getId(); |
623 | | - |
624 | | - // Instance cache |
625 | | - if ( isset( self::$archiveStartDays[$article] ) ) { |
626 | | - $cacheVal = self::$archiveStartDays[$article]; |
627 | | - if ( !is_null( $cacheVal ) ) { |
628 | | - return $cacheVal; |
629 | | - } else { |
630 | | - return $wgLqtThreadArchiveStartDays; |
631 | | - } |
632 | | - } |
633 | | - |
634 | | - // Memcached: It isn't clear that this is needed yet, but since I already wrote the |
635 | | - // code, I might as well leave it commented out instead of deleting it. |
636 | | - // Main reason I've left this commented out is because it isn't obvious how to |
637 | | - // purge the cache when necessary. |
638 | | -// global $wgMemc; |
639 | | -// $key = wfMemcKey( 'lqt-archive-start-days', $article ); |
640 | | -// $cacheVal = $wgMemc->get( $key ); |
641 | | -// if ($cacheVal != false) { |
642 | | -// if ( $cacheVal != -1 ) { |
643 | | -// return $cacheVal; |
644 | | -// } else { |
645 | | -// return $wgLqtThreadArchiveStartDays; |
646 | | -// } |
647 | | -// } |
648 | | - |
649 | | - // Load from the database. |
650 | | - $dbr = wfGetDB( DB_SLAVE ); |
651 | | - |
652 | | - $dbVal = $dbr->selectField( 'page_props', 'pp_value', |
653 | | - array( 'pp_propname' => 'lqt-archivestartdays', |
654 | | - 'pp_page' => $article ), __METHOD__ ); |
655 | | - |
656 | | - if ($dbVal) { |
657 | | - self::$archiveStartDays[$article] = $dbVal; |
658 | | -# $wgMemc->set( $key, $dbVal, 1800 ); |
659 | | - return $dbVal; |
660 | | - } else { |
661 | | - // Negative caching. |
662 | | - self::$archiveStartDays[$article] = null; |
663 | | -# $wgMemc->set( $key, -1, 86400 ); |
664 | | - return $wgLqtThreadArchiveStartDays; |
665 | | - } |
| 624 | + return Threads::getArticleArchiveStartDays( $this->article() ); |
666 | 625 | } |
667 | 626 | } |
Index: trunk/extensions/LiquidThreads/pages/NewUserMessagesView.php |
— | — | @@ -10,76 +10,53 @@ |
11 | 11 | |
12 | 12 | protected function htmlForReadButton( $label, $title, $class, $ids ) { |
13 | 13 | $ids_s = implode( ',', $ids ); |
14 | | - return <<<HTML |
15 | | - <form method="POST" class="{$class}"> |
16 | | - <input type="hidden" name="lqt_method" value="mark_as_read" /> |
17 | | - <input type="hidden" name="lqt_operand" value="{$ids_s}" /> |
18 | | - <input type="submit" value="{$label}" name="lqt_read_button" title="{$title}" /> |
19 | | - </form> |
20 | | -HTML; |
| 14 | + $html = ''; |
| 15 | + $html .= Xml::hidden( 'lqt_method', 'mark_as_read' ); |
| 16 | + $html .= Xml::hidden( 'lqt_operand', $ids_s ); |
| 17 | + $html .= Xml::submitButton( $label, array( 'name' => 'lqt_read_button', |
| 18 | + 'title' => $title ) ); |
| 19 | + $html = Xml::tags( 'form', array( 'method' => 'post', 'class' => $class ), $html ); |
| 20 | + |
| 21 | + return $html; |
21 | 22 | } |
22 | 23 | |
23 | | - function showReadAllButton( $threads ) { |
| 24 | + function getReadAllButton( $threads ) { |
24 | 25 | wfLoadExtensionMessages( 'LiquidThreads' ); |
25 | | - $ids = array_map( create_function( '$t', 'return $t->id();' ), $threads ); |
26 | | - $this->output->addHTML( |
27 | | - $this->htmlForReadButton( |
28 | | - wfMsg( 'lqt-read-all' ), |
29 | | - wfMsg( 'lqt-read-all-tooltip' ), |
30 | | - "lqt_newmessages_read_all_button", |
31 | | - $ids ) |
32 | | - ); |
| 26 | + $ids = array_map( create_function( '$t', 'return $t->id();' ), $threads ); // ew |
| 27 | + return $this->htmlForReadButton( |
| 28 | + wfMsg( 'lqt-read-all' ), |
| 29 | + wfMsg( 'lqt-read-all-tooltip' ), |
| 30 | + "lqt_newmessages_read_all_button", |
| 31 | + $ids |
| 32 | + ); |
33 | 33 | } |
34 | 34 | |
35 | | - function preShowThread( $t ) { |
| 35 | + function getUndoButton( $ids ) { |
36 | 36 | wfLoadExtensionMessages( 'LiquidThreads' ); |
37 | | - // $t_ids = implode(',', array_map(create_function('$t', 'return $t->id();'), $this->targets[$t->id()])); |
38 | | - $read_button = $this->htmlForReadButton( |
39 | | - wfMsg( 'lqt-read-message' ), |
40 | | - wfMsg( 'lqt-read-message-tooltip' ), |
41 | | - 'lqt_newmessages_read_button', |
42 | | - $this->targets[$t->id()] ); |
43 | | - $this->output->addHTML( <<<HTML |
44 | | -<table ><tr> |
45 | | -<td style="padding-right: 1em; vertical-align: top; padding-top: 1em;" > |
46 | | -$read_button |
47 | | -</td> |
48 | | -<td> |
49 | | -HTML |
50 | | - ); |
51 | | - } |
52 | | - |
53 | | - function postShowThread( $t ) { |
54 | | - $this->output->addHTML( <<<HTML |
55 | | -</td> |
56 | | -</tr></table> |
57 | | -HTML |
58 | | - ); |
59 | | - } |
60 | | - |
61 | | - function showUndo( $ids ) { |
62 | | - wfLoadExtensionMessages( 'LiquidThreads' ); |
| 37 | + |
63 | 38 | if ( count( $ids ) == 1 ) { |
64 | 39 | $t = Threads::withId( $ids[0] ); |
65 | 40 | if ( !$t ) |
66 | 41 | return; // empty or just bogus operand. |
67 | | - $msg = wfMsg( 'lqt-marked-read', $t->subject() ); |
| 42 | + $msg = wfMsgExt( 'lqt-marked-read', 'parseinline', array($t->subject()) ); |
68 | 43 | } else { |
69 | 44 | $count = count( $ids ); |
70 | | - $msg = wfMsg( 'lqt-count-marked-read', $count ); |
| 45 | + $msg = wfMsgExt( 'lqt-count-marked-read', 'parseinline', array($count) ); |
71 | 46 | } |
72 | 47 | $operand = implode( ',', $ids ); |
73 | | - $lqt_email_undo = wfMsg ( 'lqt-email-undo' ); |
74 | | - $lqt_info_undo = wfMsg ( 'lqt-email-info-undo' ); |
75 | | - $this->output->addHTML( <<<HTML |
76 | | -<form method="POST" class="lqt_undo_mark_as_read"> |
77 | | -$msg |
78 | | -<input type="hidden" name="lqt_method" value="mark_as_unread" /> |
79 | | -<input type="hidden" name="lqt_operand" value="{$operand}" /> |
80 | | -<input type="submit" value="{$lqt_email_undo}" name="lqt_read_button" title="{$lqt_info_undo}" /> |
81 | | -</form> |
82 | | -HTML |
83 | | - ); |
| 48 | + |
| 49 | + $html = ''; |
| 50 | + $html .= $msg; |
| 51 | + $html .= Xml::hidden( 'lqt_method', 'mark_as_unread' ); |
| 52 | + $html .= Xml::hidden( 'lqt_operand', $operand ); |
| 53 | + $html .= Xml::submitButton( wfMsg('lqt-email-undo'), array( 'name' => 'lqt_read_button', |
| 54 | + 'title' => wfMsg( 'lqt-email-info-undo' ) ) ); |
| 55 | + |
| 56 | + $html = Xml::tags( 'form', |
| 57 | + array( 'method' => 'post', 'class' => 'lqt_undo_mark_as_read' ), |
| 58 | + $html ); |
| 59 | + |
| 60 | + return $html; |
84 | 61 | } |
85 | 62 | |
86 | 63 | function postDivClass( $thread ) { |
— | — | @@ -102,16 +79,15 @@ |
103 | 80 | |
104 | 81 | if ( $this->request->wasPosted() && $this->methodApplies( 'mark_as_unread' ) ) { |
105 | 82 | $ids = explode( ',', $this->request->getVal( 'lqt_operand', '' ) ); |
| 83 | + |
106 | 84 | if ( $ids !== false ) { |
107 | 85 | foreach ( $ids as $id ) { |
108 | 86 | $tmp_thread = Threads::withId( $id ); if ( $tmp_thread ) |
109 | | - NewMessages::markThreadAsReadByUser( $tmp_thread, $this->user ); |
| 87 | + NewMessages::markThreadAsUnReadByUser( $tmp_thread, $this->user ); |
110 | 88 | } |
111 | 89 | $this->output->redirect( $this->title->getFullURL() ); |
112 | 90 | } |
113 | | - } |
114 | | - |
115 | | - else if ( $this->request->wasPosted() && $this->methodApplies( 'mark_as_read' ) ) { |
| 91 | + } elseif ( $this->request->wasPosted() && $this->methodApplies( 'mark_as_read' ) ) { |
116 | 92 | $ids = explode( ',', $this->request->getVal( 'lqt_operand' ) ); |
117 | 93 | if ( $ids !== false ) { |
118 | 94 | foreach ( $ids as $id ) { |
— | — | @@ -122,11 +98,9 @@ |
123 | 99 | $query = 'lqt_method=undo_mark_as_read&lqt_operand=' . implode( ',', $ids ); |
124 | 100 | $this->output->redirect( $this->title->getFullURL( $query ) ); |
125 | 101 | } |
126 | | - } |
127 | | - |
128 | | - else if ( $this->methodApplies( 'undo_mark_as_read' ) ) { |
| 102 | + } elseif ( $this->methodApplies( 'undo_mark_as_read' ) ) { |
129 | 103 | $ids = explode( ',', $this->request->getVal( 'lqt_operand', '' ) ); |
130 | | - $this->showUndo( $ids ); |
| 104 | + $this->output->addHTML( $this->getUndoButton( $ids ) ); |
131 | 105 | } |
132 | 106 | } |
133 | 107 | |
— | — | @@ -159,13 +133,36 @@ |
160 | 134 | // each thread is going to have a different article... this is pretty ugly. |
161 | 135 | $this->article = $t->article(); |
162 | 136 | |
163 | | - $this->preShowThread( $t ); |
164 | | - $this->showThread( $t ); |
165 | | - $this->postShowThread( $t ); |
| 137 | + $this->showWrappedThread( $t ); |
166 | 138 | } |
167 | 139 | return false; |
168 | 140 | } |
| 141 | + |
| 142 | + function showWrappedThread( $t ) { |
| 143 | + wfLoadExtensionMessages( 'LiquidThreads' ); |
| 144 | + |
| 145 | + $read_button = $this->htmlForReadButton( |
| 146 | + wfMsg( 'lqt-read-message' ), |
| 147 | + wfMsg( 'lqt-read-message-tooltip' ), |
| 148 | + 'lqt_newmessages_read_button', |
| 149 | + $this->targets[$t->id()] ); |
| 150 | + |
| 151 | + // Left-hand column � read button and context link to the full thread. |
| 152 | + $topmostThread = $t->topmostThread(); |
| 153 | + $contextLink = $this->permalink( $topmostThread, |
| 154 | + wfMsgExt( 'lqt-newmessages-context', 'parseinline' ) ); |
| 155 | + $leftColumn = Xml::tags( 'p', null, $read_button ) . |
| 156 | + Xml::tags( 'p', null, $contextLink ); |
| 157 | + $leftColumn = Xml::tags( 'td', array( 'class' => 'mw-lqt-newmessages-left' ), |
| 158 | + $leftColumn ); |
| 159 | + $html = "<table><tr>$leftColumn<td>"; |
| 160 | + $this->output->addHTML( $html ); |
169 | 161 | |
| 162 | + $this->showThread( $t ); |
| 163 | + |
| 164 | + $this->output->addHTML( "</td></tr></table>" ); |
| 165 | + } |
| 166 | + |
170 | 167 | function setThreads( $threads ) { |
171 | 168 | $this->threads = $threads; |
172 | 169 | } |
Index: trunk/extensions/LiquidThreads/pages/TalkpageHeaderView.php |
— | — | @@ -26,15 +26,28 @@ |
27 | 27 | |
28 | 28 | if ( $wgRequest->getVal( 'action' ) === 'edit' ) { |
29 | 29 | wfLoadExtensionMessages( 'LiquidThreads' ); |
30 | | - $warn_bold = '<strong>' . wfMsg( 'lqt_header_warning_bold' ) . '</strong>'; |
31 | | - $warn_link = '<a href="' . $this->talkpageUrl( $wgTitle, 'talkpage_new_thread' ) . '">' . |
32 | | - wfMsg( 'lqt_header_warning_new_discussion' ) . '</a>'; |
33 | | - $wgOut->addHTML( '<p class="lqt_header_warning">' . |
34 | | - wfMsg( 'lqt_header_warning_before_big', $warn_bold, $warn_link ) . |
35 | | - '<big>' . wfMsg( 'lqt_header_warning_big', $warn_bold, $warn_link ) . '</big>' . |
36 | | - wfMsg( 'word-separator' ) . |
37 | | - wfMsg( 'lqt_header_warning_after_big', $warn_bold, $warn_link ) . |
38 | | - '</p>' ); |
| 30 | + |
| 31 | + $html = ''; |
| 32 | + |
| 33 | + $warn_bold = Xml::tags( 'strong', null, |
| 34 | + wfMsgExt( 'lqt_header_warning_bold', 'parseinline' ) ); |
| 35 | + |
| 36 | + $warn_link = |
| 37 | + $this->talkpageLink( $wgTitle, wfMsgExt( 'lqt_header_warning_new_discussion', |
| 38 | + 'parseinline' ), 'talkpage_new_thread' ); |
| 39 | + |
| 40 | + $html .= wfMsgExt( 'lqt_header_warning_before_big', 'parseinline', |
| 41 | + array( $warn_bold, $warn_link ) ); |
| 42 | + $html .= Xml::tags( 'big', null, |
| 43 | + wfMsgExt( 'lqt_header_warning_big', 'parseinline', |
| 44 | + array( $warn_bold, $warn_link ) ) ); |
| 45 | + $html .= wfMsg( 'word-separator' ); |
| 46 | + $html .= wfMsgExt( 'lqt_header_warning_after_big', 'parseinline', |
| 47 | + array( $warn_bold, $warn_link ) ); |
| 48 | + |
| 49 | + $html = Xml::tags( 'p', array( 'class' => 'lqt_header_warning' ), $html ); |
| 50 | + |
| 51 | + $wgOut->addHTML( $html ); |
39 | 52 | } |
40 | 53 | |
41 | 54 | return true; |
Index: trunk/extensions/LiquidThreads/pages/IndividualThreadHistoryView.php |
— | — | @@ -15,9 +15,13 @@ |
16 | 16 | and of an old revision from getSubtitle() below. */ |
17 | 17 | function customizeSubtitle() { |
18 | 18 | wfLoadExtensionMessages( 'LiquidThreads' ); |
19 | | - $msg = wfMsg( 'lqt_hist_view_whole_thread' ); |
20 | | - $threadhist = "<a href=\"{$this->permalinkUrl($this->thread->topmostThread(), 'thread_history')}\">$msg</a>"; |
21 | | - $this->output->setSubtitle( parent::getSubtitle() . '<br />' . $this->output->getSubtitle() . "<br />$threadhist" ); |
| 19 | + $msg = wfMsgExt( 'lqt_hist_view_whole_thread', 'parseinline' ); |
| 20 | + $threadhist = $this->permalink( $this->thread->topmostThread(), |
| 21 | + $msg, |
| 22 | + 'thread_history' ); |
| 23 | + $this->output->setSubtitle( parent::getSubtitle() . '<br />' . |
| 24 | + $this->output->getSubtitle() . |
| 25 | + "<br />$threadhist" ); |
22 | 26 | return true; |
23 | 27 | } |
24 | 28 | |
Index: trunk/extensions/LiquidThreads/pages/ThreadHistoryListingView.php |
— | — | @@ -3,105 +3,138 @@ |
4 | 4 | if ( !defined( 'MEDIAWIKI' ) ) die; |
5 | 5 | |
6 | 6 | class ThreadHistoryListingView extends ThreadPermalinkView { |
| 7 | + function show() { |
| 8 | + global $wgHooks; |
| 9 | + $wgHooks['SkinTemplateTabs'][] = array( $this, 'customizeTabs' ); |
7 | 10 | |
8 | | - private function rowForThread( $t ) { |
| 11 | + if ( ! $this->thread ) { |
| 12 | + $this->showMissingThreadPage(); |
| 13 | + return false; |
| 14 | + } |
| 15 | + self::addJSandCSS(); |
| 16 | + wfLoadExtensionMessages( 'LiquidThreads' ); |
| 17 | + |
| 18 | + $this->output->setSubtitle( $this->getSubtitle() . '<br />' . wfMsg( 'lqt_hist_listing_subtitle' ) ); |
| 19 | + |
| 20 | + $this->showThreadHeading( $this->thread ); |
| 21 | + |
| 22 | + $pager = new ThreadHistoryPager( $this, $this->thread ); |
| 23 | + |
| 24 | + $html = $pager->getNavigationBar() . |
| 25 | + $pager->getBody() . |
| 26 | + $pager->getNavigationBar(); |
| 27 | + |
| 28 | + $this->output->addHTML( $html ); |
| 29 | + |
| 30 | + $this->showThread( $this->thread ); |
| 31 | + |
| 32 | + return false; |
| 33 | + } |
| 34 | + |
| 35 | + function rowForThread( $t ) { |
9 | 36 | global $wgLang, $wgOut; // TODO global. |
10 | 37 | wfLoadExtensionMessages( 'LiquidThreads' ); |
11 | 38 | /* TODO: best not to refer to LqtView class directly. */ |
12 | 39 | /* We don't use oldid because that has side-effects. */ |
13 | | - $result = array(); |
14 | | - $change_names = array( Threads::CHANGE_EDITED_ROOT => wfMsg( 'lqt_hist_comment_edited' ), |
15 | | - Threads::CHANGE_EDITED_SUMMARY => wfMsg( 'lqt_hist_summary_changed' ), |
16 | | - Threads::CHANGE_REPLY_CREATED => wfMsg( 'lqt_hist_reply_created' ), |
17 | | - Threads::CHANGE_NEW_THREAD => wfMsg( 'lqt_hist_thread_created' ), |
18 | | - Threads::CHANGE_DELETED => wfMsg( 'lqt_hist_deleted' ), |
19 | | - Threads::CHANGE_UNDELETED => wfMsg( 'lqt_hist_undeleted' ), |
20 | | - Threads::CHANGE_MOVED_TALKPAGE => wfMsg( 'lqt_hist_moved_talkpage' ) ); |
21 | | - $change_label = array_key_exists( $t->changeType(), $change_names ) ? $change_names[$t->changeType()] : ""; |
| 40 | + |
| 41 | + $sk = $this->user->getSkin(); |
22 | 42 | |
23 | | - $url = LqtView::permalinkUrlWithQuery( $this->thread, 'lqt_oldid=' . $t->revisionNumber() ); |
| 43 | + $change_names = |
| 44 | + array( |
| 45 | + Threads::CHANGE_EDITED_ROOT => wfMsg( 'lqt_hist_comment_edited' ), |
| 46 | + Threads::CHANGE_EDITED_SUMMARY => wfMsg( 'lqt_hist_summary_changed' ), |
| 47 | + Threads::CHANGE_REPLY_CREATED => wfMsg( 'lqt_hist_reply_created' ), |
| 48 | + Threads::CHANGE_NEW_THREAD => wfMsg( 'lqt_hist_thread_created' ), |
| 49 | + Threads::CHANGE_DELETED => wfMsg( 'lqt_hist_deleted' ), |
| 50 | + Threads::CHANGE_UNDELETED => wfMsg( 'lqt_hist_undeleted' ), |
| 51 | + Threads::CHANGE_MOVED_TALKPAGE => wfMsg( 'lqt_hist_moved_talkpage' ), |
| 52 | + ); |
| 53 | + |
| 54 | + $change_label = ''; |
| 55 | + |
| 56 | + if( array_key_exists( $t->changeType(), $change_names ) ) { |
| 57 | + $change_label = $change_names[$t->changeType()]; |
| 58 | + } |
24 | 59 | |
25 | | - $user_id = $t->changeUser()->getID(); # ever heard of a User object? |
| 60 | + $user_id = $t->changeUser()->getID(); |
26 | 61 | $user_text = $t->changeUser()->getName(); |
27 | | - $sig = $this->user->getSkin()->userLink( $user_id, $user_text ) . |
28 | | - $this->user->getSkin()->userToolLinks( $user_id, $user_text ); |
| 62 | + $userLinks = $sk->userLink( $user_id, $user_text ) . |
| 63 | + $sk->userToolLinks( $user_id, $user_text ); |
29 | 64 | |
30 | 65 | $change_comment = $t->changeComment(); |
31 | | - if ( !empty( $change_comment ) ) |
32 | | - $change_comment = "<em>($change_comment)</em>"; |
33 | | - |
34 | | - $result[] = "<tr>"; |
35 | | - $result[] = "<td><a href=\"$url\">" . $wgLang->timeanddate( $t->modified() ) . "</a></td>"; |
36 | | - $result[] = "<td>" . $sig . "</td>"; |
37 | | - $result[] = "<td>$change_label</td>"; |
38 | | - $result[] = "<td>$change_comment</td>"; |
39 | | - $result[] = "</tr>"; |
40 | | - return implode( '', $result ); |
41 | | - } |
42 | | - |
43 | | - function showHistoryListing( $t ) { |
44 | | - wfLoadExtensionMessages( 'LiquidThreads' ); |
45 | | - $revisions = new ThreadHistoryIterator( $t, $this->perPage, $this->perPage * ( $this->page - 1 ) ); |
46 | | - |
47 | | - $this->output->addHTML( '<table>' ); |
48 | | - foreach ( $revisions as $ht ) { |
49 | | - $this->output->addHTML( $this->rowForThread( $ht ) ); |
| 66 | + if ( $change_comment != '' ) { |
| 67 | + $change_comment = $sk->commentBlock( $change_comment ); |
50 | 68 | } |
51 | | - $this->output->addHTML( '</table>' ); |
52 | 69 | |
53 | | - if ( count( $revisions ) == 0 && $this->page == 1 ) { |
54 | | - $this->output->addHTML( '<p>' . wfMsg( 'lqt_hist_no_revisions_error' ) ); |
55 | | - } |
56 | | - else if ( count( $revisions ) == 0 ) { |
57 | | - // we could redirect to the previous page... yow. |
58 | | - $this->output->addHTML( '<p>' . wfMsg( 'lqt_hist_past_last_page_error' ) ); |
59 | | - } |
| 70 | + $html = ''; |
| 71 | + |
| 72 | + $linkText = $wgLang->timeanddate( $t->modified(), true ); |
| 73 | + $link = $this->permalink( $this->thread, $linkText, null, null, null, array(), |
| 74 | + array( 'lqt_oldid' => $t->revisionNumber() ) ); |
| 75 | + |
| 76 | + $html .= Xml::tags( 'td', null, $link ); |
| 77 | + $html .= Xml::tags( 'td', null, $userLinks ); |
| 78 | + $html .= Xml::tags( 'td', null, $change_label ); |
| 79 | + $html .= Xml::tags( 'td', null, $change_comment ); |
60 | 80 | |
61 | | - if ( $this->page > 1 ) { |
62 | | - $this->output->addHTML( '<a class="lqt_newer_older" href="' . $this->queryReplace( array( 'lqt_hist_page' => $this->page - 1 ) ) . '">' . wfMsg( 'lqt_newer' ) . '</a>' ); |
63 | | - } else { |
64 | | - $this->output->addHTML( '<span class="lqt_newer_older_disabled" title="' . wfMsg( 'lqt_hist_tooltip_newer_disabled' ) . '">' . wfMsg( 'lqt_newer' ) . '</span>' ); |
65 | | - } |
66 | | - |
67 | | - $is_last_page = false; |
68 | | - foreach ( $revisions as $r ) |
69 | | - if ( $r->changeType() == Threads::CHANGE_NEW_THREAD ) |
70 | | - $is_last_page = true; |
71 | | - if ( $is_last_page ) { |
72 | | - $this->output->addHTML( '<span class="lqt_newer_older_disabled" title="' . wfMsg( 'lqt_hist_tooltip_older_disabled' ) . '">' . wfMsg( 'lqt_older' ) . '</span>' ); |
73 | | - } else { |
74 | | - $this->output->addHTML( '<a class="lqt_newer_older" href="' . $this->queryReplace( array( 'lqt_hist_page' => $this->page + 1 ) ) . '">' . wfMsg( 'lqt_older' ) . '</a>' ); |
75 | | - } |
| 81 | + $html = Xml::tags( 'tr', null, $html ); |
| 82 | + |
| 83 | + return $html; |
76 | 84 | } |
| 85 | +} |
77 | 86 | |
78 | | - function __construct( &$output, &$article, &$title, &$user, &$request ) { |
79 | | - parent::__construct( $output, $article, $title, $user, $request ); |
80 | | - $this->loadParametersFromRequest(); |
| 87 | +class ThreadHistoryPager extends ReverseChronologicalPager { |
| 88 | + function __construct( $view, $thread ) { |
| 89 | + parent::__construct(); |
| 90 | + |
| 91 | + $this->thread = $thread; |
| 92 | + $this->view = $view; |
81 | 93 | } |
82 | | - |
83 | | - function loadParametersFromRequest() { |
84 | | - $this->perPage = $this->request->getInt( 'lqt_hist_per_page', 10 ); |
85 | | - $this->page = $this->request->getInt( 'lqt_hist_page', 1 ); |
| 94 | + |
| 95 | + function getQueryInfo() { |
| 96 | + $queryInfo = |
| 97 | + array( |
| 98 | + 'tables' => array( 'historical_thread' ), |
| 99 | + 'fields' => array( 'hthread_contents', 'hthread_revision' ), |
| 100 | + 'conds' => array( 'hthread_id' => $this->thread->id() ), |
| 101 | + 'options' => array( 'order by' => 'hthread_revision desc' ), |
| 102 | + ); |
| 103 | + |
| 104 | + return $queryInfo; |
86 | 105 | } |
| 106 | + |
| 107 | + function formatRow( $row ) { |
| 108 | + $hthread = HistoricalThread::fromTextRepresentation( $row->hthread_contents ); |
| 109 | + return $this->view->rowForThread( $hthread ); |
| 110 | + } |
| 111 | + |
| 112 | + function getStartBody() { |
| 113 | + $headers = array( |
| 114 | + 'lqt-history-time', |
| 115 | + 'lqt-history-user', |
| 116 | + 'lqt-history-action', |
| 117 | + ); |
87 | 118 | |
88 | | - function show() { |
89 | | - global $wgHooks; |
90 | | - $wgHooks['SkinTemplateTabs'][] = array( $this, 'customizeTabs' ); |
91 | | - |
92 | | - if ( ! $this->thread ) { |
93 | | - $this->showMissingThreadPage(); |
94 | | - return false; |
| 119 | + $html = ''; |
| 120 | + |
| 121 | + foreach( $headers as $header ) { |
| 122 | + $html .= Xml::tags( 'th', null, |
| 123 | + wfMsgExt( $header, 'parseinline' ) ); |
95 | 124 | } |
96 | | - self::addJSandCSS(); |
97 | | - wfLoadExtensionMessages( 'LiquidThreads' ); |
98 | | - |
99 | | - $this->output->setSubtitle( $this->getSubtitle() . '<br />' . wfMsg( 'lqt_hist_listing_subtitle' ) ); |
100 | | - |
101 | | - $this->showThreadHeading( $this->thread ); |
102 | | - $this->showHistoryListing( $this->thread ); |
103 | | - |
104 | | - $this->showThread( $this->thread ); |
105 | | - |
106 | | - return false; |
| 125 | + |
| 126 | + $html = Xml::tags( 'tr', null, $html ); |
| 127 | + $html = Xml::tags( 'thead', null, $html ); |
| 128 | + $html = "<table>$html<tbody>"; |
| 129 | + |
| 130 | + return $html; |
107 | 131 | } |
| 132 | + |
| 133 | + function getEndBody() { |
| 134 | + return "</tbody></table>"; |
| 135 | + } |
| 136 | + |
| 137 | + function getIndexField() { |
| 138 | + return 'hthread_revision'; |
| 139 | + } |
108 | 140 | } |
| 141 | + |
Index: trunk/extensions/LiquidThreads/pages/SpecialNewMessages.php |
— | — | @@ -6,7 +6,7 @@ |
7 | 7 | private $user, $output, $request, $title; |
8 | 8 | |
9 | 9 | function __construct() { |
10 | | - SpecialPage::SpecialPage( 'Newmessages' ); |
| 10 | + SpecialPage::SpecialPage( 'NewMessages' ); |
11 | 11 | $this->includable( true ); |
12 | 12 | } |
13 | 13 | |
— | — | @@ -42,15 +42,21 @@ |
43 | 43 | $wgOut->addWikitext( wfMsg( 'lqt-no-new-messages' ) ); |
44 | 44 | return; |
45 | 45 | } |
46 | | - $view->showReadAllButton( $both_sets ); // ugly hack. |
| 46 | + |
| 47 | + $html = ''; |
| 48 | + |
| 49 | + $html .= $view->getReadAllButton( $both_sets ); // ugly hack. |
47 | 50 | |
48 | 51 | $view->setHeaderLevel( 3 ); |
49 | 52 | |
50 | | - $this->output->addHTML( '<h2 class="lqt_newmessages_section">' . wfMsg ( 'lqt-messages-sent' ) . '</h2>' ); |
| 53 | + $html .= Xml::tags( 'h2', array( 'class' => 'lqt_newmessages_section' ), |
| 54 | + wfMsgExt( 'lqt-messages-sent', 'parseinline' ) ); |
| 55 | + $wgOut->addHTML( $html ); |
51 | 56 | $view->setThreads( $first_set ); |
52 | 57 | $view->show(); |
53 | 58 | |
54 | | - $this->output->addHTML( '<h2 class="lqt_newmessages_section">' . wfMsg ( 'lqt-other-messages' ) . '</h2>' ); |
| 59 | + $wgOut->addHTML( Xml::tags( 'h2', array( 'class' => 'lqt_newmessages_section' ), |
| 60 | + wfMsgExt( 'lqt-other-messages', 'parseinline' ) ) ); |
55 | 61 | $view->setThreads( $second_set ); |
56 | 62 | $view->show(); |
57 | 63 | } |
Index: trunk/extensions/LiquidThreads/pages/TalkpageView.php |
— | — | @@ -35,53 +35,64 @@ |
36 | 36 | |
37 | 37 | function showHeader() { |
38 | 38 | /* Show the contents of the actual talkpage article if it exists. */ |
| 39 | + |
| 40 | + global $wgUser; |
| 41 | + $sk = $wgUser->getSkin(); |
39 | 42 | |
40 | 43 | $article = new Article( $this->title ); |
41 | 44 | $revision = Revision::newFromId( $article->getLatest() ); |
42 | 45 | if ( $revision ) $article_text = $revision->getRawText(); |
43 | 46 | |
44 | 47 | $oldid = $this->request->getVal( 'oldid', null ); |
45 | | - $editlink = $this->title->getFullURL( 'action=edit' ); |
46 | 48 | |
47 | 49 | wfLoadExtensionMessages( 'LiquidThreads' ); |
48 | 50 | // If $article_text == "", the talkpage was probably just created |
49 | 51 | // when the first thread was posted to make the links blue. |
50 | 52 | if ( $article->exists() && $article_text != "" ) { |
51 | | - $historylink = $this->title->getFullURL( 'action=history' ); |
52 | | - $this->openDiv( 'lqt_header_content' ); |
53 | | - $this->showPostBody( $article, $oldid ); |
54 | | - $this->outputList( 'ul', 'lqt_header_commands', null, array( |
55 | | - "[<a href=\"$editlink\">" . wfMsg( 'edit' ) . "↑</a>]", |
56 | | - "[<a href=\"$historylink\">" . wfMsg( 'history_short' ) . "↑</a>]" |
57 | | - ) ); |
58 | | - $this->closeDiv(); |
| 53 | + $html = ''; |
| 54 | + |
| 55 | + $html .= $this->showPostBody( $article, $oldid ); |
| 56 | + |
| 57 | + $actionLinks = array(); |
| 58 | + $actionLinks[] = $sk->link( $this->title, |
| 59 | + wfMsgExt( 'edit', 'parseinline' ) . "↑", |
| 60 | + array(), array( 'action' => 'edit' ) ); |
| 61 | + $actionLinks[] = $sk->link( $this->title, |
| 62 | + wfMsgExt( 'history_short', 'parseinline' ) . "↑", |
| 63 | + array(), array( 'action' => 'history' ) ); |
| 64 | + |
| 65 | + $actions = ''; |
| 66 | + foreach( $actionLinks as $link ) { |
| 67 | + $actions .= Xml::tags( 'li', null, "[$link]" ) . "\n"; |
| 68 | + } |
| 69 | + $actions = Xml::tags( 'ul', array( 'class' => 'lqt_header_commands' ), $actions ); |
| 70 | + $html .= $actions; |
| 71 | + |
| 72 | + $html = Xml::tags( 'div', array( 'class' => 'lqt_header_content' ), $html ); |
| 73 | + |
| 74 | + $this->output->addHTML( $html ); |
59 | 75 | } else { |
60 | | - $this->output->addHTML( "<p class=\"lqt_header_notice\">[<a href=\"$editlink\">" . wfMsg( 'lqt_add_header' ) . "</a>]</p>" ); |
| 76 | + |
| 77 | + $editLink = $sk->link( $this->title, wfMsgExt( 'lqt_add_header', 'parseinline' ), |
| 78 | + array(), array( 'action' => 'edit' ) ); |
| 79 | + |
| 80 | + $html = Xml::tags( 'p', array( 'class' => 'lqt_header_notice' ), "[$editLink]" ); |
| 81 | + |
| 82 | + $this->output->addHTML( $html ); |
61 | 83 | } |
62 | 84 | } |
63 | | - |
64 | | - function outputList( $kind, $class, $id, $contents ) { |
65 | | - $this->output->addHTML( Xml::openElement( $kind, array( 'class' => $class, 'id' => $id ) ) ); |
66 | | - foreach ( $contents as $li ) { |
67 | | - $this->output->addHTML( Xml::openElement( 'li' ) ); |
68 | | - $this->output->addHTML( $li ); |
69 | | - $this->output->addHTML( Xml::closeElement( 'li' ) ); |
70 | | - } |
71 | | - $this->output->addHTML( Xml::closeElement( $kind ) ); |
72 | | - } |
73 | 85 | |
74 | | - function showTOC( $threads ) { |
| 86 | + function getTOC( $threads ) { |
75 | 87 | global $wgLang; |
76 | 88 | |
77 | 89 | wfLoadExtensionMessages( 'LiquidThreads' ); |
78 | 90 | |
79 | 91 | $sk = $this->user->getSkin(); |
80 | 92 | |
81 | | - $title = Xml::tags( 'h2', null, wfMsgExt( 'lqt_contents_title', 'parseinline' ) ); |
82 | | - $this->output->addHTML( $title ); |
83 | | - |
84 | 93 | $html = ''; |
85 | 94 | |
| 95 | + $html .= Xml::tags( 'h2', null, wfMsgExt( 'lqt_contents_title', 'parseinline' ) ); |
| 96 | + |
86 | 97 | // Header row |
87 | 98 | $headerRow = ''; |
88 | 99 | $headers = array( 'lqt_toc_thread_title', 'lqt_toc_thread_author', |
— | — | @@ -114,33 +125,46 @@ |
115 | 126 | $rows[] = $row; |
116 | 127 | } |
117 | 128 | |
118 | | - $html = $headerRow . "\n" . Xml::tags( 'tbody', null, implode( "\n", $rows ) ); |
| 129 | + $html .= $headerRow . "\n" . Xml::tags( 'tbody', null, implode( "\n", $rows ) ); |
119 | 130 | $html = Xml::tags( 'table', array( 'class' => 'lqt_toc' ), $html ); |
120 | 131 | |
121 | | - $this->output->addHTML( $html ); |
| 132 | + return $html; |
122 | 133 | } |
| 134 | + |
| 135 | + function getList( $kind, $class, $id, $contents ) { |
| 136 | + $html = ''; |
| 137 | + foreach ( $contents as $li ) { |
| 138 | + $html .= Xml::tags( 'li', null, $li ); |
| 139 | + } |
| 140 | + $html = Xml::tags( $kind, array( 'class' => $class, 'id' => $id ), $html ); |
| 141 | + |
| 142 | + return $html; |
| 143 | + } |
123 | 144 | |
124 | | - function showArchiveWidget( $threads ) { |
| 145 | + function getArchiveWidget( $threads ) { |
125 | 146 | wfLoadExtensionMessages( 'LiquidThreads' ); |
126 | | - |
| 147 | + |
127 | 148 | $threadlinks = $this->permalinksForThreads( $threads ); |
128 | | - $url = $this->talkpageUrl( $this->title, 'talkpage_archive' ); |
129 | 149 | |
130 | 150 | if ( count( $threadlinks ) > 0 ) { |
131 | | - $this->openDiv( 'lqt_archive_teaser' ); |
132 | | - $this->output->addHTML( '<h2 class="lqt_recently_archived">' . wfMsg( 'lqt_recently_archived' ) . '</h2>' ); |
133 | | - $this->outputList( 'ul', '', '', $threadlinks ); |
134 | | - $this->closeDiv(); |
135 | | - } else { |
| 151 | + $url = $this->talkpageUrl( $this->title, 'talkpage_archive' ); |
| 152 | + |
| 153 | + $html = ''; |
| 154 | + $html = Xml::tags( 'h2', array( 'class' => 'lqt_recently_archived' ), |
| 155 | + wfMsgExt( 'lqt_recently_archived', 'parseinline' ) ); |
| 156 | + $html .= $this->getList( 'ul', '', '', $threadlinks ); |
| 157 | + $html = Xml::tags( 'div', array( 'class' => 'lqt_archive_teaser' ), $html ); |
| 158 | + return $html; |
136 | 159 | } |
| 160 | + |
| 161 | + return ''; |
137 | 162 | } |
138 | 163 | |
139 | 164 | function showTalkpageViewOptions( $article ) { |
140 | 165 | wfLoadExtensionMessages( 'LiquidThreads' ); |
141 | | - // TODO WTF who wrote this? |
142 | 166 | |
143 | 167 | if ( $this->methodApplies( 'talkpage_sort_order' ) ) { |
144 | | - $remember_sort_checked = $this->request->getBool( 'lqt_remember_sort' ) ? 'checked ' : ''; |
| 168 | + $remember_sort_checked = $this->request->getBool( 'lqt_remember_sort' ); |
145 | 169 | $this->user->setOption( 'lqt_sort_order', $this->sort_order ); |
146 | 170 | $this->user->saveSettings(); |
147 | 171 | } else { |
— | — | @@ -148,56 +172,57 @@ |
149 | 173 | } |
150 | 174 | |
151 | 175 | if ( $article->exists() ) { |
152 | | - $nc_sort = $this->sort_order == LQT_NEWEST_CHANGES ? ' selected' : ''; |
153 | | - $nt_sort = $this->sort_order == LQT_NEWEST_THREADS ? ' selected' : ''; |
154 | | - $ot_sort = $this->sort_order == LQT_OLDEST_THREADS ? ' selected' : ''; |
155 | 176 | $newest_changes = wfMsg( 'lqt_sort_newest_changes' ); |
156 | 177 | $newest_threads = wfMsg( 'lqt_sort_newest_threads' ); |
157 | 178 | $oldest_threads = wfMsg( 'lqt_sort_oldest_threads' ); |
158 | 179 | $lqt_remember_sort = wfMsg( 'lqt_remember_sort' ) ; |
159 | 180 | $form_action_url = $this->talkpageUrl( $this->title, 'talkpage_sort_order' ); |
160 | | - $lqt_sorting_order = wfMsg( 'lqt_sorting_order' ); |
161 | 181 | $lqt_sort_newest_changes = wfMsg( 'lqt_sort_newest_changes' ); |
162 | 182 | $lqt_sort_newest_threads = wfMsg( 'lqt_sort_newest_threads' ); |
163 | 183 | $lqt_sort_oldest_threads = wfMsg( 'lqt_sort_oldest_threads' ); |
164 | 184 | $go = wfMsg( 'go' ); |
| 185 | + |
| 186 | + $html = ''; |
| 187 | + |
| 188 | + $html .= Xml::label( wfMsg( 'lqt_sorting_order' ), 'lqt_sort_select' ) . ' '; |
| 189 | + |
| 190 | + $sortOrderSelect = |
| 191 | + new XmlSelect( 'lqt_order', 'lqt_sort_select', $this->sort_order ); |
| 192 | + |
| 193 | + $sortOrderSelect->setAttribute( 'class', 'lqt_sort_select' ); |
| 194 | + $sortOrderSelect->addOption( wfMsg( 'lqt_sort_newest_changes' ), |
| 195 | + LQT_NEWEST_CHANGES ); |
| 196 | + $sortOrderSelect->addOption( wfMsg( 'lqt_sort_newest_changes' ), |
| 197 | + LQT_NEWEST_THREADS ); |
| 198 | + $sortOrderSelect->addOption( wfMsg( 'lqt_sort_newest_changes' ), |
| 199 | + LQT_OLDEST_THREADS ); |
| 200 | + $html .= $sortOrderSelect->getHTML(); |
| 201 | + |
165 | 202 | if ( $this->user->isLoggedIn() ) { |
166 | | - $remember_sort = |
167 | | - <<<HTML |
168 | | -<br /> |
169 | | -<label for="lqt_remember_sort_checkbox"> |
170 | | -<input id="lqt_remember_sort_checkbox" name="lqt_remember_sort" type="checkbox" value="1" $remember_sort_checked /> |
171 | | -$lqt_remember_sort</label> |
172 | | -HTML; |
173 | | - } else { |
174 | | - $remember_sort = ''; |
| 203 | + $html .= Xml::element( 'br' ) . |
| 204 | + Xml::checkLabel( $lqt_remember_sort, 'lqt_remember_sort', |
| 205 | + 'lqt_remember_sort', $remember_sort_checked ); |
175 | 206 | } |
176 | | - if ( in_array( 'deletedhistory', $this->user->getRights() ) ) { |
177 | | - $show_deleted_checked = $this->request->getBool( 'lqt_show_deleted_threads' ) ? 'checked ' : ''; |
178 | | - $show_deleted = "<br />\n" . |
179 | | - "<label for=\"lqt_show_deleted_threads_checkbox\">\n" . |
180 | | - "<input id=\"lqt_show_deleted_threads_checkbox\" name=\"lqt_show_deleted_threads\" type=\"checkbox\" value=\"1\" $show_deleted_checked />\n" . |
181 | | - wfMsg( 'lqt_delete_show_checkbox' ) . "</label>\n"; |
182 | | - } else { |
183 | | - $show_deleted = ""; |
| 207 | + |
| 208 | + if ( $this->user->isAllowed( 'deletedhistory' ) ) { |
| 209 | + $show_deleted_checked = $this->request->getBool( 'lqt_show_deleted_threads' ); |
| 210 | + |
| 211 | + $html .= Xml::element( 'br' ) . |
| 212 | + Xml::checkLabel( wfMsg('lqt_delete_show_checkbox' ), |
| 213 | + 'lqt_show_deleted_threads', |
| 214 | + 'lqt_show_deleted_threads', |
| 215 | + $show_deleted_checked ); |
184 | 216 | } |
185 | | - $this->openDiv( 'lqt_view_options' ); |
186 | | - $this->output->addHTML( |
187 | | - |
188 | | - <<<HTML |
189 | | -<form name="lqt_sort" action="$form_action_url" method="post">$lqt_sorting_order |
190 | | -<select name="lqt_order" class="lqt_sort_select"> |
191 | | -<option value="nc"$nc_sort>$lqt_sort_newest_changes</option> |
192 | | -<option value="nt"$nt_sort>$lqt_sort_newest_threads</option> |
193 | | -<option value="ot"$ot_sort>$lqt_sort_oldest_threads</option> |
194 | | -</select> |
195 | | -$remember_sort |
196 | | -$show_deleted |
197 | | -<input name="submitsort" type="submit" value="$go" class="lqt_go_sort"/> |
198 | | -</form> |
199 | | -HTML |
200 | | - ); |
201 | | - $this->closeDiv(); |
| 217 | + |
| 218 | + $html .= Xml::submitButton( wfMsg( 'go' ), array( 'class' => 'lqt_go_sort', |
| 219 | + 'name' => 'submitsort' ) ); |
| 220 | + |
| 221 | + $html = Xml::tags( 'form', array( 'action' => $form_action_url, |
| 222 | + 'method' => 'post', |
| 223 | + 'name' => 'lqt_sort' ), $html ); |
| 224 | + $html = Xml::tags( 'div', array( 'class' => 'lqt_view_options' ), $html ); |
| 225 | + |
| 226 | + $this->output->addHTML( $html ); |
202 | 227 | } |
203 | 228 | |
204 | 229 | } |
— | — | @@ -205,23 +230,28 @@ |
206 | 231 | function show() { |
207 | 232 | global $wgHooks; |
208 | 233 | wfLoadExtensionMessages( 'LiquidThreads' ); |
209 | | - // Why is a hook added here? |
| 234 | + // FIXME Why is a hook added here? |
210 | 235 | $wgHooks['SkinTemplateTabs'][] = array( $this, 'customizeTabs' ); |
211 | 236 | |
212 | 237 | $this->output->setPageTitle( $this->title->getPrefixedText() ); |
213 | 238 | self::addJSandCSS(); |
214 | | - $article = new Article( $this->title ); // Added in r29715 sorting. Why? |
| 239 | + $article = new Article( $this->title ); |
215 | 240 | |
216 | | - // Removed in r29715 sorting. Again, why? |
217 | 241 | $this->showHeader(); |
| 242 | + |
| 243 | + $html = ''; |
218 | 244 | |
219 | | - global $wgRequest; // TODO |
| 245 | + global $wgRequest; |
220 | 246 | if ( $this->methodApplies( 'talkpage_new_thread' ) ) { |
221 | 247 | $this->showNewThreadForm(); |
222 | 248 | } else { |
223 | 249 | $this->showTalkpageViewOptions( $article ); |
224 | | - $url = $this->talkpageUrl( $this->title, 'talkpage_new_thread' ); |
225 | | - $this->output->addHTML( "<strong><a class=\"lqt_start_discussion\" href=\"$url\">" . wfMsg( 'lqt_new_thread' ) . "</a></strong>" ); |
| 250 | + $newThreadLink = $this->talkpageLink( $this->title, |
| 251 | + wfMsgExt( 'lqt_new_thread', 'parseinline' ), |
| 252 | + 'talkpage_new_thread', null, true, |
| 253 | + array( 'class' => 'lqt_start_discussion' ) ); |
| 254 | + |
| 255 | + $this->output->addHTML( Xml::tags( 'strong', null, $newThreadLink ) ); |
226 | 256 | } |
227 | 257 | |
228 | 258 | $queryType = |
— | — | @@ -229,24 +259,32 @@ |
230 | 260 | ? 'fresh' : 'fresh-undeleted'; |
231 | 261 | $threads = $this->queries->query( $queryType ); |
232 | 262 | |
233 | | - $this->openDiv( 'lqt_toc_archive_wrapper' ); |
234 | | - |
235 | | - $this->openDiv( 'lqt_archive_teaser_empty' ); |
236 | | - $this->output->addHTML( "<div class=\"lqt_browse_archive\"><a href=\"{$this->talkpageUrl($this->title, 'talkpage_archive')}\">" . |
237 | | - wfMsg( 'lqt_browse_archive_without_recent' ) . "</a></div>" ); |
238 | | - $this->closeDiv(); |
| 263 | + $archiveBrowseLink = $this->talkpageLink( $this->title, |
| 264 | + wfMsgExt( 'lqt_browse_archive_without_recent', 'parseinline' ), |
| 265 | + 'talkpage_archive' ); |
| 266 | + $archiveBrowseLink = Xml::tags( 'div', array( 'class' => 'lqt_browse_archive' ), |
| 267 | + $archiveBrowseLink ); |
| 268 | + $archiveBrowseLink = Xml::tags( 'div', array( 'class' => 'lqt_archive_teaser_empty' ), |
| 269 | + $archiveBrowseLink ); |
| 270 | + |
239 | 271 | $recently_archived_threads = $this->queries->query( 'recently-archived' ); |
240 | 272 | if ( count( $threads ) > 3 || count( $recently_archived_threads ) > 0 ) { |
241 | | - $this->showTOC( $threads ); |
| 273 | + $toc = $this->getTOC( $threads ); |
242 | 274 | } |
243 | | - $this->showArchiveWidget( $recently_archived_threads ); |
244 | | - $this->closeDiv(); |
245 | | - // Clear any floats |
246 | | - $this->output->addHTML( '<br clear="all" />' ); |
| 275 | + $archiveWidget = $this->getArchiveWidget( $recently_archived_threads ); |
247 | 276 | |
| 277 | + $html = Xml::tags( 'div', array( 'class' => 'lqt_toc_archive_wrapper' ), |
| 278 | + $archiveBrowseLink . $toc . |
| 279 | + $archiveWidget ); |
| 280 | + |
| 281 | + $html .= Xml::element( 'br', array( 'style' => 'clear: both;' ) ); |
| 282 | + |
| 283 | + $this->output->addHTML( $html ); |
| 284 | + |
248 | 285 | foreach ( $threads as $t ) { |
249 | 286 | $this->showThread( $t ); |
250 | 287 | } |
| 288 | + |
251 | 289 | return false; |
252 | 290 | } |
253 | 291 | } |
Index: trunk/extensions/LiquidThreads/pages/ThreadHistoricalRevisionView.php |
— | — | @@ -8,33 +8,45 @@ |
9 | 9 | |
10 | 10 | function postDivClass( $thread ) { |
11 | 11 | $is_changed_thread = $thread->changeObject() && |
12 | | - $thread->changeObject()->id() == $thread->id(); |
13 | | - if ( $is_changed_thread ) |
14 | | - return 'lqt_post_changed_by_history'; |
15 | | - else |
16 | | - return 'lqt_post'; |
| 12 | + ( $thread->changeObject()->id() == $thread->id() ); |
| 13 | + if ( $is_changed_thread ) { |
| 14 | + return 'lqt_post_changed_by_history'; |
| 15 | + } else { |
| 16 | + return 'lqt_post'; |
| 17 | + } |
17 | 18 | } |
18 | 19 | |
19 | 20 | function showHistoryInfo() { |
20 | | - global $wgLang; // TODO global. |
| 21 | + global $wgLang; |
21 | 22 | wfLoadExtensionMessages( 'LiquidThreads' ); |
22 | | - $this->openDiv( 'lqt_history_info' ); |
23 | | - $this->output->addHTML( wfMsg( 'lqt_revision_as_of', |
24 | | - $wgLang->timeanddate( $this->thread->modified() ), |
25 | | - $wgLang->date( $this->thread->modified() ), |
26 | | - $wgLang->time( $this->thread->modified() ) ) . '<br />' ); |
27 | 23 | |
| 24 | + $html = ''; |
| 25 | + $html .= wfMsgExt( 'lqt_revision_as_of', 'parseinline', |
| 26 | + array( |
| 27 | + $wgLang->timeanddate( $this->thread->modified() ), |
| 28 | + $wgLang->date( $this->thread->modified() ), |
| 29 | + $wgLang->time( $this->thread->modified() ) |
| 30 | + ) |
| 31 | + ); |
| 32 | + |
| 33 | + $html .= '<br/>'; |
| 34 | + |
28 | 35 | $ct = $this->thread->changeType(); |
29 | 36 | if ( $ct == Threads::CHANGE_NEW_THREAD ) { |
30 | | - $msg = wfMsg( 'lqt_change_new_thread' ); |
| 37 | + $msg = wfMsgExt( 'lqt_change_new_thread', 'parseinline' ); |
31 | 38 | } else if ( $ct == Threads::CHANGE_REPLY_CREATED ) { |
32 | | - $msg = wfMsg( 'lqt_change_reply_created' ); |
| 39 | + $msg = wfMsgExt( 'lqt_change_reply_created', 'parseinline' ); |
33 | 40 | } else if ( $ct == Threads::CHANGE_EDITED_ROOT ) { |
34 | | - $diff_url = $this->permalinkUrlWithDiff( $this->thread ); |
35 | | - $msg = wfMsg( 'lqt_change_edited_root' ) . " [<a href=\"$diff_url\">" . wfMsg( 'diff' ) . '</a>]'; |
| 41 | + $diff_link = $this->diffPermalink( $this->thread, |
| 42 | + wfMsgExt( 'diff', 'parseinline' ) ); |
| 43 | + $msg = wfMsgExt( 'lqt_change_edited_root', 'parseinline' ) . |
| 44 | + " [$diff_link]"; |
36 | 45 | } |
37 | | - $this->output->addHTML( $msg ); |
38 | | - $this->closeDiv(); |
| 46 | + $html .= $msg; |
| 47 | + |
| 48 | + $html = Xml::tags( 'div', array( 'class' => 'lqt_history_info' ), $html ); |
| 49 | + |
| 50 | + $this->output->addHTML( $html ); |
39 | 51 | } |
40 | 52 | |
41 | 53 | function show() { |
Index: trunk/extensions/LiquidThreads/pages/SummaryPageView.php |
— | — | @@ -7,11 +7,13 @@ |
8 | 8 | wfLoadExtensionMessages( 'LiquidThreads' ); |
9 | 9 | $thread = Threads::withSummary( $this->article ); |
10 | 10 | if ( $thread ) { |
11 | | - $url = $thread->root()->getTitle()->getFullURL(); |
12 | | - $name = $thread->root()->getTitle()->getPrefixedText(); |
| 11 | + global $wgUser; |
| 12 | + |
| 13 | + $t = $thread->root()->getTitle(); |
| 14 | + $link = $wgUser->getSkin->link( $t ); |
13 | 15 | $this->output->setSubtitle( |
14 | | - wfMsg( 'lqt_summary_subtitle', |
15 | | - '<a href="' . $url . '">' . $name . '</a>' ) ); |
| 16 | + wfMsgExt( 'lqt_summary_subtitle', array( 'parseinline', 'replaceafter' ), |
| 17 | + $link ) ); |
16 | 18 | } |
17 | 19 | return true; |
18 | 20 | } |
Index: trunk/extensions/LiquidThreads/pages/TalkpageArchiveView.php |
— | — | @@ -5,225 +5,130 @@ |
6 | 6 | class TalkpageArchiveView extends TalkpageView { |
7 | 7 | function __construct( &$output, &$article, &$title, &$user, &$request ) { |
8 | 8 | parent::__construct( $output, $article, $title, $user, $request ); |
9 | | - $this->loadQueryFromRequest(); |
10 | 9 | } |
11 | 10 | |
12 | | - function showThread( $t ) { |
13 | | - $this->output->addHTML( <<<HTML |
14 | | -<tr> |
15 | | -<td><a href="{$this->permalinkUrl($t)}">{$t->subjectWithoutIncrement()}</a></td> |
16 | | -<td> |
17 | | -HTML |
18 | | - ); if ( $t->hasSummary() ) { |
19 | | - $this->showPostBody( $t->summary() ); |
20 | | - } else if ( $t->type() == Threads::TYPE_MOVED ) { |
21 | | - $rthread = $t->redirectThread(); |
22 | | - if ( $rthread && $rthread->summary() ) { |
23 | | - $this->showPostBody( $rthread->summary() ); |
24 | | - } |
25 | | - } |
26 | | - $this->output->addHTML( <<<HTML |
27 | | -</td> |
28 | | -</tr> |
29 | | -HTML |
30 | | - ); |
31 | | - } |
| 11 | + function show() { |
| 12 | + global $wgHooks, $wgOut; |
| 13 | + $wgHooks['SkinTemplateTabs'][] = array( $this, 'customizeTabs' ); |
32 | 14 | |
33 | | - function loadQueryFromRequest() { |
34 | 15 | wfLoadExtensionMessages( 'LiquidThreads' ); |
35 | | - // Begin with with the requirements for being *in* the archive. |
36 | | - global $wgLqtThreadArchiveStartDays; |
37 | | - $startdate = Date::now()->nDaysAgo( $wgLqtThreadArchiveStartDays )->midnight(); |
38 | | - $where = array( Threads::articleClause( $this->article ), |
39 | | - 'thread.thread_parent is null', |
40 | | - '(thread.thread_summary_page is not null' . |
41 | | - ' OR thread.thread_type = ' . Threads::TYPE_MOVED . ')', |
42 | | - 'thread.thread_modified < ' . $startdate->text() ); |
43 | | - $options = array( 'ORDER BY thread.thread_modified DESC' ); |
| 16 | + $this->output->setPageTitle( $this->title->getPrefixedText() ); |
| 17 | + $this->output->setSubtitle( wfMsg( 'lqt-archive-subtitle' ) ); |
| 18 | + self::addJSandCSS(); |
| 19 | + |
| 20 | + $this->output->addWikiMsg( 'lqt-archive-intro', |
| 21 | + $this->article->getTitle()->getPrefixedText() ); |
44 | 22 | |
45 | | - $annotations = array( wfMsg ( 'lqt-searching' ) ); |
| 23 | + $pager = new TalkpageArchivePager( $this->article, $this ); |
| 24 | + |
| 25 | + $html = $pager->getNavigationBar() . |
| 26 | + $pager->getBody() . |
| 27 | + $pager->getNavigationBar(); |
| 28 | + |
| 29 | + $wgOut->addHTML( $html ); |
46 | 30 | |
47 | | - $r = $this->request; |
48 | | - |
49 | | - /* START AND END DATES */ |
50 | | - // $this->start and $this->end are clipped into the range of available |
51 | | - // months, for use in the actual query and the selects. $this->raw* are |
52 | | - // as actually provided, for use by the 'older' and 'newer' buttons. |
53 | | - $ignore_dates = ! $r->getVal( 'lqt_archive_filter_by_date', true ); |
54 | | - if ( !$ignore_dates ) { |
55 | | - $months = Threads::monthsWhereArticleHasThreads( $this->article ); |
56 | | - } |
57 | | - $s = $r->getVal( 'lqt_archive_start' ); |
58 | | - if ( $s && ctype_digit( $s ) && strlen( $s ) == 6 && !$ignore_dates ) { |
59 | | - $this->selstart = new Date( "{$s}01000000" ); |
60 | | - $this->starti = array_search( $s, $months ); |
61 | | - $where[] = 'thread.thread_modified >= ' . $this->selstart->text(); |
62 | | - } |
63 | | - $e = $r->getVal( 'lqt_archive_end' ); |
64 | | - if ( $e && ctype_digit( $e ) && strlen( $e ) == 6 && !$ignore_dates ) { |
65 | | - $this->selend = new Date( "{$e}01000000" ); |
66 | | - $this->endi = array_search( $e, $months ); |
67 | | - $where[] = 'thread.thread_modified < ' . $this->selend->nextMonth()->text(); |
68 | | - } |
69 | | - if ( isset( $this->selstart ) && isset( $this->selend ) ) { |
70 | | - |
71 | | - $this->datespan = $this->starti - $this->endi; |
72 | | - |
73 | | - $formattedFrom = $this->formattedMonth( $this->selstart->text() ); |
74 | | - $formattedTo = $this->formattedMonth( $this->selend->text() ); |
75 | | - |
76 | | - if ( $this->datespan == 0 ) { |
77 | | - $annotations[] = wfMsg( 'lqt_archive_month_annotation', $formattedFrom ); |
78 | | - } else { |
79 | | - $annotations[] = wfMsg( 'lqt_archive_month_range_annotation', $formattedFrom, $formattedTo ); |
80 | | - } |
81 | | - } else if ( isset( $this->selstart ) ) { |
82 | | - $annotations[] = "after {$this->selstart->text()}"; |
83 | | - } else if ( isset( $this->selend ) ) { |
84 | | - $annotations[] = "before {$this->selend->text()}"; |
85 | | - } |
86 | | - |
87 | | - $this->where = $where; |
88 | | - $this->options = $options; |
89 | | - $this->annotations = implode( "<br />\n", $annotations ); |
| 31 | + return false; |
90 | 32 | } |
| 33 | +} |
91 | 34 | |
92 | | - function threads() { |
93 | | - return Threads::where( $this->where, $this->options ); |
| 35 | +class TalkpageArchivePager extends TablePager { |
| 36 | + |
| 37 | + public function __construct( $article, $view ) { |
| 38 | + parent::__construct(); |
| 39 | + $this->article = $article; |
| 40 | + $this->view = $view; |
94 | 41 | } |
95 | 42 | |
96 | | - function formattedMonth( $yyyymm ) { |
97 | | - global $wgLang; // TODO global. |
98 | | - return $wgLang->getMonthName( substr( $yyyymm, 4, 2 ) ) . ' ' . substr( $yyyymm, 0, 4 ); |
| 43 | + public function isFieldSortable( $field ) { |
| 44 | + $sortable = array( 'page_title', 'thread_created', 'thread_modified' ); |
| 45 | + |
| 46 | + return in_array( $field, $sortable ); |
99 | 47 | } |
100 | | - |
101 | | - function monthSelect( $months, $name ) { |
102 | | - $selection = $this->request->getVal( $name ); |
103 | | - |
104 | | - // Silently adjust to stay in range. |
105 | | - $selection = max( min( $selection, $months[0] ), $months[count( $months ) - 1] ); |
106 | | - |
107 | | - $options = array(); |
108 | | - foreach ( $months as $m ) { |
109 | | - $options[$this->formattedMonth( $m )] = $m; |
| 48 | + |
| 49 | + public function formatValue( $field, $value ) { |
| 50 | + global $wgUser, $wgLang; |
| 51 | + |
| 52 | + $sk = $wgUser->getSkin(); |
| 53 | + |
| 54 | + switch( $field ) { |
| 55 | + case 'page_title': |
| 56 | + $title = Title::makeTitle( NS_LQT_THREAD, $value ); |
| 57 | + $split = Thread::splitIncrementFromSubject( $title->getText() ); |
| 58 | + return $sk->link( $title, $split[1] ); |
| 59 | + case 'thread_summary_page': |
| 60 | + $summary = ''; |
| 61 | + |
| 62 | + if ($value) { |
| 63 | + $page = Article::newFromId( $value ); |
| 64 | + $summary = $this->view->showPostBody( $page ); |
| 65 | + } elseif ($this->mCurrentRow->thread_type == Threads::TYPE_MOVED) { |
| 66 | + $thread = new Thread( $this->mCurrentRow, array() ); |
| 67 | + |
| 68 | + $rt = $thread->redirectThread(); |
| 69 | + if ( $rt->hasSummary() ) { |
| 70 | + $summaryPage = $rt->summary(); |
| 71 | + $summary = $this->view->showPostBody( $summaryPage ); |
| 72 | + } |
| 73 | + } |
| 74 | + return $summary; |
| 75 | + case 'thread_created': |
| 76 | + case 'thread_modified': |
| 77 | + return $wgLang->timeanddate( $value, true ); |
| 78 | + case 'rev_user_text': |
| 79 | + $uid = $this->mCurrentRow->rev_user; |
| 80 | + return $sk->userLink( $uid, $value ) . $sk->userToolLinks( $uid, $value ); |
| 81 | + default: |
| 82 | + return $value; |
110 | 83 | } |
111 | | - $result = "<select name=\"$name\" id=\"$name\">"; |
112 | | - foreach ( $options as $label => $value ) { |
113 | | - $selected = $selection == $value ? 'selected="true"' : ''; |
114 | | - $result .= "<option value=\"$value\" $selected>$label"; |
115 | | - } |
116 | | - $result .= "</select>"; |
117 | | - return $result; |
118 | 84 | } |
119 | | - |
120 | | - function clip( $vals, $min, $max ) { |
121 | | - $res = array(); |
122 | | - foreach ( $vals as $val ) $res[] = max( min( $val, $max ), $min ); |
123 | | - return $res; |
| 85 | + |
| 86 | + public function getDefaultSort() { |
| 87 | + return 'thread_created'; |
124 | 88 | } |
125 | | - |
126 | | - /* @return True if there are no threads to show, false otherwise. |
127 | | - TODO is is somewhat bizarre. */ |
128 | | - function showSearchForm() { |
129 | | - $months = Threads::monthsWhereArticleHasThreads( $this->article ); |
130 | | - if ( count( $months ) == 0 ) { |
131 | | - return true; |
132 | | - } |
133 | | - wfLoadExtensionMessages( 'LiquidThreads' ); |
134 | | - |
135 | | - $use_dates = $this->request->getVal( 'lqt_archive_filter_by_date', null ); |
136 | | - if ( $use_dates === null ) { |
137 | | - $use_dates = $this->request->getBool( 'lqt_archive_start', false ) || |
138 | | - $this->request->getBool( 'lqt_archive_end', false ); |
139 | | - } |
140 | | - $any_date_check = !$use_dates ? 'checked="1"' : ''; |
141 | | - $these_dates_check = $use_dates ? 'checked="1"' : ''; |
142 | | - $any_date = wfMsg ( 'lqt-any-date' ); |
143 | | - $only_date = wfMsg ( 'lqt-only-date' ); |
144 | | - $date_from = wfMsg ( 'lqt-date-from' ); |
145 | | - $date_to = wfMsg ( 'lqt-date-to' ); |
146 | | - $date_info = wfMsg ( 'lqt-date-info' ); |
147 | | - if ( isset( $this->datespan ) ) { |
148 | | - $oatte = $this->starti + 1; |
149 | | - $oatts = $this->starti + 1 + $this->datespan; |
150 | | - |
151 | | - $natts = $this->endi - 1; |
152 | | - $natte = $this->endi - 1 - $this->datespan; |
153 | | - |
154 | | - list( $oe, $os, $ns, $ne ) = |
155 | | - $this->clip( array( $oatte, $oatts, $natts, $natte ), |
156 | | - 0, count( $months ) - 1 ); |
157 | | - |
158 | | - $older = '<a class="lqt_newer_older" href="' . $this->queryReplace( array( |
159 | | - 'lqt_archive_filter_by_date' => '1', |
160 | | - 'lqt_archive_start' => $months[$os], |
161 | | - 'lqt_archive_end' => $months[$oe] ) ) |
162 | | - . '">«' . wfMsg ( 'lqt-older' ) . '</a>'; |
163 | | - $newer = '<a class="lqt_newer_older" href="' . $this->queryReplace( array( |
164 | | - 'lqt_archive_filter_by_date' => '1', |
165 | | - 'lqt_archive_start' => $months[$ns], |
166 | | - 'lqt_archive_end' => $months[$ne] ) ) |
167 | | - . '">' . wfMsg ( 'lqt-newer' ) . '»</a>'; |
168 | | - } |
169 | | - else { |
170 | | - $older = '<span class="lqt_newer_older_disabled" title="' . wfMsg ( 'lqt-date-info' ) . '">«' . wfMsg ( 'lqt-older' ) . '</span>'; |
171 | | - $newer = '<span class="lqt_newer_older_disabled" title="' . wfMsg ( 'lqt-date-info' ) . '">' . wfMsg ( 'lqt-newer' ) . '»</span>'; |
172 | | - } |
173 | | - |
174 | | - $this->output->addHTML( <<<HTML |
175 | | -<form id="lqt_archive_search_form" action="{$this->title->getLocalURL()}"> |
176 | | -<input type="hidden" name="lqt_method" value="talkpage_archive"> |
177 | | -<input type="hidden" name="title" value="{$this->title->getPrefixedURL()}" |
178 | | - |
179 | | -<input type="radio" id="lqt_archive_filter_by_date_no" |
180 | | -name="lqt_archive_filter_by_date" value="0" {$any_date_check}> |
181 | | -<label for="lqt_archive_filter_by_date_no">{$any_date}</label> <br /> |
182 | | -<input type="radio" id="lqt_archive_filter_by_date_yes" |
183 | | -name="lqt_archive_filter_by_date" value="1" {$these_dates_check}> |
184 | | -<label for="lqt_archive_filter_by_date_yes">{$only_date}</label> <br /> |
185 | | - |
186 | | -<table> |
187 | | -<tr><td><label for="lqt_archive_start">{$date_from}</label> |
188 | | -<td>{$this->monthSelect($months, 'lqt_archive_start')} <br /> |
189 | | -<tr><td><label for="lqt_archive_end">{$date_to}</label> |
190 | | -<td>{$this->monthSelect($months, 'lqt_archive_end')} |
191 | | -</table> |
192 | | -<input type="submit"> |
193 | | -$older $newer |
194 | | -</form> |
195 | | -HTML |
196 | | - ); |
197 | | - return false; |
| 89 | + |
| 90 | + public function getFieldNames() { |
| 91 | + $fieldToMsg = |
| 92 | + array( |
| 93 | + 'thread_created' => 'lqt-thread-created', |
| 94 | + 'page_title' => 'lqt-title', |
| 95 | + 'thread_modified' => 'lqt_toc_thread_modified', |
| 96 | + 'rev_user_text' => 'lqt_toc_thread_author', |
| 97 | + 'thread_summary_page' => 'lqt-summary', |
| 98 | + ); |
| 99 | + |
| 100 | + return array_map( 'wfMsg', $fieldToMsg ); |
198 | 101 | } |
| 102 | + |
| 103 | + public function getQueryInfo() { |
| 104 | + $dbr = wfGetDB( DB_SLAVE ); |
| 105 | + |
| 106 | + $hasSummaryClauses = array( 'thread_summary_page is not null', |
| 107 | + 'thread_type' => Threads::TYPE_MOVED ); |
| 108 | + $hasSummaryClause = $dbr->makeList( $hasSummaryClauses, LIST_OR ); |
| 109 | + |
| 110 | + $startDays = Threads::getArticleArchiveStartDays( $this->article ); |
| 111 | + $startdate = Date::now()->nDaysAgo( $startDays )->midnight(); |
| 112 | + |
| 113 | + $queryInfo = |
| 114 | + array( |
| 115 | + 'tables' => array( 'thread', 'page', 'revision' ), |
| 116 | + 'fields' => '*', |
| 117 | + 'conds' => |
| 118 | + array( |
| 119 | + Threads::articleClause( $this->article ), |
| 120 | + Threads::topLevelClause(), |
| 121 | + $hasSummaryClause, |
| 122 | + 'thread_modified < '. $dbr->addQuotes( $startdate->text() ), |
| 123 | + 'rev_parent_id' => 0, |
| 124 | + ), |
| 125 | + 'join_conds' => |
| 126 | + array( |
| 127 | + 'page' => array( 'left join', 'thread_root=page_id' ), |
| 128 | + 'revision' => array( 'left join', 'rev_page=page_id' ), |
| 129 | + ), |
| 130 | + ); |
| 131 | + |
199 | 132 | |
200 | | - function show() { |
201 | | - global $wgHooks; |
202 | | - $wgHooks['SkinTemplateTabs'][] = array( $this, 'customizeTabs' ); |
203 | | - |
204 | | - $this->output->setPageTitle( $this->title->getPrefixedText() ); |
205 | | - self::addJSandCSS(); |
206 | | - wfLoadExtensionMessages( 'LiquidThreads' ); |
207 | | - |
208 | | - $empty = $this->showSearchForm(); |
209 | | - if ( $empty ) { |
210 | | - $this->output->addHTML( '<p><br /><b>' . wfMsg( 'lqt-nothread' ) . '</b></p>' ); |
211 | | - return false; |
212 | | - } |
213 | | - $lqt_title = wfMsg ( 'lqt-title' ); |
214 | | - $lqt_summary = wfMsg ( 'lqt-summary' ); |
215 | | - $this->output->addHTML( <<<HTML |
216 | | -<p class="lqt_search_annotations">{$this->annotations}</p> |
217 | | -<table class="lqt_archive_listing"> |
218 | | -<col class="lqt_titles" /> |
219 | | -<col class="lqt_summaries" /> |
220 | | -<tr><th>{$lqt_title}<th>{$lqt_summary}</tr> |
221 | | -HTML |
222 | | - ); |
223 | | - foreach ( $this->threads() as $t ) { |
224 | | - $this->showThread( $t ); |
225 | | - } |
226 | | - $this->output->addHTML( '</table>' ); |
227 | | - |
228 | | - return false; |
| 133 | + return $queryInfo; |
229 | 134 | } |
230 | 135 | } |
Index: trunk/extensions/LiquidThreads/pages/ThreadPermalinkView.php |
— | — | @@ -17,25 +17,33 @@ |
18 | 18 | return true; |
19 | 19 | } |
20 | 20 | |
21 | | - efInsertIntoAssoc( 'article', array( |
22 | | - 'text' => wfMsg( $article_t->getNamespaceKey() ), |
23 | | - 'href' => $article_t->getFullURL(), |
24 | | - 'class' => $article_t->exists() ? '' : 'new' ), |
25 | | - 'nstab-thread', $content_actions ); |
26 | | - efInsertIntoAssoc( 'not_talk', array( |
27 | | - // talkpage certainly exists since this thread is from it. |
28 | | - 'text' => wfMsg( 'talk' ), |
29 | | - 'href' => $talk_t->getFullURL() ), |
30 | | - 'nstab-thread', $content_actions ); |
| 21 | + $articleTab = |
| 22 | + array( |
| 23 | + 'text' => wfMsg( $article_t->getNamespaceKey() ), |
| 24 | + 'href' => $article_t->getFullURL(), |
| 25 | + 'class' => $article_t->exists() ? '' : 'new' |
| 26 | + ); |
| 27 | + efInsertIntoAssoc( 'article', $articleTab, 'nstab-thread', $content_actions ); |
| 28 | + |
| 29 | + $talkTab = |
| 30 | + array( |
| 31 | + // talkpage certainly exists since this thread is from it. |
| 32 | + 'text' => wfMsg( 'talk' ), |
| 33 | + 'href' => $talk_t->getFullURL() |
| 34 | + ); |
| 35 | + |
| 36 | + efInsertIntoAssoc( 'not_talk', $talkTab, 'nstab-thread', $content_actions ); |
31 | 37 | |
32 | 38 | unset( $content_actions['edit'] ); |
33 | 39 | unset( $content_actions['viewsource'] ); |
34 | 40 | unset( $content_actions['talk'] ); |
| 41 | + |
35 | 42 | if ( array_key_exists( 'move', $content_actions ) && $this->thread ) { |
36 | 43 | $content_actions['move']['href'] = |
37 | 44 | SpecialPage::getTitleFor( 'MoveThread' )->getFullURL() . '/' . |
38 | 45 | $this->thread->title()->getPrefixedURL(); |
39 | 46 | } |
| 47 | + |
40 | 48 | if ( array_key_exists( 'delete', $content_actions ) && $this->thread ) { |
41 | 49 | $content_actions['delete']['href'] = |
42 | 50 | SpecialPage::getTitleFor( 'DeleteThread' )->getFullURL() . '/' . |
— | — | @@ -68,20 +76,27 @@ |
69 | 77 | function showMissingThreadPage() { |
70 | 78 | wfLoadExtensionMessages( 'LiquidThreads' ); |
71 | 79 | $this->output->setPageTitle( wfMsg( 'lqt_nosuchthread_title' ) ); |
72 | | - $this->output->addHTML( wfMsg( 'lqt_nosuchthread' ) ); |
| 80 | + $this->output->addWikiMsg( 'lqt_nosuchthread' ); |
73 | 81 | } |
74 | 82 | |
75 | 83 | function getSubtitle() { |
76 | 84 | wfLoadExtensionMessages( 'LiquidThreads' ); |
77 | | - // TODO the archive month part is obsolete. |
78 | | - if ( Date::now()->nDaysAgo( 30 )->midnight()->isBefore( new Date( $this->thread->modified() ) ) ) |
79 | | - $query = ''; |
80 | | - else |
81 | | - $query = 'lqt_archive_month=' . substr( $this->thread->modified(), 0, 6 ); |
| 85 | + |
| 86 | + if ( $this->thread->isHistorical() ) { |
| 87 | + // TODO: Point to the relevant part of the archive. |
| 88 | + $query = ''; |
| 89 | + } else { |
| 90 | + $query = ''; |
| 91 | + } |
| 92 | + |
82 | 93 | $talkpage = $this->thread->article()->getTitle(); |
83 | | - $talkpage_link = $this->user->getSkin()->makeKnownLinkObj( $talkpage, '', $query ); |
| 94 | + $talkpage_link = $this->user->getSkin()->link( $talkpage ); |
| 95 | + |
84 | 96 | if ( $this->thread->hasSuperthread() ) { |
85 | | - return wfMsg( 'lqt_fragment', "<a href=\"{$this->permalinkUrl($this->thread->topmostThread())}\">" . wfMsg( 'lqt_discussion_link' ) . "</a>", $talkpage_link ); |
| 97 | + $permalink = $this->permalink( $this->thread->topmostThread(), |
| 98 | + wfMsg( 'lqt_discussion_link' ) ); |
| 99 | + |
| 100 | + return wfMsg( 'lqt_fragment', $permalink, $talkpage_link ); |
86 | 101 | } else { |
87 | 102 | return wfMsg( 'lqt_from_talk', $talkpage_link ); |
88 | 103 | } |
— | — | @@ -92,11 +107,17 @@ |
93 | 108 | parent::__construct( $output, $article, $title, $user, $request ); |
94 | 109 | |
95 | 110 | $t = Threads::withRoot( $this->article ); |
96 | | - $r = $this->request->getVal( 'lqt_oldid', null ); if ( $r ) { |
97 | | - $t = $t->atRevision( $r ); |
98 | | - if ( !$t ) { $this->noSuchRevision(); return; } |
99 | | - |
| 111 | + $oldid = $this->request->getVal( 'lqt_oldid', null ); |
| 112 | + |
| 113 | + if ( $oldid ) { |
| 114 | + $t = $t->atRevision( $oldid ); |
| 115 | + |
| 116 | + if ( !$t ) { |
| 117 | + $this->noSuchRevision(); |
| 118 | + return; |
| 119 | + } |
100 | 120 | } |
| 121 | + |
101 | 122 | $this->thread = $t; |
102 | 123 | if ( !$t ) { |
103 | 124 | return; // error reporting is handled in show(). this kinda sucks. |