*/
use MediaWiki\Logger\LoggerFactory;
+use MediaWiki\MediaWikiServices;
/**
* The edit page/HTML interface (split from Article)
$revision = $this->mArticle->getRevisionFetched();
// Disallow editing revisions with content models different from the current one
- if ( $revision && $revision->getContentModel() !== $this->contentModel ) {
- $this->displayViewSourcePage(
- $this->getContentObject(),
- wfMessage(
- 'contentmodelediterror',
- $revision->getContentModel(),
- $this->contentModel
- )->plain()
- );
- return;
+ // Undo edits being an exception in order to allow reverting content model changes.
+ if ( $revision
+ && $revision->getContentModel() !== $this->contentModel
+ ) {
+ $prevRev = null;
+ if ( $this->undidRev ) {
+ $undidRevObj = Revision::newFromId( $this->undidRev );
+ $prevRev = $undidRevObj ? $undidRevObj->getPrevious() : null;
+ }
+ if ( !$this->undidRev
+ || !$prevRev
+ || $prevRev->getContentModel() !== $this->contentModel
+ ) {
+ $this->displayViewSourcePage(
+ $this->getContentObject(),
+ wfMessage(
+ 'contentmodelediterror',
+ $revision->getContentModel(),
+ $this->contentModel
+ )->plain()
+ );
+ return;
+ }
}
$this->isConflict = false;
$this->showTextbox( $text, 'wpTextbox1', [ 'readonly' ] );
$wgOut->addHTML( $this->editFormTextAfterContent );
- $wgOut->addHTML( Html::rawElement( 'div', [ 'class' => 'templatesUsed' ],
- Linker::formatTemplates( $this->getTemplates() ) ) );
+ $wgOut->addHTML( $this->makeTemplatesOnThisPageList( $this->getTemplates() ) );
$wgOut->addModules( 'mediawiki.action.edit.collapsibleFooter' );
// May be overridden by revision.
$this->contentFormat = $request->getText( 'format', $this->contentFormat );
- if ( !ContentHandler::getForModelID( $this->contentModel )
- ->isSupportedFormat( $this->contentFormat )
- ) {
+ try {
+ $handler = ContentHandler::getForModelID( $this->contentModel );
+ } catch ( MWUnknownContentModelException $e ) {
+ throw new ErrorPageError(
+ 'editpage-invalidcontentmodel-title',
+ 'editpage-invalidcontentmodel-text',
+ [ $this->contentModel ]
+ );
+ }
+
+ if ( !$handler->isSupportedFormat( $this->contentFormat ) ) {
throw new ErrorPageError(
'editpage-notsupportedcontentformat-title',
'editpage-notsupportedcontentformat-text',
$oldContent = $this->page->getContent( Revision::RAW );
$popts = ParserOptions::newFromUserAndLang( $wgUser, $wgContLang );
$newContent = $content->preSaveTransform( $this->mTitle, $wgUser, $popts );
+ if ( $newContent->getModel() !== $oldContent->getModel() ) {
+ // The undo may change content
+ // model if its reverting the top
+ // edit. This can result in
+ // mismatched content model/format.
+ $this->contentModel = $newContent->getModel();
+ $this->contentFormat = $oldrev->getContentFormat();
+ }
if ( $newContent->equals( $oldContent ) ) {
# Tell the user that the undo results in no change,
$handler = ContentHandler::getForModelID( $this->contentModel );
return $handler->makeEmptyContent();
- } else {
+ } elseif ( !$this->undidRev ) {
// Content models should always be the same since we error
- // out if they are different before this point.
+ // out if they are different before this point (in ->edit()).
+ // The exception being, during an undo, the current revision might
+ // differ from the prior revision.
$logger = LoggerFactory::getInstance( 'editpage' );
if ( $this->contentModel !== $rev->getContentModel() ) {
$logger->warning( "Overriding content model from current edit {prev} to {new}", [
] );
$this->contentFormat = $rev->getContentFormat();
}
-
- return $content;
}
+ return $content;
}
/**
$wgOut->addHTML( $this->editFormTextAfterTools . "\n" );
- $wgOut->addHTML( Html::rawElement( 'div', [ 'class' => 'templatesUsed' ],
- Linker::formatTemplates( $this->getTemplates(), $this->preview, $this->section != '' ) ) );
+ $wgOut->addHTML( $this->makeTemplatesOnThisPageList( $this->getTemplates() ) );
$wgOut->addHTML( Html::rawElement( 'div', [ 'class' => 'hiddencats' ],
Linker::formatHiddenCategories( $this->page->getHiddenCategories() ) ) );
}
+ /**
+ * Wrapper around TemplatesOnThisPageFormatter to make
+ * a "templates on this page" list.
+ *
+ * @param Title[] $templates
+ * @return string HTML
+ */
+ protected function makeTemplatesOnThisPageList( array $templates ) {
+ $templateListFormatter = new TemplatesOnThisPageFormatter(
+ $this->context, MediaWikiServices::getInstance()->getLinkRenderer()
+ );
+
+ // preview if preview, else section if section, else false
+ $type = false;
+ if ( $this->preview ) {
+ $type = 'preview';
+ } elseif ( $this->section != '' ) {
+ $type = 'section';
+ }
+
+ return Html::rawElement( 'div', [ 'class' => 'templatesUsed' ],
+ $templateListFormatter->format( $templates, $type )
+ );
+
+ }
+
/**
* Extract the section title from current section text, if any.
*
* subclasses may reorganize the form.
* Note that you do not need to worry about the label's for=, it will be
* inferred by the id given to the input. You can remove them both by
- * passing array( 'id' => false ) to $userInputAttrs.
+ * passing [ 'id' => false ] to $userInputAttrs.
*
* @param string $summary The value of the summary input
* @param string $labelText The html to place inside the label
* @param array $inputAttrs Array of attrs to use on the input
* @param array $spanLabelAttrs Array of attrs to use on the span inside the label
*
- * @return array An array in the format array( $label, $input )
+ * @return array An array in the format [ $label, $input ]
*/
function getSummaryInput( $summary = "", $labelText = null,
$inputAttrs = null, $spanLabelAttrs = null