http://www.mediawiki.org/wiki/Special:Code/MediaWiki/73604
Revision: 73604
Author: werdna
Date: 2010-09-23 14:12:57 +0000 (Thu, 23 Sep 2010)
Log Message:
-----------
LiquidThreads: Allow embedding threads and discussion pages in wikitext.
Modified Paths:
--------------
trunk/extensions/LiquidThreads/LiquidThreads.php
trunk/extensions/LiquidThreads/LqtFunctions.php
trunk/extensions/LiquidThreads/api/ApiThreadAction.php
trunk/extensions/LiquidThreads/classes/ParserFunctions.php
trunk/extensions/LiquidThreads/classes/View.php
trunk/extensions/LiquidThreads/lqt.js
trunk/extensions/LiquidThreads/pages/TalkpageView.php
Modified: trunk/extensions/LiquidThreads/LiquidThreads.php
===================================================================
--- trunk/extensions/LiquidThreads/LiquidThreads.php 2010-09-23 14:10:09 UTC
(rev 73603)
+++ trunk/extensions/LiquidThreads/LiquidThreads.php 2010-09-23 14:12:57 UTC
(rev 73604)
@@ -124,6 +124,10 @@
// $wgSpecialPages['HotTopics'] = 'SpecialHotTopics';
$wgSpecialPageGroups['NewMessages'] = 'wiki';
+// Embedding
+$wgHooks['OutputPageParserOutput'][] = 'LqtParserFunctions::onAddParserOutput';
+$wgHooks['OutputPageBeforeHTML'][] = 'LqtParserFunctions::onAddHTML';
+
// Classes
$wgAutoloadClasses['LqtDispatch'] = $dir . 'classes/Dispatch.php';
$wgAutoloadClasses['LqtView'] = $dir . 'classes/View.php';
@@ -248,3 +252,6 @@
in specific namespaces. NULL means either all or none, depending
on the above. */
$wgLiquidThreadsAllowUserControlNamespaces = null;
+
+/** Allow LiquidThreads embedding */
+$wgLiquidThreadsAllowEmbedding = true;
Modified: trunk/extensions/LiquidThreads/LqtFunctions.php
===================================================================
--- trunk/extensions/LiquidThreads/LqtFunctions.php 2010-09-23 14:10:09 UTC
(rev 73603)
+++ trunk/extensions/LiquidThreads/LqtFunctions.php 2010-09-23 14:12:57 UTC
(rev 73604)
@@ -47,6 +47,13 @@
'lqtpagelimit',
array( 'LqtParserFunctions', 'lqtPageLimit' )
);
+
+ global $wgLiquidThreadsAllowEmbedding;
+
+ if ($wgLiquidThreadsAllowEmbedding) {
+ $parser->setHook( 'talkpage', array( 'LqtParserFunctions',
'lqtTalkPage' ) );
+ $parser->setHook( 'thread', array( 'LqtParserFunctions',
'lqtThread' ) );
+ }
return true;
}
Modified: trunk/extensions/LiquidThreads/api/ApiThreadAction.php
===================================================================
--- trunk/extensions/LiquidThreads/api/ApiThreadAction.php 2010-09-23
14:10:09 UTC (rev 73603)
+++ trunk/extensions/LiquidThreads/api/ApiThreadAction.php 2010-09-23
14:12:57 UTC (rev 73604)
@@ -774,6 +774,35 @@
$this->getResult()->addValue( null, 'threadaction', $result );
}
+ public function actionInlineEditForm( $threads, $params ) {
+ $method = $talkpage = $operand = null;
+
+ if ( isset($params['method']) ) {
+ $method = $params['method'];
+ }
+
+ if ( isset( $params['talkpage'] ) ) {
+ $talkpage = $params['talkpage'];
+ }
+
+ if ( $talkpage ) {
+ $talkpage = new Article( Title::newFromText( $talkpage
) );
+ } else {
+ $talkpage = null;
+ }
+
+ if ( count($threads) ) {
+ $operand = $threads[0];
+ $operand = $operand->id();
+ }
+
+ $output = LqtView::getInlineEditForm( $talkpage, $method,
$operand );
+
+ $result = array( 'inlineeditform' => array( 'html' => $output )
);
+
+ $this->getResult()->addValue( null, 'threadaction', $result );
+ }
+
public function getDescription() {
return 'Allows actions to be taken on threads and posts in
threaded discussions.';
}
@@ -791,6 +820,7 @@
'edit' => 'actionEdit',
'addreaction' => 'actionAddReaction',
'deletereaction' => 'actionDeleteReaction',
+ 'inlineeditform' => 'actionInlineEditForm',
);
}
@@ -818,6 +848,7 @@
'NULL to specify the default signature',
'type' => 'Specifies the type of reaction to add',
'value' => 'Specifies the value associated with the
reaction to add',
+ 'method' => 'For getting inline edit forms, the method
to get a form for',
);
}
@@ -877,6 +908,8 @@
'signature' => null,
'type' => null,
'value' => null,
+ 'method' => null,
+ 'operand' => null,
);
}
Modified: trunk/extensions/LiquidThreads/classes/ParserFunctions.php
===================================================================
--- trunk/extensions/LiquidThreads/classes/ParserFunctions.php 2010-09-23
14:10:09 UTC (rev 73603)
+++ trunk/extensions/LiquidThreads/classes/ParserFunctions.php 2010-09-23
14:12:57 UTC (rev 73604)
@@ -19,4 +19,171 @@
$parser->mOutput->setProperty( 'lqt-page-limit', $param
);
}
}
+
+ /** To bypass the parser cache just for the LiquidThreads part, we have
a cute trick.
+ * We leave a placeholder comment in the HTML, which we expand out in
a hook. This way,
+ * most of the page can be cached, but the LiquidThreads dynamicism
still works.
+ * Thanks to Tim for the idea. */
+ static function lqtTalkPage( $parser, $args, $parser, $frame ) {
+ global $wgStyleVersion;
+
+ $pout = $parser->getOutput();
+
+ // Prepare information.
+ $title = null;
+ if ( $args['talkpage'] ) {
+ $title = Title::newFromText( $args['talkpage'] );
+ }
+ if ( is_null($title) ) {
+ $title = $parser->getTitle();
+ }
+
+ $talkpage = new Article( $title );
+ $article = new Article( $parser->getTitle() );
+
+ $data = array(
+ 'type' => 'talkpage',
+ 'args' => $args,
+ 'article' => $article,
+ 'title' => $article->getTitle(),
+ 'talkpage' => $talkpage,
+ );
+
+ if ( !isset( $pout->mLqtReplacements ) ) {
+ $pout->mLqtReplacements = array();
+ }
+
+ // Generate a token
+ $tok = wfGenerateToken();
+ $text = '<!--LQT-PAGE-'.$tok.'-->';
+ $pout->mLqtReplacements[$text] = $data;
+
+ return $text;
+ }
+
+ static function lqtThread( $parser, $args, $parser, $frame ) {
+ global $wgStyleVersion;
+
+ $pout = $parser->getOutput();
+
+ // Prepare information.
+ $title = Title::newFromText( $args['thread'] );
+ $thread = null;
+ if ( $args['thread'] ) {
+ if ( is_numeric( $args['thread'] ) ) {
+ $thread = Threads::withId( $args['thread'] );
+ } elseif ( $title ) {
+ $article = new Article( $title );
+ $thread = Threads::withRoot( $article );
+ }
+ }
+
+ if ( is_null( $thread ) ) {
+ return '';
+ }
+
+ $data = array(
+ 'type' => 'thread',
+ 'args' => $args,
+ 'thread' => $thread->id(),
+ 'title' => $thread->title(),
+ );
+
+ if ( !isset( $pout->mLqtReplacements ) ) {
+ $pout->mLqtReplacements = array();
+ }
+
+ // Generate a token
+ $tok = wfGenerateToken();
+ $text = '<!--LQT-THREAD-'.$tok.'-->';
+ $pout->mLqtReplacements[$text] = $data;
+
+ return $text;
+ }
+
+ static function runLqtTalkPage( $details ) {
+ extract($details);
+
+ global $wgUser, $wgRequest, $wgOut;
+ $oldOut = $wgOut->getHTML();
+ $wgOut->clearHTML();
+
+ $view = new TalkpageView( $wgOut, $article, $title, $wgUser,
$wgRequest );
+ $view->setTalkpage( $talkpage );
+
+ // Handle show/hide preferences. Header gone by default.
+ $view->hideItems( 'header' );
+
+ if ( array_key_exists( 'show', $args ) ) {
+ $show = explode( ' ', $args['show'] );
+ $view->setShownItems( $show );
+ }
+
+ $view->show();
+
+ $html = $wgOut->getHTML();
+ $wgOut->clearHTML();
+ $wgOut->getHTML( $oldOut );
+
+ return $html;
+ }
+
+ static function showLqtThread( $details ) {
+ extract($details);
+
+ global $wgUser, $wgRequest, $wgOut;
+ $oldOut = $wgOut->getHTML();
+ $wgOut->clearHTML();
+
+ $thread = Threads::withId( $thread );
+
+ $view = new LqtView( $wgOut, $article, $title, $wgUser,
$wgRequest );
+
+ $view->showThread( $thread );
+
+ $html = $wgOut->getHTML();
+ $wgOut->clearHTML();
+ $wgOut->getHTML( $oldOut );
+
+ return $html;
+ }
+
+ static function onAddParserOutput( &$out, $pout ) {
+ if ( !isset($pout->mLqtReplacements ) ) {
+ return true;
+ }
+
+ if ( !isset($out->mLqtReplacements) ) {
+ $out->mLqtReplacements = array();
+ }
+
+ $processedReplacements = array();
+ foreach( $pout->mLqtReplacements as $text => $details ) {
+ $result = '';
+
+ if ( $details['type'] == 'talkpage' ) {
+ $result = self::runLqtTalkPage( $details );
+ } elseif ( $details['type'] == 'thread' ) {
+ $result = self::showLqtThread( $details );
+ }
+
+ $out->mLqtReplacements[$text] = $result;
+ LqtView::addJsAndCss();
+ }
+
+ return true;
+ }
+
+ static function onAddHTML( &$out, &$text ) {
+ if ( !isset($out->mLqtReplacements) ||
!count($out->mLqtReplacements) ) {
+ return true;
+ }
+
+ $replacements = $out->mLqtReplacements;
+
+ $replacer = new ReplacementArray( $replacements );
+ $text = $replacer->replace( $text );
+
+ return true;
+ }
}
Modified: trunk/extensions/LiquidThreads/classes/View.php
===================================================================
--- trunk/extensions/LiquidThreads/classes/View.php 2010-09-23 14:10:09 UTC
(rev 73603)
+++ trunk/extensions/LiquidThreads/classes/View.php 2010-09-23 14:12:57 UTC
(rev 73604)
@@ -308,6 +308,13 @@
$operand = $this->request->getVal( 'lqt_operand' );
$thread = Threads::withId( intval( $operand ) );
+
+ // Yuck.
+ global $wgOut, $wgRequest;
+ $oldOut = $wgOut;
+ $oldRequest = $wgRequest;
+ $wgOut = $this->output;
+ $wgRequest = $this->request;
$hookResult = wfRunHooks( 'LiquidThreadsDoInlineEditForm',
array(
@@ -324,10 +331,41 @@
$this->showNewThreadForm( $this->article );
} elseif ( $method == 'edit' ) {
$this->showPostEditingForm( $thread );
+ } else {
+ throw new MWException( "Invalid thread method $method"
);
}
+
+ $wgOut = $oldOut;
+ $wgRequest = $oldRequest;
$this->output->setArticleBodyOnly( true );
}
+
+ static function getInlineEditForm( $talkpage, $method, $operand ) {
+ $output = new OutputPage;
+ $request = new FauxRequest( array() );
+ $title = null;
+
+ if ( $talkpage ) {
+ $title = $talkpage->getTitle();
+ } elseif ( $operand ) {
+ $thread = Threads::withId( $operand );
+ if ( $thread ) {
+ $talkpage = $thread->article();
+ $title = $talkpage->getTitle();
+ }
+ }
+
+ $request->setVal( 'lqt_method', $method );
+ $request->setVal( 'lqt_operand', $operand );
+
+ global $wgUser;
+ $view = new LqtView( $output, $talkpage, $title, $wgUser,
$request );
+
+ $view->doInlineEditForm();
+
+ return $output->getHTML();
+ }
function showNewThreadForm( $talkpage ) {
$submitted_nonce = $this->request->getVal( 'lqt_nonce' );
@@ -1931,6 +1969,14 @@
$thread->sortkey(),
array( 'id' => 'lqt-thread-sortkey-' .
$thread->id() )
);
+
+ $html .= Xml::hidden(
+ 'lqt-thread-talkpage-' . $thread->id(),
+
$thread->article()->getTitle()->getPrefixedText(),
+ array(
+ 'class' =>
'lqt-thread-talkpage-metadata',
+ )
+ );
}
if ( ! $thread->title() ) {
Modified: trunk/extensions/LiquidThreads/lqt.js
===================================================================
--- trunk/extensions/LiquidThreads/lqt.js 2010-09-23 14:10:09 UTC (rev
73603)
+++ trunk/extensions/LiquidThreads/lqt.js 2010-09-23 14:12:57 UTC (rev
73604)
@@ -25,7 +25,7 @@
return;
}
- var query = '&lqt_method=reply&lqt_operand='+thread_id;
+ var params = { 'method' : 'reply', 'thread' : thread_id };
var repliesElement =
$j(container).contents().filter('.lqt-thread-replies');
var replyDiv =
repliesElement.contents().filter('.lqt-reply-form');
@@ -45,7 +45,7 @@
replyDiv = replyDiv[0];
- liquidThreads.injectEditForm( query, replyDiv, e.preload );
+ liquidThreads.injectEditForm( params, replyDiv, e.preload );
liquidThreads.currentReplyThread = thread_id;
},
@@ -88,11 +88,12 @@
'handleNewLink' : function(e) {
e.preventDefault();
- var query = '&lqt_method=talkpage_new_thread';
+ var talkpage = $j(this).attr('lqt_talkpage');
+ var params = {'talkpage' : talkpage, 'method' :
'talkpage_new_thread' };
- var container = $j('.lqt-new-thread' );
+ var container = $j('.lqt-new-thread' ).data('lqt-talkpage',
talkpage);
- liquidThreads.injectEditForm( query, container );
+ liquidThreads.injectEditForm( params, container );
liquidThreads.currentReplyThread = 0;
},
@@ -105,14 +106,17 @@
var container = $j('<div/>').addClass('lqt-edit-form');
parent.contents().fadeOut();
parent.append(container);
- var
query='&lqt_method=edit&lqt_operand='+parent.data('thread-id');
+ var params = { 'method' : 'edit', 'thread' :
parent.data('thread-id') };
- liquidThreads.injectEditForm( query, container );
+ liquidThreads.injectEditForm( params, container );
},
- 'injectEditForm' : function(query, container, preload) {
- var url =
wgServer+wgScript+'?lqt_inline=1&title='+encodeURIComponent(wgPageName)+
- query;
+ 'injectEditForm' : function(params, container, preload) {
+ var page = $j(container).closest('.lqt-thread-topmost')
+ .find('.lqt-thread-talkpage-metadata').val();
+ if ( !page ) {
+ page = $j(container).data('lqt-talkpage');
+ }
liquidThreads.cancelEdit( container );
@@ -197,17 +201,23 @@
function() {
if ( isIE7 ) {
$j(container).empty().show();
- $j(container).load(wgServer+wgScript,
-
'title='+encodeURIComponent(wgPageName)+
- query+'&lqt_inline=1',
finishSetup );
- } else {
- $j(container).load(wgServer+wgScript,
-
'title='+encodeURIComponent(wgPageName)+
- query+'&lqt_inline=1',
finishSetup );
}
+ liquidThreads.loadInlineEditForm( params,
container, finishSetup );
} );
},
+
+ 'loadInlineEditForm' : function( params, container, callback ) {
+ params['action'] = 'threadaction';
+ params['threadaction'] = 'inlineeditform';
+
+ liquidThreads.apiRequest( params,
+ function(result) {
+ var content =
$j(result.threadaction.inlineeditform.html);
+ $j(container).empty().append(content);
+ callback();
+ } );
+ },
'doLivePreview' : function( e ) {
e.preventDefault();
@@ -952,7 +962,9 @@
e.preventDefault();
} else if ( type == 'talkpage_new_thread' ) {
- liquidThreads.doNewThread( wgPageName, subject, text,
summary,
+ var container = editform.closest('.lqt-new-thread');
+ var page = container.data('lqt-talkpage');
+ liquidThreads.doNewThread( page, subject, text, summary,
doneCallback, bump, signature );
e.preventDefault();
Modified: trunk/extensions/LiquidThreads/pages/TalkpageView.php
===================================================================
--- trunk/extensions/LiquidThreads/pages/TalkpageView.php 2010-09-23
14:10:09 UTC (rev 73603)
+++ trunk/extensions/LiquidThreads/pages/TalkpageView.php 2010-09-23
14:12:57 UTC (rev 73604)
@@ -2,6 +2,19 @@
if ( !defined( 'MEDIAWIKI' ) ) die;
class TalkpageView extends LqtView {
+ protected $mShowItems = array( 'toc', 'options', 'header' );
+ protected $talkpage;
+
+ function __construct( &$output, &$article, &$title, &$user, &$request )
{
+ parent::__construct( $output, $article, $title, $user, $request
);
+
+ $this->talkpage = $article;
+ }
+
+ function setTalkPage($tp) {
+ $this->talkpage = $tp;
+ }
+
/* Added to SkinTemplateTabs hook in TalkpageView::show(). */
static function customizeTalkpageTabs( $skintemplate,
&$content_actions, $view ) {
// The arguments are passed in by reference.
@@ -262,7 +275,9 @@
$this->output->redirect( $url );
}
- $this->showHeader();
+ if ( $this->shouldShow('header') ) {
+ $this->showHeader();
+ }
$html = '';
@@ -274,16 +289,18 @@
$newThreadText = wfMsgExt( 'lqt_new_thread',
'parseinline' );
$newThreadLink = $sk->link(
$this->title, $newThreadText,
- array( ),
+ array( 'lqt_talkpage' =>
$this->talkpage->getTitle()->getPrefixedText() ),
array( 'lqt_method' => 'talkpage_new_thread' ),
array( 'known' )
);
- $talkpageHeader .= Xml::tags(
+ $newThreadLink = Xml::tags(
'strong',
array( 'class' => 'lqt_start_discussion' ),
$newThreadLink
);
+
+ $talkpageHeader .= $newThreadLink;
}
$talkpageHeader .= $this->getSearchBox();
@@ -294,7 +311,11 @@
$talkpageHeader
);
- $this->output->addHTML( $talkpageHeader );
+ if ( $this->shouldShow('options') ) {
+ $this->output->addHTML( $talkpageHeader );
+ } elseif ( $this->shouldShow('simplenew') ) {
+ $this->output->addHTML( $newThreadLink );
+ }
if ( $this->methodApplies( 'talkpage_new_thread' ) ) {
$params = array( 'class' => 'lqt-new-thread
lqt-edit-form' );
@@ -310,9 +331,9 @@
$threads = $this->getPageThreads( $pager );
- if ( count( $threads ) > 0 ) {
+ if ( count( $threads ) > 0 && $this->shouldShow('toc') ) {
$html .= $this->getTOC( $threads );
- } else {
+ } elseif ( count($threads) == 0 ) {
$html .= Xml::tags( 'div', array( 'class' =>
'lqt-no-threads' ),
wfMsgExt( 'lqt-no-threads',
'parseinline' ) );
}
@@ -363,7 +384,7 @@
function getPager() {
$sortType = $this->getSortType();
- return new LqtDiscussionPager( $this->article, $sortType );
+ return new LqtDiscussionPager( $this->talkpage, $sortType );
}
function getPageThreads( $pager ) {
@@ -390,6 +411,28 @@
// Default
return LQT_NEWEST_CHANGES;
}
+
+ // Hide a number of items from the view
+ // Valid values: toc, options, header
+ function hideItems( $items ) {
+ $this->mShowItems = array_diff( $this->mShowItems,
(array)$items );
+ }
+
+ // Show a number of items in the view
+ // Valid values: toc, options, header
+ function showItems( $items ) {
+ $this->mShowItems = array_merge( $this->mShowItems,
(array)$items );
+ }
+
+ // Whether or not to show an item
+ function shouldShow( $item ) {
+ return in_array( $item, $this->mShowItems );
+ }
+
+ // Set the items shown
+ function setShownItems( $items ) {
+ $this->mShowItems = $items;
+ }
}
class LqtDiscussionPager extends IndexPager {
_______________________________________________
MediaWiki-CVS mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-cvs