From: daniel Date: Tue, 16 Oct 2012 10:38:20 +0000 (+0200) Subject: Introducing ContentGetParserOutput hook. X-Git-Tag: 1.31.0-rc.0~19500 X-Git-Url: http://git.cyclocoop.org/%7B%24admin_url%7Dcompta/comptes/journal.php?a=commitdiff_plain;h=fda090a7e7f85f146ec84798fda45232ab67613e;p=lhc%2Fweb%2Fwiklou.git Introducing ContentGetParserOutput hook. This hooks allows extensions to override the normal model-specific rendering of page content. A typical use would be to provide syntax highlighting for pages that contain scripts. In that sense, ContentGetParserOutput is a generalization of the old ShowRawCssJs hook. Change-Id: Ibfb2cbefea44eeee9f2a027f47e7721bf177ba0f --- diff --git a/docs/hooks.txt b/docs/hooks.txt index 66b5068244..02c9fad1b2 100644 --- a/docs/hooks.txt +++ b/docs/hooks.txt @@ -801,6 +801,19 @@ content model name, but no entry for that model exists in $wgContentHandlers. $modeName: the requested content model name &$handler: set this to a ContentHandler object, if desired. +'ContentGetParserOutput': Customize parser output for a given content object, +called by AbstractContent::getParserOutput. May be used to override the normal +model-specific rendering of page content. +$content: The Content to render +$title: Title of the page, as context +$revId: The revision ID, as context +$options: ParserOptions for rendering. To avoid confusing the parser cache, +the output can only depend on parameters provided to this hook function, not on global state. +$generateHtml: boolean, indicating whether full HTML should be generated. If false, +generation of HTML may be skipped, but other information should still be present in the +ParserOutput object. +&$output: ParserOutput, to manipulate or replace + 'ConvertContent': Called by AbstractContent::convert when a conversion to another content model is requested. $content: The Content object to be converted. @@ -1994,7 +2007,7 @@ $title : Current Title object being displayed in search results. $article: The article object corresponding to the page 'ShowRawCssJs': Customise the output of raw CSS and JavaScript in page views. -DEPRECATED, use the ContentHandler facility to handle CSS and JavaScript! +DEPRECATED, use the ContentGetParserOutput hook instead! $text: Text being shown $title: Title of the custom script/stylesheet page $output: Current OutputPage object diff --git a/includes/content/AbstractContent.php b/includes/content/AbstractContent.php index 137efb8a49..8c6e24a619 100644 --- a/includes/content/AbstractContent.php +++ b/includes/content/AbstractContent.php @@ -441,4 +441,57 @@ abstract class AbstractContent implements Content { wfRunHooks( 'ConvertContent', array( $this, $toModel, $lossy, &$result ) ); return $result; } + + /** + * Returns a ParserOutput object, filled by a call to fillParserOutput(). + * Subclasses that want to control the parser output may override this, or + * they can override fillParserOutput(). If they override getParserOutput(), + * itself, they should take care to call the ContentGetParserOutput hook. + * + * @param $title Title Context title for parsing + * @param $revId int|null Revision ID (for {{REVISIONID}}) + * @param $options ParserOptions|null Parser options + * @param $generateHtml bool Whether or not to generate HTML + * + * @return ParserOutput representing the HTML form of the text + */ + public function getParserOutput( Title $title, $revId = null, + ParserOptions $options = null, $generateHtml = true + ) { + # Generic implementation, relying on $this->getHtml() + + if ( $options === null ) { + $options = $this->getContentHandler()->makeParserOptions( 'canonical' ); + } + + $po = new ParserOutput(); + + if ( wfRunHooks( 'ContentGetParserOutput', + array( $this, $title, $revId, $options, $generateHtml, &$po ) ) ) { + + $this->fillParserOutput( $title, $revId, $options, $generateHtml, $po ); + } + + return $po; + } + + /** + * Fills the provided ParserOutput object with the HTML returned by getHtml(). + * Subclasses should override this (or getParserOutput) appropriately. + * This placeholder implementation always throws an exception. + * + * @param $title Title Context title for parsing + * @param $revId int|null Revision ID (for {{REVISIONID}}) + * @param $options ParserOptions|null Parser options + * @param $generateHtml bool Whether or not to generate HTML + * @param &$output ParserOutput The output object to fill (reference). + * + * @throws MWException + */ + protected function fillParserOutput( Title $title, $revId, + ParserOptions $options, $generateHtml, ParserOutput &$output + ) { + // Don't make abstract, so subclasses that override getParserOutput() directly don't fail. + throw new MWException( 'Subclasses of AbstractContent must override fillParserOutput!' ); + } } diff --git a/includes/content/CssContent.php b/includes/content/CssContent.php index 03cc2d005c..a25bd76662 100644 --- a/includes/content/CssContent.php +++ b/includes/content/CssContent.php @@ -57,7 +57,7 @@ class CssContent extends TextContent { protected function getHtml() { $html = ""; $html .= "
\n";
-		$html .= $this->getHighlightHtml();
+		$html .= htmlspecialchars( $this->getNativeData() );
 		$html .= "\n
\n"; return $html; diff --git a/includes/content/JavaScriptContent.php b/includes/content/JavaScriptContent.php index 2ae572bec0..247de6d265 100644 --- a/includes/content/JavaScriptContent.php +++ b/includes/content/JavaScriptContent.php @@ -58,7 +58,7 @@ class JavaScriptContent extends TextContent { protected function getHtml() { $html = ""; $html .= "
\n";
-		$html .= $this->getHighlightHtml();
+		$html .= htmlspecialchars( $this->getNativeData() );
 		$html .= "\n
\n"; return $html; diff --git a/includes/content/TextContent.php b/includes/content/TextContent.php index f66dacd7c1..a6ee7b0ead 100644 --- a/includes/content/TextContent.php +++ b/includes/content/TextContent.php @@ -189,32 +189,27 @@ class TextContent extends AbstractContent { } /** - * Returns a generic ParserOutput object, wrapping the HTML returned by - * getHtml(). + * Fills the provided ParserOutput object with the HTML returned by getHtml(). + * + * Content models in $wgTextModelsToParse will be parsed as wikitext to process links, + * magic words, etc. + * + * Subclasses may override this to provide custom rendering. * * @param $title Title Context title for parsing * @param int|null $revId Revision ID (for {{REVISIONID}}) * @param $options ParserOptions|null Parser options * @param bool $generateHtml Whether or not to generate HTML - * - * @return ParserOutput representing the HTML form of the text + * @param $output ParserOutput The output object to fill (reference). */ - public function getParserOutput( Title $title, - $revId = null, - ParserOptions $options = null, $generateHtml = true + protected function fillParserOutput( Title $title, $revId, + ParserOptions $options, $generateHtml, ParserOutput &$output ) { global $wgParser, $wgTextModelsToParse; - if ( !$options ) { - //NOTE: use canonical options per default to produce cacheable output - $options = $this->getContentHandler()->makeParserOptions( 'canonical' ); - } - if ( in_array( $this->getModel(), $wgTextModelsToParse ) ) { - // parse just to get links etc into the database - $po = $wgParser->parse( $this->getNativeData(), $title, $options, true, true, $revId ); - } else { - $po = new ParserOutput(); + // parse just to get links etc into the database, HTML is replaced below. + $output = $wgParser->parse( $this->getNativeData(), $title, $options, true, true, $revId ); } if ( $generateHtml ) { @@ -223,34 +218,25 @@ class TextContent extends AbstractContent { $html = ''; } - $po->setText( $html ); - return $po; + $output->setText( $html ); } /** * Generates an HTML version of the content, for display. Used by * getParserOutput() to construct a ParserOutput object. * - * This default implementation just calls getHighlightHtml(). Content - * models that have another mapping to HTML (as is the case for markup - * languages like wikitext) should override this method to generate the - * appropriate HTML. + * This default implementation runs the text returned by $this->getNativeData() + * through htmlspecialchars and tried to convert line breaks and indentation to HTML.. * * @return string An HTML representation of the content */ - protected function getHtml() { - return $this->getHighlightHtml(); - } - - /** - * Generates a syntax-highlighted version of the content, as HTML. - * Used by the default implementation of getHtml(). - * - * @return string an HTML representation of the content's markup - */ - protected function getHighlightHtml() { - # TODO: make Highlighter interface, use highlighter here, if available - return htmlspecialchars( $this->getNativeData() ); + public static function convertWhiteSpaceToHTML( $msg ) { + $msg = htmlspecialchars( $msg ); + $msg = preg_replace( '/^ /m', ' ', $msg ); + $msg = preg_replace( '/ $/m', ' ', $msg ); + $msg = preg_replace( '/ /', '  ', $msg ); + $msg = str_replace( "\n", '
', $msg ); + return $msg; } /** diff --git a/includes/content/WikitextContent.php b/includes/content/WikitextContent.php index 26337db947..d821d9d75d 100644 --- a/includes/content/WikitextContent.php +++ b/includes/content/WikitextContent.php @@ -277,28 +277,21 @@ class WikitextContent extends TextContent { * using $wgParser. * * @since 1.21 + * @see AbstractContent::fillParserOutput(). * * @param $title Title * @param int $revId Revision to pass to the parser (default: null) * @param $options ParserOptions (default: null) * @param bool $generateHtml (default: false) - * - * @internal param \IContextSource|null $context - * @return ParserOutput representing the HTML form of the text + * @param &$output ParserOutput representing the HTML form of the text, + * may be manipulated or replaced. */ - public function getParserOutput( Title $title, - $revId = null, - ParserOptions $options = null, $generateHtml = true + protected function fillParserOutput( Title $title, $revId, + ParserOptions $options, $generateHtml, ParserOutput &$output ) { global $wgParser; - if ( !$options ) { - //NOTE: use canonical options per default to produce cacheable output - $options = $this->getContentHandler()->makeParserOptions( 'canonical' ); - } - - $po = $wgParser->parse( $this->getNativeData(), $title, $options, true, true, $revId ); - return $po; + $output = $wgParser->parse( $this->getNativeData(), $title, $options, true, true, $revId ); } protected function getHtml() { diff --git a/tests/phpunit/includes/content/ContentHandlerTest.php b/tests/phpunit/includes/content/ContentHandlerTest.php index c3455133e2..29044726b1 100644 --- a/tests/phpunit/includes/content/ContentHandlerTest.php +++ b/tests/phpunit/includes/content/ContentHandlerTest.php @@ -431,4 +431,18 @@ class DummyContentForTesting extends AbstractContent { public function getParserOutput( Title $title, $revId = null, ParserOptions $options = null, $generateHtml = true ) { return new ParserOutput( $this->getNativeData() ); } + + /** + * @see AbstractContent::fillParserOutput() + * + * @param $title Title Context title for parsing + * @param $revId int|null Revision ID (for {{REVISIONID}}) + * @param $options ParserOptions|null Parser options + * @param $generateHtml bool Whether or not to generate HTML + * @param $output ParserOutput The output object to fill (reference). + */ + protected function fillParserOutput( Title $title, $revId, + ParserOptions $options, $generateHtml, ParserOutput &$output ) { + $output = new ParserOutput( $this->getNativeData() ); + } } diff --git a/tests/phpunit/includes/content/CssContentTest.php b/tests/phpunit/includes/content/CssContentTest.php index 1c458203c7..61716f9b5b 100644 --- a/tests/phpunit/includes/content/CssContentTest.php +++ b/tests/phpunit/includes/content/CssContentTest.php @@ -5,7 +5,7 @@ * @group Database * ^--- needed, because we do need the database to test link updates */ -class CssContentTest extends MediaWikiTestCase { +class CssContentTest extends JavaScriptContentTest { protected function setUp() { parent::setUp(); diff --git a/tests/phpunit/includes/content/TextContentTest.php b/tests/phpunit/includes/content/TextContentTest.php index c7138b7dde..d7dde37e9b 100644 --- a/tests/phpunit/includes/content/TextContentTest.php +++ b/tests/phpunit/includes/content/TextContentTest.php @@ -7,14 +7,21 @@ */ class TextContentTest extends MediaWikiLangTestCase { protected $context; + protected $savedContentGetParserOutput; protected function setUp() { + global $wgHooks; + parent::setUp(); // Anon user $user = new User(); $user->setName( '127.0.0.1' ); + $this->context = new RequestContext( new FauxRequest() ); + $this->context->setTitle( Title::newFromText( 'Test' ) ); + $this->context->setUser( $user ); + $this->setMwGlobals( array( 'wgUser' => $user, 'wgTextModelsToParse' => array( @@ -26,9 +33,22 @@ class TextContentTest extends MediaWikiLangTestCase { 'wgAlwaysUseTidy' => false, ) ); - $this->context = new RequestContext( new FauxRequest() ); - $this->context->setTitle( Title::newFromText( 'Test' ) ); - $this->context->setUser( $user ); + // bypass hooks that force custom rendering + if ( isset( $wgHooks['ContentGetParserOutput'] ) ) { + $this->savedContentGetParserOutput = $wgHooks['ContentGetParserOutput']; + unset( $wgHooks['ContentGetParserOutput'] ); + } + } + + public function teardown() { + global $wgHooks; + + // restore hooks that force custom rendering + if ( $this->savedContentGetParserOutput !== null ) { + $wgHooks['ContentGetParserOutput'] = $this->savedContentGetParserOutput; + } + + parent::teardown(); } public function newContent( $text ) {