This is needed to fix bug 41706 and similar, watch for follow-ups.
Automatic, implicit conversion may be handy in several cases, especially
for converting between different text based content models. E.g. it should
be possible to create a diff between a JavaScript and a wikitext page. This
change lais the foundations for this ability.
Change-Id: Ie7d87b67b24ac9897cb5696220a7785b228d3c79
$modeName: the requested content model name
&$handler: set this to a ContentHandler object, if desired.
+'ConvertContent': Called by AbstractContent::convert when a conversion to another
+content model is requested.
+$content: The Content object to be converted.
+$toModel: The ID of the content model to convert to.
+$lossy: boolean indicating whether lossy conversion is allowed.
+&$result: Output parameter, in case the handler function wants to provide a
+converted Content object. Note that $result->getContentModel() must return $toModel.
+Handler functions that modify $result should generally return false to further
+attempts at conversion.
+
'ContribsPager::getQueryInfo': Before the contributions query is about to run
&$pager: Pager object for contributions
&$queryInfo: The query for the contribs Pager
public function matchMagicWord( MagicWord $word ) {
return false;
}
+
+ /**
+ * @see Content::convert()
+ *
+ * This base implementation calls the hook ConvertContent to enable custom conversions.
+ * Subclasses may override this to implement conversion for "their" content model.
+ *
+ * @param String $toModel the desired content model, use the CONTENT_MODEL_XXX flags.
+ * @param String $lossy flag, set to "lossy" to allow lossy conversion. If lossy conversion is
+ * not allowed, full round-trip conversion is expected to work without losing information.
+ *
+ * @return Content|bool A content object with the content model $toModel, or false if
+ * that conversion is not supported.
+ */
+ public function convert( $toModel, $lossy = '' ) {
+ if ( $this->getModel() === $toModel ) {
+ //nothing to do, shorten out.
+ return $this;
+ }
+
+ $lossy = ( $lossy === 'lossy' ); // string flag, convert to boolean for convenience
+ $result = false;
+
+ wfRunHooks( 'ConvertContent', array( $this, $toModel, $lossy, &$result ) );
+ return $result;
+ }
}
/**
* @since 1.21
*
- * @return string The wikitext to include when another page includes this
+ * @return string|false The wikitext to include when another page includes this
* content, or false if the content is not includable in a wikitext page.
*
* @todo allow native handling, bypassing wikitext representation, like
*/
public function matchMagicWord( MagicWord $word );
- // TODO: ImagePage and CategoryPage interfere with per-content action handlers
+ /**
+ * Converts this content object into another content object with the given content model,
+ * if that is possible.
+ *
+ * @param String $toModel the desired content model, use the CONTENT_MODEL_XXX flags.
+ * @param String $lossy flag, set to "lossy" to allow lossy conversion. If lossy conversion is
+ * not allowed, full round-trip conversion is expected to work without losing information.
+ *
+ * @return Content|bool A content object with the content model $toModel, or false if
+ * that conversion is not supported.
+ */
+ public function convert( $toModel, $lossy = '' );
+
+ // TODO: ImagePage and CategoryPage interfere with per-content action handlers
// TODO: nice&sane integration of GeSHi syntax highlighting
// [11:59] <vvv> Hooks are ugly; make CodeHighlighter interface and a
// config to set the class which handles syntax highlighting
}
/**
- * Returns the text represented by this Content object, as a string.
+ * Returns attempts to convert this content object to wikitext,
+ * and then returns the text string. The conversion may be lossy.
*
- * @return string: the raw text
+ * @note: this allows any text-based content to be transcluded as if it was wikitext.
+ *
+ * @return string|false: the raw text, or null if the conversion failed
*/
public function getWikitextForTransclusion( ) {
- return $this->getNativeData();
+ $wikitext = $this->convert( CONTENT_MODEL_WIKITEXT, 'lossy' );
+
+ if ( $wikitext ) {
+ return $wikitext->getNativeData();
+ } else {
+ return false;
+ }
}
/**
# TODO: make Highlighter interface, use highlighter here, if available
return htmlspecialchars( $this->getNativeData() );
}
+
+ /**
+ * @see Content::convert()
+ *
+ * This implementation provides lossless conversion between content models based
+ * on TextContent.
+ *
+ * @param String $toModel the desired content model, use the CONTENT_MODEL_XXX flags.
+ * @param String $lossy flag, set to "lossy" to allow lossy conversion. If lossy conversion is
+ * not allowed, full round-trip conversion is expected to work without losing information.
+ *
+ * @return Content|bool A content object with the content model $toModel, or false if
+ * that conversion is not supported.
+ */
+ public function convert( $toModel, $lossy = '' ) {
+ $converted = parent::convert( $toModel, $lossy );
+
+ if ( $converted !== false ) {
+ return $converted;
+ }
+
+ $toHandler = ContentHandler::getForModelID( $toModel );
+
+ if ( $toHandler instanceof TextContentHandler ) {
+ //NOTE: ignore content serialization format - it's just text anyway.
+ $text = $this->getNativeData();
+ $converted = $toHandler->unserializeContent( $text );
+ }
+
+ return $converted;
+ }
}
}
}
+ public static function provideConvert() {
+ return array(
+ array( // #0
+ 'Hallo Welt',
+ CONTENT_MODEL_WIKITEXT,
+ 'lossless',
+ 'Hallo Welt'
+ ),
+ array( // #1
+ 'Hallo Welt',
+ CONTENT_MODEL_WIKITEXT,
+ 'lossless',
+ 'Hallo Welt'
+ ),
+ array( // #1
+ 'Hallo Welt',
+ CONTENT_MODEL_CSS,
+ 'lossless',
+ 'Hallo Welt'
+ ),
+ array( // #1
+ 'Hallo Welt',
+ CONTENT_MODEL_JAVASCRIPT,
+ 'lossless',
+ 'Hallo Welt'
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideConvert
+ */
+ public function testConvert( $text, $model, $lossy, $expectedNative ) {
+ $content = $this->newContent( $text );
+
+ $converted = $content->convert( $model, $lossy );
+
+ if ( $expectedNative === false ) {
+ $this->assertFalse( $converted, "conversion to $model was expected to fail!" );
+ } else {
+ $this->assertInstanceOf( 'Content', $converted );
+ $this->assertEquals( $expectedNative, $converted->getNativeData() );
+ }
+ }
+
}