*/
$wgContentHandlerUseDB = false;
+/**
+ * Determines which types of text are parsed as wikitext. This does not imply that these kinds
+ * of texts are also rendered as wikitext, it only means that links, magic words, etc will have
+ * the effect on the database they would have on a wikitext page.
+ *
+ * @todo: On the long run, it would be nice to put categories etc into a separate structure,
+ * or at least parse only the contents of comments in the scripts.
+ *
+ * @since 1.21
+ */
+$wgTextModelsToParse = array(
+ CONTENT_MODEL_WIKITEXT, // Just for completeness, wikitext will always be parsed.
+ CONTENT_MODEL_JAVASCRIPT, // Make categories etc work, people put them into comments.
+ CONTENT_MODEL_CSS, // Make categories etc work, people put them into comments.
+);
+
/**
* Whether the user must enter their password to change their e-mail address
*
$content = $this->getContentObject();
# Use the normal message if there's nothing to display
- if ( $this->firsttime && $content->isEmpty() ) {
+ if ( $this->firsttime && ( $content === false || $content->isEmpty() ) ) {
$action = $this->mTitle->exists() ? 'edit' :
( $this->mTitle->isTalkPage() ? 'createtalk' : 'createpage' );
throw new PermissionsError( $action, $permErrors );
}
/**
- * Gets an editable textual representation of the given Content object.
+ * Gets an editable textual representation of $content.
* The textual representation can be turned by into a Content object by the
* toEditContent() method.
*
+ * If $content is null or false or a string, $content is returned unchanged.
+ *
* If the given Content object is not of a type that can be edited using the text base EditPage,
* an exception will be raised. Set $this->allowNonTextContent to true to allow editing of non-textual
* content.
*
- * @param Content $content
+ * @param Content|null|false|string $content
* @return String the editable text form of the content.
*
* @throws MWException if $content is not an instance of TextContent and $this->allowNonTextContent is not true.
*/
- protected function toEditText( Content $content ) {
+ protected function toEditText( $content ) {
+ if ( $content === null || $content === false ) {
+ return $content;
+ }
+
+ if ( is_string( $content ) ) {
+ return $content;
+ }
+
if ( !$this->allowNonTextContent && !( $content instanceof TextContent ) ) {
throw new MWException( "This content model can not be edited as text: "
. ContentHandler::getLocalizedName( $content->getModel() ) );
$this->section, $textboxContent,
$this->summary, $this->edittime );
- ContentHandler::runLegacyHooks( 'EditPageGetDiffText', array( $this, &$newContent ) );
- wfRunHooks( 'EditPageGetDiffContent', array( $this, &$newContent ) );
+ if ( $newContent ) {
+ ContentHandler::runLegacyHooks( 'EditPageGetDiffText', array( $this, &$newContent ) );
+ wfRunHooks( 'EditPageGetDiffContent', array( $this, &$newContent ) );
- $popts = ParserOptions::newFromUserAndLang( $wgUser, $wgContLang );
- $newContent = $newContent->preSaveTransform( $this->mTitle, $wgUser, $popts );
+ $popts = ParserOptions::newFromUserAndLang( $wgUser, $wgContLang );
+ $newContent = $newContent->preSaveTransform( $this->mTitle, $wgUser, $popts );
+ }
if ( ( $oldContent && !$oldContent->isEmpty() ) || ( $newContent && !$newContent->isEmpty() ) ) {
$oldtitle = wfMessage( $oldtitlemsg )->parse();
$newtitle = wfMessage( 'yourtext' )->parse();
+ if ( !$oldContent ) {
+ $oldContent = $newContent->getContentHandler()->makeEmptyContent();
+ }
+
+ if ( !$newContent ) {
+ $newContent = $oldContent->getContentHandler()->makeEmptyContent();
+ }
+
$de = $oldContent->getContentHandler()->createDifferenceEngine( $this->mArticle->getContext() );
$de->setContent( $oldContent, $newContent );
return $this->getNativeData();
}
+ /**
+ * Returns a Content object with pre-save transformations applied.
+ * This implementation just trims trailing whitespace.
+ *
+ * @param $title Title
+ * @param $user User
+ * @param $popts ParserOptions
+ * @return Content
+ */
+ public function preSaveTransform( Title $title, User $user, ParserOptions $popts ) {
+ $text = $this->getNativeData();
+ $pst = rtrim( $text );
+
+ return ( $text === $pst ) ? $this : new WikitextContent( $pst );
+ }
+
/**
* Diff this content object with another content object..
*
$revId = null,
ParserOptions $options = null, $generateHtml = true
) {
- # Generic implementation, relying on $this->getHtml()
+ 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();
+ }
if ( $generateHtml ) {
$html = $this->getHtml();
$html = '';
}
- $po = new ParserOutput( $html );
+ $po->setText( $html );
return $po;
}
$text = $this->getNativeData();
$pst = $wgParser->preSaveTransform( $text, $title, $user, $popts );
+ rtrim( $pst );
- return new WikitextContent( $pst );
+ return ( $text === $pst ) ? $this : new WikitextContent( $pst );
}
/**
foreach ( $params['srcs'] as $src ) {
$source = $this->resolveToFSPath( $src );
- if ( $source === null ) {
- $fsFiles[$src] = null; // invalid path
+ if ( $source === null || !is_file( $source ) ) {
+ $fsFiles[$src] = null; // invalid path or file does not exist
} else {
$fsFiles[$src] = new FSFile( $source );
}
} else {
$tmpPath = $tmpFile->getPath();
// Copy the source file over the temp file
+ wfSuppressWarnings();
$ok = copy( $source, $tmpPath );
+ wfRestoreWarnings();
if ( !$ok ) {
$tmpFiles[$src] = null;
} else {
* @return array
*/
public function getDescLinkAttribs( $title = null, $params = '' ) {
- $query = $this->page ? ( 'page=' . urlencode( $this->page ) ) : '';
+ $query = '';
+ if ( $this->page && $this->page !== 1 ) {
+ $query = 'page=' . urlencode( $this->page );
+ }
if( $params ) {
$query .= $query ? '&'.$params : $params;
}
public function dataGetParserOutput() {
return array(
- array("MediaWiki:Test.css", null, "hello <world>\n",
- "<pre class=\"mw-code mw-css\" dir=\"ltr\">\nhello <world>\n\n</pre>"),
+ array(
+ "MediaWiki:Test.css",
+ null,
+ "hello <world>\n",
+ "<pre class=\"mw-code mw-css\" dir=\"ltr\">\nhello <world>\n\n</pre>" ),
+
+ array(
+ "MediaWiki:Test.css",
+ null,
+ "/* hello [[world]] */\n",
+ "<pre class=\"mw-code mw-css\" dir=\"ltr\">\n/* hello [[world]] */\n\n</pre>",
+ array( 'Links' => array( // NOTE: assumes default settings for $wgTextModelsToParse
+ array( 'World' => 0 ) ) ) ),
+
// @todo: more...?
);
}
public function dataGetParserOutput() {
return array(
- array("MediaWiki:Test.js", null, "hello <world>\n",
- "<pre class=\"mw-code mw-js\" dir=\"ltr\">\nhello <world>\n\n</pre>"),
+ array(
+ "MediaWiki:Test.js",
+ null,
+ "hello <world>\n",
+ "<pre class=\"mw-code mw-js\" dir=\"ltr\">\nhello <world>\n\n</pre>" ),
+
+ array(
+ "MediaWiki:Test.js",
+ null,
+ "hello(); // [[world]]\n",
+ "<pre class=\"mw-code mw-js\" dir=\"ltr\">\nhello(); // [[world]]\n\n</pre>",
+ array( 'Links' => array( // NOTE: assumes default settings for $wgTextModelsToParse
+ array( 'World' => 0 ) ) ) ),
+
// @todo: more...?
);
}
array( 'hello \'\'this\'\' is <nowiki>~~~</nowiki>',
'hello \'\'this\'\' is <nowiki>~~~</nowiki>',
),
+ array( " Foo \n ",
+ " Foo",
+ ),
);
}
public function dataGetParserOutput() {
return array(
- array("TextContentTest_testGetParserOutput", CONTENT_MODEL_TEXT, "hello ''world'' & stuff\n", "hello ''world'' & stuff"),
+ array(
+ "TextContentTest_testGetParserOutput",
+ CONTENT_MODEL_TEXT,
+ "hello ''world'' & [[stuff]]\n", "hello ''world'' & [[stuff]]",
+ array( 'Links' => array() ) ),
// @todo: more...?
);
}
/**
* @dataProvider dataGetParserOutput
*/
- public function testGetParserOutput( $title, $model, $text, $expectedHtml ) {
+ public function testGetParserOutput( $title, $model, $text, $expectedHtml, $expectedFields = null ) {
$title = Title::newFromText( $title );
$content = ContentHandler::makeContent( $text, $title, $model );
$html = preg_replace( '#<!--.*?-->#sm', '', $html ); // strip comments
$this->assertEquals( $expectedHtml, trim( $html ) );
+
+ if ( $expectedFields ) {
+ foreach ( $expectedFields as $field => $exp ) {
+ $f = 'get' . ucfirst( $field );
+ $v = call_user_func( array( $po, $f ) );
+
+ if ( is_array( $exp ) ) {
+ $this->assertArrayEquals( $exp, $v );
+ } else {
+ $this->assertEquals( $exp, $v );
+ }
+ }
+ }
+
// @todo: assert more properties
}
public function dataPreSaveTransform() {
return array(
- array( 'hello this is ~~~',
- "hello this is ~~~",
+ array( #0: no signature resolution
+ "hello this is ~~~",
+ "hello this is ~~~",
+ ),
+ array( #1: rtrim
+ " Foo \n ",
+ " Foo",
),
);
}
public function dataGetSecondaryDataUpdates() {
return array(
- array("WikitextContentTest_testGetSecondaryDataUpdates_1",
+ array( "WikitextContentTest_testGetSecondaryDataUpdates_1",
CONTENT_MODEL_WIKITEXT, "hello ''world''\n",
array( 'LinksUpdate' => array( 'mRecursive' => true,
'mLinks' => array() ) )
),
- array("WikitextContentTest_testGetSecondaryDataUpdates_2",
+ array( "WikitextContentTest_testGetSecondaryDataUpdates_2",
CONTENT_MODEL_WIKITEXT, "hello [[world test 21344]]\n",
array( 'LinksUpdate' => array( 'mRecursive' => true,
'mLinks' => array( array( 'World_test_21344' => 0 ) ) ) )
array( 'hello \'\'this\'\' is <nowiki>~~~</nowiki>',
'hello \'\'this\'\' is <nowiki>~~~</nowiki>',
),
+ array( // rtrim
+ " Foo \n ",
+ " Foo",
+ ),
);
}
return $cases;
}
+ public function testGetLocalCopyAndReference404() {
+ $this->backend = $this->singleBackend;
+ $this->tearDownFiles();
+ $this->doTestGetLocalCopyAndReference404();
+ $this->tearDownFiles();
+
+ $this->backend = $this->multiBackend;
+ $this->tearDownFiles();
+ $this->doTestGetLocalCopyAndReference404();
+ $this->tearDownFiles();
+ }
+
+ public function doTestGetLocalCopyAndReference404() {
+ $backendName = $this->backendClass();
+
+ $base = self::baseStorePath();
+
+ $tmpFile = $this->backend->getLocalCopy( array(
+ 'src' => "$base/unittest-cont1/not-there" ) );
+ $this->assertEquals( null, $tmpFile, "Local copy of not existing file is null ($backendName)." );
+
+ $tmpFile = $this->backend->getLocalReference( array(
+ 'src' => "$base/unittest-cont1/not-there" ) );
+ $this->assertEquals( null, $tmpFile, "Local ref of not existing file is null ($backendName)." );
+ }
+
/**
* @dataProvider provider_testPrepareAndClean
*/