Index: branches/lqt-updates/extensions/LiquidThreads/LiquidThreads.php |
— | — | @@ -260,7 +260,14 @@ |
261 | 261 | $wgAutoloadClasses['LiquidThreadsFormatterContext'] = "$dir/classes/view/Formatter.php"; |
262 | 262 | $wgAutoloadClasses['LiquidThreadsPostFormatter'] = "$dir/classes/view/PostFormatter.php"; |
263 | 263 | $wgAutoloadClasses['LiquidThreadsPostFormatterContext'] = "$dir/classes/view/PostFormatter.php"; |
| 264 | +$wgAutoloadClasses['LiquidThreadsTopicFormatter'] = "$dir/classes/view/TopicFormatter.php"; |
| 265 | +$wgAutoloadClasses['LiquidThreadsTopicFormatterContext'] = "$dir/classes/view/TopicFormatter.php"; |
264 | 266 | |
| 267 | +// Toolbars |
| 268 | +$wgAutoloadClasses['LiquidThreadsToolbar'] = "$dir/classes/view/Toolbar.php"; |
| 269 | +$wgAutoloadClasses['LiquidThreadsPostToolbar'] = "$dir/classes/view/PostToolbar.php"; |
| 270 | +$wgAutoloadClasses['LiquidThreadsTopicToolbar'] = "$dir/classes/view/TopicToolbar.php"; |
| 271 | + |
265 | 272 | /** CONFIGURATION SECTION */ |
266 | 273 | |
267 | 274 | $wgDefaultUserOptions['lqt-watch-threads'] = true; |
Index: branches/lqt-updates/extensions/LiquidThreads/classes/model/PostVersion.php |
— | — | @@ -140,6 +140,10 @@ |
141 | 141 | throw new MWException( "Invalid argument to ".__METHOD__ ); |
142 | 142 | } |
143 | 143 | |
| 144 | + if ( $timestamp == null ) { |
| 145 | + return $post->getCurrentVersion(); |
| 146 | + } |
| 147 | + |
144 | 148 | $dbr = wfGetDB( DB_SLAVE ); |
145 | 149 | |
146 | 150 | $conds = array( 'lpv_post' => $post->getID() ); |
Index: branches/lqt-updates/extensions/LiquidThreads/classes/model/Topic.php |
— | — | @@ -27,6 +27,9 @@ |
28 | 28 | /** Array of LiquidThreadsPost objects, the posts in this topic **/ |
29 | 29 | protected $posts; |
30 | 30 | |
| 31 | + /** Array of LiquidThreadsPost objects, the direct responses to this topic. **/ |
| 32 | + protected $directResponses; |
| 33 | + |
31 | 34 | /** The number of replies that this topic has **/ |
32 | 35 | protected $replyCount; |
33 | 36 | |
— | — | @@ -341,6 +344,29 @@ |
342 | 345 | return $this->posts; |
343 | 346 | } |
344 | 347 | |
| 348 | + /** |
| 349 | + * Retrieves direct responses to this topic. |
| 350 | + * Basically, all posts with no parentID set |
| 351 | + * @return Array of LiquidThreadsPost objects. |
| 352 | + */ |
| 353 | + public function getDirectResponses() { |
| 354 | + if ( is_array( $this->directResponses ) ) { |
| 355 | + return $this->directResponses; |
| 356 | + } // else |
| 357 | + |
| 358 | + $posts = $this->getPosts(); |
| 359 | + |
| 360 | + $this->directResponses = array(); |
| 361 | + |
| 362 | + foreach( $posts as $post ) { |
| 363 | + if ( ! $post->getParentID() ) { |
| 364 | + $this->directResponses[$post->getID()] = $post; |
| 365 | + } |
| 366 | + } |
| 367 | + |
| 368 | + return $this->directResponses; |
| 369 | + } |
| 370 | + |
345 | 371 | /* PROPERTY SETTERS */ |
346 | 372 | |
347 | 373 | /** |
Index: branches/lqt-updates/extensions/LiquidThreads/classes/view/PostFormatter.php |
— | — | @@ -1,7 +1,21 @@ |
2 | 2 | <?php |
3 | 3 | |
4 | 4 | class LiquidThreadsPostFormatter extends LiquidThreadsFormatter { |
| 5 | + |
5 | 6 | /** |
| 7 | + * Get a shared instance of this class. |
| 8 | + */ |
| 9 | + public static function singleton() { |
| 10 | + static $singleton = null; |
| 11 | + |
| 12 | + if ( !$singleton ) { |
| 13 | + $singleton = new self; |
| 14 | + } |
| 15 | + |
| 16 | + return $singleton; |
| 17 | + } |
| 18 | + |
| 19 | + /** |
6 | 20 | * Returns the correct class for the context object |
7 | 21 | */ |
8 | 22 | public function getContextClass() { |
— | — | @@ -40,11 +54,9 @@ |
41 | 55 | } |
42 | 56 | |
43 | 57 | $timestamp = $context->get('timestamp'); |
44 | | - if ( !is_null($timestamp) ) { |
45 | | - $version = PostVersion::newPointInTime( $post, $timestamp ); |
46 | | - } else { |
47 | | - $version = $object->getCurrentVersion(); |
48 | | - } |
| 58 | + // NULL means current version |
| 59 | + $version = LiquidThreadsPostVersion::newPointInTime( $object, $timestamp ); |
| 60 | + $context->set('version', $version); |
49 | 61 | |
50 | 62 | if ( $context->get('single') ) { |
51 | 63 | return $this->formatSingleComment( $object, $version, $context ); |
— | — | @@ -122,7 +134,7 @@ |
123 | 135 | |
124 | 136 | $html .= Xml::closeElement( 'div' ); |
125 | 137 | |
126 | | - $html .= $this->getToolbar( $object, $version, $context ); |
| 138 | + $html .= $this->getToolbar( $object, $context ); |
127 | 139 | $html .= $this->getPostSignature( $object, $version, $context ); |
128 | 140 | $html .= Xml::closeElement( 'div' ); |
129 | 141 | } |
— | — | @@ -158,237 +170,11 @@ |
159 | 171 | * @param $context A LiquidThreadsPostFormatterContext object. |
160 | 172 | * @return HTML |
161 | 173 | */ |
162 | | - protected function getToolbar( $post, $version, $context ) { |
163 | | - $html = ''; |
164 | | - |
165 | | - $headerParts = array(); |
166 | | - |
167 | | - foreach ( $this->getMajorCommands( $post, $version, $context ) as $key => $cmd ) { |
168 | | - $content = $this->formatCommand( $cmd, false /* No icon divs */ ); |
169 | | - $headerParts[] = Xml::tags( 'li', |
170 | | - array( 'class' => "lqt-command lqt-command-$key" ), |
171 | | - $content ); |
172 | | - } |
173 | | - |
174 | | - // Drop-down menu |
175 | | - $commands = $this->getMinorCommands( $post, $version, $context ); |
176 | | - $menuHTML = Xml::tags( 'ul', array( 'class' => 'lqt-thread-toolbar-command-list' ), |
177 | | - $this->formatCommands( $commands ) ); |
178 | | - |
179 | | - $triggerText = Xml::tags( 'a', array( 'class' => 'lqt-thread-actions-icon', |
180 | | - 'href' => '#' ), |
181 | | - wfMsgHTML( 'lqt-menu-trigger' ) ); |
182 | | - $dropDownTrigger = Xml::tags( 'div', |
183 | | - array( 'class' => 'lqt-thread-actions-trigger ' . |
184 | | - 'lqt-command-icon', 'style' => 'display: none;' ), |
185 | | - $triggerText ); |
186 | | - |
187 | | - if ( count( $commands ) ) { |
188 | | - $headerParts[] = Xml::tags( 'li', |
189 | | - array( 'class' => 'lqt-thread-toolbar-menu' ), |
190 | | - $dropDownTrigger ); |
191 | | - } |
192 | | - |
193 | | - $html .= implode( ' ', $headerParts ); |
194 | | - |
195 | | - $html = Xml::tags( 'ul', array( 'class' => 'lqt-thread-toolbar-commands' ), $html ); |
196 | | - |
197 | | - $html = Xml::tags( 'div', array( 'class' => 'lqt-thread-toolbar' ), $html ) . |
198 | | - $menuHTML; |
199 | | - |
200 | | - return $html; |
201 | | - } |
202 | | - |
203 | | - /** |
204 | | - * Formats a list of toolbar commands. |
205 | | - * @param $commands Associative array of commands. |
206 | | - * @return HTML |
207 | | - * @see LiquidThreadsPostFormatter::formatCommand |
208 | | - */ |
209 | | - function formatCommands( $commands ) { |
210 | | - $result = array(); |
211 | | - foreach ( $commands as $key => $command ) { |
212 | | - $thisCommand = $this->formatCommand( $command ); |
213 | | - |
214 | | - $thisCommand = Xml::tags( |
215 | | - 'li', |
216 | | - array( 'class' => 'lqt-command lqt-command-' . $key ), |
217 | | - $thisCommand |
218 | | - ); |
219 | | - |
220 | | - $result[] = $thisCommand; |
221 | | - } |
222 | | - return join( ' ', $result ); |
223 | | - } |
224 | | - |
225 | | - /** |
226 | | - * Formats a toolbar command |
227 | | - * @param $command Associative array describing this command |
228 | | - * Valid keys: |
229 | | - * label: The text to show for this command. |
230 | | - * href: The URL to link to. |
231 | | - * enabled: Whether or not this command is enabled. |
232 | | - * tooltip: If specified, the tooltip to show for this command. |
233 | | - * icon: If specified, an icon is shown. |
234 | | - * showlabel: Whether or not to show the label. Default: on. |
235 | | - * @param $icon_divs Boolean: If false, do not insert <divs> to style with an icon. |
236 | | - * @return HTML: Command formatted in a <div> |
237 | | - */ |
238 | | - function formatCommand( $command, $icon_divs = true ) { |
239 | | - $label = $command['label']; |
240 | | - $href = $command['href']; |
241 | | - $enabled = $command['enabled']; |
242 | | - $tooltip = isset( $command['tooltip'] ) ? $command['tooltip'] : ''; |
243 | | - |
244 | | - if ( isset( $command['icon'] ) ) { |
245 | | - $icon = Xml::tags( 'div', array( 'title' => $label, |
246 | | - 'class' => 'lqt-command-icon' ), ' ' ); |
247 | | - if ( $icon_divs ) { |
248 | | - if ( !empty( $command['showlabel'] ) ) { |
249 | | - $label = $icon . ' ' . $label; |
250 | | - } else { |
251 | | - $label = $icon; |
252 | | - } |
253 | | - } else { |
254 | | - if ( empty( $command['showlabel'] ) ) { |
255 | | - $label = ''; |
256 | | - } |
257 | | - } |
258 | | - } |
259 | | - |
260 | | - if ( $enabled ) { |
261 | | - $thisCommand = Xml::tags( 'a', array( 'href' => $href, 'title' => $tooltip ), |
262 | | - $label ); |
263 | | - } else { |
264 | | - $thisCommand = Xml::tags( 'span', array( 'class' => 'lqt_command_disabled', |
265 | | - 'title' => $tooltip ), $label ); |
266 | | - } |
267 | | - |
268 | | - return $thisCommand; |
269 | | - } |
270 | | - |
271 | | - /** |
272 | | - * Gets the commands to show in the dropdown of a post. |
273 | | - * @param $post The LiquidThreadsPost to show a dropdown for. |
274 | | - * @param $version The LiquidThreadsPostVersion to show the dropdown for. |
275 | | - * @param $context A LiquidThreadsPostFormatterContext object. |
276 | | - * @return An associative array of arguments suitable for |
277 | | - * LiquidThreadsPostFormatter::formatCommand |
278 | | - * @see LiquidThreadsPostFormatter::formatCommand |
279 | | - */ |
280 | | - function getMinorCommands( $post, $version, $context ) { |
281 | | - $commands = array(); |
282 | | - |
283 | | - // TODO make this link operate properly |
284 | | - $history_url = SpecialPage::getTitleFor( 'PostHistory', $post->getID() ); |
285 | | - $commands['history'] = array( |
286 | | - 'label' => wfMsgExt( 'history_short', 'parseinline' ), |
287 | | - 'href' => $history_url, |
288 | | - 'enabled' => true, |
289 | | - ); |
| 174 | + protected function getToolbar( $post, $context ) { |
| 175 | + $toolbar = LiquidThreadsPostToolbar::singleton(); |
290 | 176 | |
291 | | - // TODO permissions checking |
292 | | - $edit_url = SpecialPage::getTitleFor( 'EditPost', $post->getID() ); |
293 | | - $commands['edit'] = array( |
294 | | - 'label' => wfMsgExt( 'edit', 'parseinline' ), |
295 | | - 'href' => $edit_url, |
296 | | - 'enabled' => true |
297 | | - ); |
298 | | - |
299 | | - if ( $context->get('user')->isAllowed( 'lqt-split' ) ) { |
300 | | - $splitUrl = SpecialPage::getTitleFor( 'SplitThread', $post->getID() )->getFullURL(); |
301 | | - $commands['split'] = array( |
302 | | - 'label' => wfMsgExt( 'lqt-thread-split', 'parseinline' ), |
303 | | - 'href' => $splitUrl, |
304 | | - 'enabled' => true |
305 | | - ); |
306 | | - } |
307 | | - |
308 | | - // TODO implement merging |
309 | | -// if ( $context->get('user')->isAllowed( 'lqt-merge' ) ) { |
310 | | -// $mergeParams = $_GET; |
311 | | -// $mergeParams['lqt_merge_from'] = $thread->id(); |
312 | | -// |
313 | | -// unset( $mergeParams['title'] ); |
314 | | -// |
315 | | -// $mergeUrl = $this->title->getLocalURL( wfArrayToCGI( $mergeParams ) ); |
316 | | -// $label = wfMsgExt( 'lqt-thread-merge', 'parseinline' ); |
317 | | -// |
318 | | -// $commands['merge'] = array( |
319 | | -// 'label' => $label, |
320 | | -// 'href' => $mergeUrl, |
321 | | -// 'enabled' => true |
322 | | -// ); |
323 | | -// } |
324 | | - |
325 | | - $commands['link'] = array( |
326 | | - 'label' => wfMsgExt( 'lqt_permalink', 'parseinline' ), |
327 | | - 'href' => SpecialPage::getTitleFor( 'Post', $post->getID() ), |
328 | | - 'enabled' => true, |
329 | | - 'showlabel' => true, |
330 | | - 'tooltip' => wfMsgExt( 'lqt_permalink', 'parseinline' ) |
331 | | - ); |
332 | | - |
333 | | - wfRunHooks( 'LiquidThreadsPostMinorCommands', |
334 | | - array( $post, $version, $context, &$commands ) ); |
335 | | - |
336 | | - return $commands; |
| 177 | + return $toolbar->getHTML( $post, $context ); |
337 | 178 | } |
338 | | - |
339 | | - /** |
340 | | - * Gets the main commands in the main (non-dropdown) part of the toolbar. |
341 | | - * @param $post The LiquidThreadsPost to show a toolbar for. |
342 | | - * @param $version The LiquidThreadsPostVersion to show the toolbar for. |
343 | | - * @param $context A LiquidThreadsPostFormatterContext object. |
344 | | - * @return An associative array of arguments suitable for |
345 | | - * LiquidThreadsPostFormatter::formatCommand |
346 | | - * @see LiquidThreadsPostFormatter::formatCommand |
347 | | - */ |
348 | | - function getMajorCommands( $post, $version, $context ) { |
349 | | - $commands = array(); |
350 | | - |
351 | | -// if ( $this->user->isAllowed( 'lqt-merge' ) && |
352 | | -// $this->request->getCheck( 'lqt_merge_from' ) ) { |
353 | | -// $srcThread = Threads::withId( $this->request->getVal( 'lqt_merge_from' ) ); |
354 | | -// $par = $srcThread->title()->getPrefixedText(); |
355 | | -// $mergeTitle = SpecialPage::getTitleFor( 'MergeThread', $par ); |
356 | | -// $mergeUrl = $mergeTitle->getLocalURL( 'dest=' . $thread->id() ); |
357 | | -// $label = wfMsgExt( 'lqt-thread-merge-to', 'parseinline' ); |
358 | | -// |
359 | | -// $commands['merge-to'] = array( |
360 | | -// 'label' => $label, 'href' => $mergeUrl, |
361 | | -// 'enabled' => true, |
362 | | -// 'tooltip' => $label |
363 | | -// ); |
364 | | -// } |
365 | | - |
366 | | - // TODO permissions checking, proper URL |
367 | | - $commands['reply'] = array( |
368 | | - 'label' => wfMsgExt( 'lqt_reply', 'parseinline' ), |
369 | | - 'href' => SpecialPage::getTitleFor('Reply', $post->getID() )->getFullURL(), |
370 | | - 'enabled' => true, |
371 | | - 'showlabel' => 1, |
372 | | - 'tooltip' => wfMsg( 'lqt_reply' ), |
373 | | - 'icon' => 'reply.png', |
374 | | - ); |
375 | | - |
376 | | - // Parent post link |
377 | | - if ( $version->getParentID() ) { |
378 | | - $parentID = $version->getParentID(); |
379 | | - |
380 | | - $commands['parent'] = array( |
381 | | - 'label' => wfMsgExt( 'lqt-parent', 'parseinline' ), |
382 | | - 'href' => '#' . $this->getAnchor($parentID), |
383 | | - 'enabled' => true, |
384 | | - 'showlabel' => 1, |
385 | | - ); |
386 | | - } |
387 | | - |
388 | | - wfRunHooks( 'LiquidThreadsPostMajorCommands', |
389 | | - array( $post, $version, $context, &$commands ) ); |
390 | | - |
391 | | - return $commands; |
392 | | - } |
393 | 179 | |
394 | 180 | function getPostSignature( $post, $version, $context ) { |
395 | 181 | $lang = $context->get('language'); |
— | — | @@ -451,5 +237,6 @@ |
452 | 238 | 'language', |
453 | 239 | 'nesting-level', |
454 | 240 | 'post-callbacks', |
| 241 | + 'version', |
455 | 242 | ); |
456 | 243 | } |
Index: branches/lqt-updates/extensions/LiquidThreads/classes/view/TopicToolbar.php |
— | — | @@ -0,0 +1,97 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +class LiquidThreadsTopicToolbar extends LiquidThreadsToolbar { |
| 5 | + /** |
| 6 | + * Get a shared instance of this class. |
| 7 | + */ |
| 8 | + public static function singleton() { |
| 9 | + static $singleton = null; |
| 10 | + |
| 11 | + if ( !$singleton ) { |
| 12 | + $singleton = new self; |
| 13 | + } |
| 14 | + |
| 15 | + return $singleton; |
| 16 | + } |
| 17 | + |
| 18 | + /** |
| 19 | + * Returns the correct class for the context object |
| 20 | + */ |
| 21 | + public function getContextClass() { |
| 22 | + return 'LiquidThreadsTopicFormatterContext'; |
| 23 | + } |
| 24 | + |
| 25 | + /** |
| 26 | + * Returns the class that can be formatted by this object. |
| 27 | + */ |
| 28 | + public function getObjectClass() { |
| 29 | + return 'LiquidThreadsTopic'; |
| 30 | + } |
| 31 | + |
| 32 | + /** |
| 33 | + * Returns the commands to be shown in this toolbar. |
| 34 | + * @param $object The object that the toolbar is for. |
| 35 | + * @param $context A context object, usually for a related formatter. |
| 36 | + * @return An array suitable for LiquidThreadsToolbar::formatCommands |
| 37 | + */ |
| 38 | + function getCommands( $topic, $context = null ) { |
| 39 | + $commands = array(); |
| 40 | + |
| 41 | + $commands['history'] = array( |
| 42 | + 'label' => wfMsg( 'history_short' ), |
| 43 | + 'href' => SpecialPage::getTitleFor('TopicHistory', $topic->getID())->getFullURL(), |
| 44 | + 'enabled' => true |
| 45 | + ); |
| 46 | + |
| 47 | + if ( $context->get('user')->isAllowed( 'move' ) ) { |
| 48 | + $move_href = SpecialPage::getTitleFor( 'MoveTopic', $topic->getID() )->getFullURL(); |
| 49 | + $commands['move'] = array( |
| 50 | + 'label' => wfMsg( 'lqt-movethread' ), |
| 51 | + 'href' => $move_href, |
| 52 | + 'enabled' => true |
| 53 | + ); |
| 54 | + } |
| 55 | + |
| 56 | +// if ( $this->user->isAllowed( 'protect' ) ) { |
| 57 | +// $protect_href = $thread->title()->getLocalURL( 'action=protect' ); |
| 58 | +// |
| 59 | +// // Check if it's already protected |
| 60 | +// if ( !$thread->title()->isProtected() ) { |
| 61 | +// $label = wfMsg( 'protect' ); |
| 62 | +// } else { |
| 63 | +// $label = wfMsg( 'unprotect' ); |
| 64 | +// } |
| 65 | +// |
| 66 | +// $commands['protect'] = array( |
| 67 | +// 'label' => $label, |
| 68 | +// 'href' => $protect_href, |
| 69 | +// 'enabled' => true |
| 70 | +// ); |
| 71 | +// } |
| 72 | + |
| 73 | +// if ( !$this->user->isAnon() && !$thread->title()->userIsWatching() ) { |
| 74 | +// $commands['watch'] = array( |
| 75 | +// 'label' => wfMsg( 'watch' ), |
| 76 | +// 'href' => self::permalinkUrlWithQuery( $thread, 'action=watch' ), |
| 77 | +// 'enabled' => true |
| 78 | +// ); |
| 79 | +// } else if ( !$this->user->isAnon() ) { |
| 80 | +// $commands['unwatch'] = array( |
| 81 | +// 'label' => wfMsg( 'unwatch' ), |
| 82 | +// 'href' => self::permalinkUrlWithQuery( $thread, 'action=unwatch' ), |
| 83 | +// 'enabled' => true |
| 84 | +// ); |
| 85 | +// } |
| 86 | + |
| 87 | + $summarizeUrl = SpecialPage::getTitleFor('SummarizeTopic', $topic->getID())->getFullURL(); |
| 88 | + $commands['summarize'] = array( |
| 89 | + 'label' => wfMsgExt( 'lqt_summarize_link', 'parseinline' ), |
| 90 | + 'href' => $summarizeUrl, |
| 91 | + 'enabled' => true, |
| 92 | + ); |
| 93 | + |
| 94 | + wfRunHooks( 'LiquidThreadsTopicCommands', array( $topic, $context, &$commands ) ); |
| 95 | + |
| 96 | + return $commands; |
| 97 | + } |
| 98 | +} |
Index: branches/lqt-updates/extensions/LiquidThreads/classes/view/Toolbar.php |
— | — | @@ -0,0 +1,104 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +abstract class LiquidThreadsToolbar extends LiquidThreadsFormatter { |
| 5 | + /** |
| 6 | + * Gets the HTML for this toolbar. |
| 7 | + * @param $object The object that the toolbar is for. |
| 8 | + * @param $context A context object, usually for a related formatter. |
| 9 | + * @return HTML result |
| 10 | + */ |
| 11 | + public function getHTML( $object, $context = null ) { |
| 12 | + $commands = $this->getCommands( $object, $context ); |
| 13 | + |
| 14 | + $formattedCommands = $this->formatCommands( $commands ); |
| 15 | + |
| 16 | + $list = Xml::tags( 'ul', array( 'class' => $this->getCSSClass() ), |
| 17 | + $formattedCommands ); |
| 18 | + |
| 19 | + return $list; |
| 20 | + } |
| 21 | + |
| 22 | + /** |
| 23 | + * Gets the class to be applied to the toolbar. |
| 24 | + */ |
| 25 | + protected function getCSSClass() { |
| 26 | + return 'lqt-toolbar'; |
| 27 | + } |
| 28 | + |
| 29 | + /** |
| 30 | + * Returns the commands to be shown in this toolbar. |
| 31 | + * @param $object The object that the toolbar is for. |
| 32 | + * @param $context A context object, usually for a related formatter. |
| 33 | + * @return An array suitable for LiquidThreadsToolbar::formatCommands |
| 34 | + */ |
| 35 | + abstract protected function getCommands( $object, $context = null ); |
| 36 | + |
| 37 | + /** |
| 38 | + * Formats a list of toolbar commands. |
| 39 | + * @param $commands Associative array of commands. |
| 40 | + * @return HTML |
| 41 | + * @see LiquidThreadsPostFormatter::formatCommand |
| 42 | + */ |
| 43 | + public function formatCommands( $commands ) { |
| 44 | + $result = array(); |
| 45 | + foreach ( $commands as $key => $command ) { |
| 46 | + $thisCommand = $this->formatCommand( $command ); |
| 47 | + |
| 48 | + $thisCommand = Xml::tags( |
| 49 | + 'li', |
| 50 | + array( 'class' => 'lqt-command lqt-command-' . $key ), |
| 51 | + $thisCommand |
| 52 | + ); |
| 53 | + |
| 54 | + $result[] = $thisCommand; |
| 55 | + } |
| 56 | + return join( ' ', $result ); |
| 57 | + } |
| 58 | + |
| 59 | + /** |
| 60 | + * Formats a toolbar command |
| 61 | + * @param $command Associative array describing this command |
| 62 | + * Valid keys: |
| 63 | + * label: The text to show for this command. |
| 64 | + * href: The URL to link to. |
| 65 | + * enabled: Whether or not this command is enabled. |
| 66 | + * tooltip: If specified, the tooltip to show for this command. |
| 67 | + * icon: If specified, an icon is shown. |
| 68 | + * showlabel: Whether or not to show the label. Default: on. |
| 69 | + * @param $icon_divs Boolean: If false, do not insert <divs> to style with an icon. |
| 70 | + * @return HTML: Command formatted in a <div> |
| 71 | + */ |
| 72 | + public function formatCommand( $command, $icon_divs = true ) { |
| 73 | + $label = $command['label']; |
| 74 | + $href = $command['href']; |
| 75 | + $enabled = $command['enabled']; |
| 76 | + $tooltip = isset( $command['tooltip'] ) ? $command['tooltip'] : ''; |
| 77 | + |
| 78 | + if ( isset( $command['icon'] ) ) { |
| 79 | + $icon = Xml::tags( 'div', array( 'title' => $label, |
| 80 | + 'class' => 'lqt-command-icon' ), ' ' ); |
| 81 | + if ( $icon_divs ) { |
| 82 | + if ( !empty( $command['showlabel'] ) ) { |
| 83 | + $label = $icon . ' ' . $label; |
| 84 | + } else { |
| 85 | + $label = $icon; |
| 86 | + } |
| 87 | + } else { |
| 88 | + if ( empty( $command['showlabel'] ) ) { |
| 89 | + $label = ''; |
| 90 | + } |
| 91 | + } |
| 92 | + } |
| 93 | + |
| 94 | + if ( $enabled ) { |
| 95 | + $thisCommand = Xml::tags( 'a', array( 'href' => $href, 'title' => $tooltip ), |
| 96 | + $label ); |
| 97 | + } else { |
| 98 | + $thisCommand = Xml::tags( 'span', array( 'class' => 'lqt_command_disabled', |
| 99 | + 'title' => $tooltip ), $label ); |
| 100 | + } |
| 101 | + |
| 102 | + return $thisCommand; |
| 103 | + } |
| 104 | + |
| 105 | +} |
Index: branches/lqt-updates/extensions/LiquidThreads/classes/view/TopicFormatter.php |
— | — | @@ -0,0 +1,167 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +class LiquidThreadsTopicFormatter extends LiquidThreadsFormatter { |
| 5 | + |
| 6 | + /** |
| 7 | + * Get a shared instance of this class. |
| 8 | + */ |
| 9 | + public static function singleton() { |
| 10 | + static $singleton = null; |
| 11 | + |
| 12 | + if ( !$singleton ) { |
| 13 | + $singleton = new self; |
| 14 | + } |
| 15 | + |
| 16 | + return $singleton; |
| 17 | + } |
| 18 | + |
| 19 | + /** |
| 20 | + * Returns the correct class for the context object |
| 21 | + */ |
| 22 | + public function getContextClass() { |
| 23 | + return 'LiquidThreadsTopicFormatterContext'; |
| 24 | + } |
| 25 | + |
| 26 | + /** |
| 27 | + * Returns the class that can be formatted by this object. |
| 28 | + */ |
| 29 | + public function getObjectClass() { |
| 30 | + return 'LiquidThreadsTopic'; |
| 31 | + } |
| 32 | + |
| 33 | + /** |
| 34 | + * Convert a LiquidThreadsPost to HTML. |
| 35 | + * @param $object The LiquidThreadsPost to convert. |
| 36 | + * @param $context LiquidThreadsPostFormatterContext object. |
| 37 | + * @return HTML result |
| 38 | + */ |
| 39 | + public function getHTML( $object, $context = null ) { |
| 40 | + // Error checking |
| 41 | + $this->checkArguments( $object, $context ); |
| 42 | + |
| 43 | + if ( ! $context->get('language') ) { |
| 44 | + global $wgLang; |
| 45 | + $context->set( 'language', $wgLang ); |
| 46 | + } |
| 47 | + |
| 48 | + if ( ! $context->get('user') ) { |
| 49 | + global $wgUser; |
| 50 | + $context->set('user', $wgUser ); |
| 51 | + } |
| 52 | + |
| 53 | + $html = Xml::openElement( 'div', |
| 54 | + array( 'class' => 'lqt-topic', |
| 55 | + 'id' => 'lqt-topic-id-'.$object->getID() ) ); |
| 56 | + |
| 57 | + // Show topic heading |
| 58 | + $html .= $this->getHeading( $object, $context ); |
| 59 | + |
| 60 | + // Now show the comments |
| 61 | + |
| 62 | + // TODO Show only comments as they appeared at $timestamp |
| 63 | + $directResponses = $object->getDirectResponses(); |
| 64 | + |
| 65 | + $postContext = $context->get('post-context'); |
| 66 | + |
| 67 | + if ( is_null($postContext) ) { |
| 68 | + $postContext = new LiquidThreadsPostFormatterContext(); |
| 69 | + |
| 70 | + $postContext->set( 'timestamp', $context->get('timestamp') ); |
| 71 | + $postContext->set( 'user', $context->get('user') ); |
| 72 | + $postContext->set( 'language', $context->get('language') ); |
| 73 | + } |
| 74 | + |
| 75 | + // Set up formatter |
| 76 | + $postFormatter = LiquidThreadsPostFormatter::singleton(); |
| 77 | + |
| 78 | + foreach( $directResponses as $reply ) { |
| 79 | + $html .= $postFormatter->getHTML( $reply, $postContext ); |
| 80 | + } |
| 81 | + |
| 82 | + $html .= Xml::closeElement( 'div' ); |
| 83 | + |
| 84 | + return $html; |
| 85 | + } |
| 86 | + |
| 87 | + /** |
| 88 | + * Gets the heading and its included topic-level toolbar. |
| 89 | + * @param $object The LiquidThreadsTopic for which to get a heading. |
| 90 | + * @param $context The context object. |
| 91 | + * @return HTML result. |
| 92 | + */ |
| 93 | + protected function getHeading( $object, $context ) { |
| 94 | + $version = $context->get('version'); |
| 95 | + |
| 96 | + if ( !($version instanceof LiquidThreadsTopicVersion) || |
| 97 | + $version->getTopicID() != $object->getID() ) |
| 98 | + { |
| 99 | + $version = LiquidThreadsTopicVersion::newPointInTime( $object, |
| 100 | + $context->get('timestamp') ); |
| 101 | + } |
| 102 | + |
| 103 | + $toolbar = LiquidThreadsTopicToolbar::singleton(); |
| 104 | + $toolbarHTML = $toolbar->getHTML( $object, $context ); |
| 105 | + |
| 106 | + $subject = $version->getSubject(); |
| 107 | + |
| 108 | + $formattedSubject = $this->formatSubject( $subject ); |
| 109 | + |
| 110 | + $formattedSubject = Xml::tags( 'span', array( 'class' => 'mw-headline' ), |
| 111 | + $formattedSubject ); |
| 112 | + |
| 113 | + $formattedSubject = Xml::tags( 'h2', |
| 114 | + array( |
| 115 | + 'class' => 'lqt-header', |
| 116 | + 'id' => 'lqt-header-id-'.$object->getID(), |
| 117 | + ), $formattedSubject ); |
| 118 | + |
| 119 | + $html = $formattedSubject . "\n" . $toolbarHTML; |
| 120 | + |
| 121 | + $html = Xml::tags( 'div', array( 'class' => 'lqt-heading' ), $html ); |
| 122 | + |
| 123 | + return $html; |
| 124 | + } |
| 125 | + |
| 126 | + /** |
| 127 | + * Formats a topic subject. |
| 128 | + * @param $subject String: The subject source to format. |
| 129 | + * @return The subject, lightly formatted, as HTML. |
| 130 | + */ |
| 131 | + protected function formatSubject( $subject ) { |
| 132 | + wfProfileIn( __METHOD__ ); |
| 133 | + global $wgUser; |
| 134 | + $sk = $wgUser->getSkin(); |
| 135 | + |
| 136 | + # Sanitize text a bit: |
| 137 | + $subject = str_replace( "\n", " ", $subject ); |
| 138 | + # Allow HTML entities |
| 139 | + $subject = Sanitizer::escapeHtmlAllowEntities( $subject ); |
| 140 | + |
| 141 | + # Render links: |
| 142 | + $subject = $sk->formatLinksInComment( $subject, null, false ); |
| 143 | + |
| 144 | + wfProfileOut( __METHOD__ ); |
| 145 | + return $subject; |
| 146 | + } |
| 147 | + |
| 148 | +} |
| 149 | + |
| 150 | +/** |
| 151 | + * This class provides context for formatting a LiquidThreadsTopic object. |
| 152 | + * Valid fields are: |
| 153 | + * timestamp: The point in time at which to show this LiquidThreadsTopic. |
| 154 | + * user: The User object for which to show this LiquidThreadsTopic. |
| 155 | + * language: Override the Language object that the topic is shown in. |
| 156 | + * post-callbacks: If set, an associative array of callbacks used to replace display of |
| 157 | + * individual posts. Key is the post ID, value is a callback. Used for |
| 158 | + * edit forms and the like. |
| 159 | + */ |
| 160 | +class LiquidThreadsTopicFormatterContext extends LiquidThreadsFormatterContext { |
| 161 | + protected $validFields = array( |
| 162 | + 'timestamp', |
| 163 | + 'user', |
| 164 | + 'language', |
| 165 | + 'post-context', |
| 166 | + 'version', |
| 167 | + ); |
| 168 | +} |
Index: branches/lqt-updates/extensions/LiquidThreads/classes/view/PostToolbar.php |
— | — | @@ -0,0 +1,219 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +class LiquidThreadsPostToolbar extends LiquidThreadsToolbar { |
| 5 | + |
| 6 | + /** |
| 7 | + * Returns the correct class for the context object |
| 8 | + */ |
| 9 | + public function getContextClass() { |
| 10 | + return 'LiquidThreadsPostFormatterContext'; |
| 11 | + } |
| 12 | + |
| 13 | + /** |
| 14 | + * Returns the class that can be formatted by this object. |
| 15 | + */ |
| 16 | + public function getObjectClass() { |
| 17 | + return 'LiquidThreadsPost'; |
| 18 | + } |
| 19 | + |
| 20 | + /** |
| 21 | + * Get a shared instance of this class. |
| 22 | + */ |
| 23 | + public static function singleton() { |
| 24 | + static $singleton = null; |
| 25 | + |
| 26 | + if ( !$singleton ) { |
| 27 | + $singleton = new self; |
| 28 | + } |
| 29 | + |
| 30 | + return $singleton; |
| 31 | + } |
| 32 | + |
| 33 | + /** |
| 34 | + * Generates a toolbar for a post. |
| 35 | + * @param $post The LiquidThreadsPost being shown. |
| 36 | + * @param $version The LiquidThreadsPostVersion to show the dropdown for. |
| 37 | + * @param $context A LiquidThreadsPostFormatterContext object. |
| 38 | + * @return HTML |
| 39 | + */ |
| 40 | + public function getHTML( $post, $context = null ) { |
| 41 | + $this->checkArguments( $post, $context ); |
| 42 | + |
| 43 | + $html = ''; |
| 44 | + |
| 45 | + $version = $context->get('version'); |
| 46 | + // Retrieve the appropriate version if necessary |
| 47 | + if ( is_null($version) || $version->getPostID() != $post->getID() ) { |
| 48 | + $timestamp = $context->get('timestamp'); |
| 49 | + $version = LiquidThreadsPostVersion::newPointInTime( $post, $timestamp ); |
| 50 | + $context->set('version', $version); |
| 51 | + } |
| 52 | + |
| 53 | + $headerParts = array(); |
| 54 | + |
| 55 | + foreach ( $this->getCommands( $post, $context ) as $key => $cmd ) { |
| 56 | + $content = $this->formatCommand( $cmd, false /* No icon divs */ ); |
| 57 | + $headerParts[] = Xml::tags( 'li', |
| 58 | + array( 'class' => "lqt-command lqt-command-$key" ), |
| 59 | + $content ); |
| 60 | + } |
| 61 | + |
| 62 | + // Drop-down menu |
| 63 | + $commands = $this->getMinorCommands( $post, $context ); |
| 64 | + $menuHTML = Xml::tags( 'ul', array( 'class' => 'lqt-thread-toolbar-command-list' ), |
| 65 | + $this->formatCommands( $commands ) ); |
| 66 | + |
| 67 | + $triggerText = Xml::tags( 'a', array( 'class' => 'lqt-thread-actions-icon', |
| 68 | + 'href' => '#' ), |
| 69 | + wfMsgHTML( 'lqt-menu-trigger' ) ); |
| 70 | + $dropDownTrigger = Xml::tags( 'div', |
| 71 | + array( 'class' => 'lqt-thread-actions-trigger ' . |
| 72 | + 'lqt-command-icon', 'style' => 'display: none;' ), |
| 73 | + $triggerText ); |
| 74 | + |
| 75 | + if ( count( $commands ) ) { |
| 76 | + $headerParts[] = Xml::tags( 'li', |
| 77 | + array( 'class' => 'lqt-thread-toolbar-menu' ), |
| 78 | + $dropDownTrigger ); |
| 79 | + } |
| 80 | + |
| 81 | + $html .= implode( ' ', $headerParts ); |
| 82 | + |
| 83 | + $html = Xml::tags( 'ul', array( 'class' => 'lqt-thread-toolbar-commands' ), $html ); |
| 84 | + |
| 85 | + $html = Xml::tags( 'div', array( 'class' => 'lqt-thread-toolbar' ), $html ) . |
| 86 | + $menuHTML; |
| 87 | + |
| 88 | + return $html; |
| 89 | + } |
| 90 | + |
| 91 | + /** |
| 92 | + * Gets the main commands in the main (non-dropdown) part of the toolbar. |
| 93 | + * @param $post The LiquidThreadsPost to show a toolbar for. |
| 94 | + * @param $version The LiquidThreadsPostVersion to show the toolbar for. |
| 95 | + * @param $context A LiquidThreadsPostFormatterContext object. |
| 96 | + * @return An associative array of arguments suitable for |
| 97 | + * LiquidThreadsToolbar::formatCommand |
| 98 | + * @see LiquidThreadsToolbar::formatCommand |
| 99 | + */ |
| 100 | + protected function getCommands( $post, $context = null ) { |
| 101 | + $commands = array(); |
| 102 | + |
| 103 | + // Will have been set in getToolbar() |
| 104 | + $version = $context->get('version'); |
| 105 | + |
| 106 | +// if ( $this->user->isAllowed( 'lqt-merge' ) && |
| 107 | +// $this->request->getCheck( 'lqt_merge_from' ) ) { |
| 108 | +// $srcThread = Threads::withId( $this->request->getVal( 'lqt_merge_from' ) ); |
| 109 | +// $par = $srcThread->title()->getPrefixedText(); |
| 110 | +// $mergeTitle = SpecialPage::getTitleFor( 'MergeThread', $par ); |
| 111 | +// $mergeUrl = $mergeTitle->getLocalURL( 'dest=' . $thread->id() ); |
| 112 | +// $label = wfMsgExt( 'lqt-thread-merge-to', 'parseinline' ); |
| 113 | +// |
| 114 | +// $commands['merge-to'] = array( |
| 115 | +// 'label' => $label, 'href' => $mergeUrl, |
| 116 | +// 'enabled' => true, |
| 117 | +// 'tooltip' => $label |
| 118 | +// ); |
| 119 | +// } |
| 120 | + |
| 121 | + // TODO permissions checking, proper URL |
| 122 | + $commands['reply'] = array( |
| 123 | + 'label' => wfMsgExt( 'lqt_reply', 'parseinline' ), |
| 124 | + 'href' => SpecialPage::getTitleFor('Reply', $post->getID() )->getFullURL(), |
| 125 | + 'enabled' => true, |
| 126 | + 'showlabel' => 1, |
| 127 | + 'tooltip' => wfMsg( 'lqt_reply' ), |
| 128 | + 'icon' => 'reply.png', |
| 129 | + ); |
| 130 | + |
| 131 | + // Parent post link |
| 132 | + if ( $version->getParentID() ) { |
| 133 | + $parentID = $version->getParentID(); |
| 134 | + |
| 135 | + $commands['parent'] = array( |
| 136 | + 'label' => wfMsgExt( 'lqt-parent', 'parseinline' ), |
| 137 | + 'href' => '#' . $this->getAnchor($parentID), |
| 138 | + 'enabled' => true, |
| 139 | + 'showlabel' => 1, |
| 140 | + ); |
| 141 | + } |
| 142 | + |
| 143 | + wfRunHooks( 'LiquidThreadsPostMajorCommands', |
| 144 | + array( $post, $version, $context, &$commands ) ); |
| 145 | + |
| 146 | + return $commands; |
| 147 | + } |
| 148 | + |
| 149 | + |
| 150 | + /** |
| 151 | + * Gets the commands to show in the dropdown of a post. |
| 152 | + * @param $post The LiquidThreadsPost to show a dropdown for. |
| 153 | + * @param $version The LiquidThreadsPostVersion to show the dropdown for. |
| 154 | + * @param $context A LiquidThreadsPostFormatterContext object. |
| 155 | + * @return An associative array of arguments suitable for |
| 156 | + * LiquidThreadsToolbar::formatCommand |
| 157 | + * @see LiquidThreadsToolbar::formatCommand |
| 158 | + */ |
| 159 | + protected function getMinorCommands( $post, $context ) { |
| 160 | + $commands = array(); |
| 161 | + |
| 162 | + // Will have been set in getToolbar() |
| 163 | + $version = $context->get('version'); |
| 164 | + |
| 165 | + // TODO make this link operate properly |
| 166 | + $history_url = SpecialPage::getTitleFor( 'PostHistory', $post->getID() ); |
| 167 | + $commands['history'] = array( |
| 168 | + 'label' => wfMsgExt( 'history_short', 'parseinline' ), |
| 169 | + 'href' => $history_url, |
| 170 | + 'enabled' => true, |
| 171 | + ); |
| 172 | + |
| 173 | + // TODO permissions checking |
| 174 | + $edit_url = SpecialPage::getTitleFor( 'EditPost', $post->getID() ); |
| 175 | + $commands['edit'] = array( |
| 176 | + 'label' => wfMsgExt( 'edit', 'parseinline' ), |
| 177 | + 'href' => $edit_url, |
| 178 | + 'enabled' => true |
| 179 | + ); |
| 180 | + |
| 181 | + if ( $context->get('user')->isAllowed( 'lqt-split' ) ) { |
| 182 | + $splitUrl = SpecialPage::getTitleFor( 'SplitThread', $post->getID() )->getFullURL(); |
| 183 | + $commands['split'] = array( |
| 184 | + 'label' => wfMsgExt( 'lqt-thread-split', 'parseinline' ), |
| 185 | + 'href' => $splitUrl, |
| 186 | + 'enabled' => true |
| 187 | + ); |
| 188 | + } |
| 189 | + |
| 190 | + // TODO implement merging |
| 191 | +// if ( $context->get('user')->isAllowed( 'lqt-merge' ) ) { |
| 192 | +// $mergeParams = $_GET; |
| 193 | +// $mergeParams['lqt_merge_from'] = $thread->id(); |
| 194 | +// |
| 195 | +// unset( $mergeParams['title'] ); |
| 196 | +// |
| 197 | +// $mergeUrl = $this->title->getLocalURL( wfArrayToCGI( $mergeParams ) ); |
| 198 | +// $label = wfMsgExt( 'lqt-thread-merge', 'parseinline' ); |
| 199 | +// |
| 200 | +// $commands['merge'] = array( |
| 201 | +// 'label' => $label, |
| 202 | +// 'href' => $mergeUrl, |
| 203 | +// 'enabled' => true |
| 204 | +// ); |
| 205 | +// } |
| 206 | + |
| 207 | + $commands['link'] = array( |
| 208 | + 'label' => wfMsgExt( 'lqt_permalink', 'parseinline' ), |
| 209 | + 'href' => SpecialPage::getTitleFor( 'Post', $post->getID() ), |
| 210 | + 'enabled' => true, |
| 211 | + 'showlabel' => true, |
| 212 | + 'tooltip' => wfMsgExt( 'lqt_permalink', 'parseinline' ) |
| 213 | + ); |
| 214 | + |
| 215 | + wfRunHooks( 'LiquidThreadsPostMinorCommands', |
| 216 | + array( $post, $version, $context, &$commands ) ); |
| 217 | + |
| 218 | + return $commands; |
| 219 | + } |
| 220 | +} |