Introduce two new classes, containing code split off from EditPage: * IntroMessageBuilder (edit notices and other intro messages) * PreloadedContentBuilder (initial text of new pages / sections) I'm doing both of these features in one change, because they share a lot of code. They are meant to be used by alternative editors to support all of the features of the MediaWiki edit form. This isn't everything you need yet (we should at least do this for the edit checkboxes too), but it's a step. Bug: T201613 Change-Id: If0b05710cb52a977bf4e85947d72d68683a0a29e
220 lines
7.2 KiB
PHP
220 lines
7.2 KiB
PHP
<?php
|
|
|
|
namespace MediaWiki\EditPage;
|
|
|
|
use Content;
|
|
use MediaWiki\Content\IContentHandlerFactory;
|
|
use MediaWiki\Content\Transform\ContentTransformer;
|
|
use MediaWiki\HookContainer\HookContainer;
|
|
use MediaWiki\HookContainer\HookRunner;
|
|
use MediaWiki\Page\ProperPageIdentity;
|
|
use MediaWiki\Page\RedirectLookup;
|
|
use MediaWiki\Page\WikiPageFactory;
|
|
use MediaWiki\Permissions\Authority;
|
|
use MediaWiki\Revision\RevisionRecord;
|
|
use MediaWiki\SpecialPage\SpecialPageFactory;
|
|
use MediaWiki\Title\Title;
|
|
use ParserOptions;
|
|
use Wikimedia\Assert\Assert;
|
|
use WikitextContent;
|
|
|
|
/**
|
|
* Provides the initial content of the edit box displayed in an edit form
|
|
* when creating a new page or a new section.
|
|
*
|
|
* Used by EditPage, and may be used by extensions providing alternative editors.
|
|
*
|
|
* @since 1.41
|
|
*/
|
|
class PreloadedContentBuilder {
|
|
|
|
use ParametersHelper;
|
|
|
|
private IContentHandlerFactory $contentHandlerFactory;
|
|
private WikiPageFactory $wikiPageFactory;
|
|
private RedirectLookup $redirectLookup;
|
|
private SpecialPageFactory $specialPageFactory;
|
|
private ContentTransformer $contentTransformer;
|
|
private HookRunner $hookRunner;
|
|
|
|
public function __construct(
|
|
IContentHandlerFactory $contentHandlerFactory,
|
|
WikiPageFactory $wikiPageFactory,
|
|
RedirectLookup $redirectLookup,
|
|
SpecialPageFactory $specialPageFactory,
|
|
ContentTransformer $contentTransformer,
|
|
HookContainer $hookContainer
|
|
) {
|
|
// Services
|
|
$this->contentHandlerFactory = $contentHandlerFactory;
|
|
$this->wikiPageFactory = $wikiPageFactory;
|
|
$this->redirectLookup = $redirectLookup;
|
|
$this->specialPageFactory = $specialPageFactory;
|
|
$this->contentTransformer = $contentTransformer;
|
|
$this->hookRunner = new HookRunner( $hookContainer );
|
|
}
|
|
|
|
/**
|
|
* Get the initial content of the edit box displayed in an edit form
|
|
* when creating a new page or a new section.
|
|
*
|
|
* @param ProperPageIdentity $page
|
|
* @param Authority $performer
|
|
* @param string|null $preload
|
|
* @param string[] $preloadParams
|
|
* @param string|null $section
|
|
* @return Content
|
|
*/
|
|
public function getPreloadedContent(
|
|
ProperPageIdentity $page,
|
|
Authority $performer,
|
|
?string $preload,
|
|
array $preloadParams,
|
|
?string $section
|
|
): Content {
|
|
Assert::parameterElementType( 'string', $preloadParams, '$preloadParams' );
|
|
|
|
$content = null;
|
|
if ( $section !== 'new' ) {
|
|
$content = $this->getDefaultContent( $page );
|
|
}
|
|
if ( $content === null ) {
|
|
// Custom preload text for new sections
|
|
$defaultPreload = $section === 'new' ? 'MediaWiki:addsection-preload' : '';
|
|
$preload = $preload ?: $defaultPreload;
|
|
$content = $this->getPreloadedContentFromParams( $page, $performer, $preload, $preloadParams );
|
|
}
|
|
$title = Title::newFromPageIdentity( $page );
|
|
if ( !$title->getArticleID() ) {
|
|
$contentModel = $title->getContentModel();
|
|
$contentHandler = $this->contentHandlerFactory->getContentHandler( $contentModel );
|
|
$contentFormat = $contentHandler->getDefaultFormat();
|
|
$text = $contentHandler->serializeContent( $content, $contentFormat );
|
|
$this->hookRunner->onEditFormPreloadText( $text, $title );
|
|
$content = $contentHandler->unserializeContent( $text, $contentFormat );
|
|
}
|
|
return $content;
|
|
}
|
|
|
|
/**
|
|
* Get the content that is displayed when viewing a page that does not exist.
|
|
* Users should be discouraged from saving the page with identical content to this.
|
|
*
|
|
* Some code may depend on the fact that this is only non-null for the 'MediaWiki:' namespace.
|
|
* Beware.
|
|
*
|
|
* @param ProperPageIdentity $page
|
|
* @return Content|null
|
|
*/
|
|
public function getDefaultContent( ProperPageIdentity $page ): ?Content {
|
|
$title = Title::newFromPageIdentity( $page );
|
|
$contentModel = $title->getContentModel();
|
|
$contentHandler = $this->contentHandlerFactory->getContentHandler( $contentModel );
|
|
$contentFormat = $contentHandler->getDefaultFormat();
|
|
if ( $title->getNamespace() === NS_MEDIAWIKI ) {
|
|
// If this is a system message, get the default text.
|
|
$text = $title->getDefaultMessageText();
|
|
if ( $text !== false ) {
|
|
return $contentHandler->unserializeContent( $text, $contentFormat );
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Get the contents to be preloaded into the box by loading the given page.
|
|
*
|
|
* @param ProperPageIdentity $page
|
|
* @param Authority $performer
|
|
* @param string $preload Representing the title to preload from.
|
|
* @param string[] $preloadParams Parameters to use (interface-message style) in the preloaded text
|
|
* @return Content
|
|
*/
|
|
private function getPreloadedContentFromParams(
|
|
ProperPageIdentity $page,
|
|
Authority $performer,
|
|
string $preload,
|
|
array $preloadParams
|
|
): Content {
|
|
$title = Title::newFromPageIdentity( $page );
|
|
$contentModel = $title->getContentModel();
|
|
$handler = $this->contentHandlerFactory->getContentHandler( $contentModel );
|
|
|
|
// T297725: Don't trick users into making edits to e.g. .js subpages
|
|
if ( !$handler->supportsPreloadContent() || $preload === '' ) {
|
|
return $handler->makeEmptyContent();
|
|
}
|
|
|
|
$title = Title::newFromText( $preload );
|
|
|
|
if ( $title && $title->getNamespace() == NS_MEDIAWIKI ) {
|
|
// When the preload source is in NS_MEDIAWIKI, get the content via wfMessage, to
|
|
// enable preloading from i18n messages. The message framework can work with normal
|
|
// pages in NS_MEDIAWIKI, so this does not restrict preloading only to i18n messages.
|
|
$msg = wfMessage( $title->getText() );
|
|
|
|
if ( $msg->isDisabled() ) {
|
|
// Message is disabled and should not be used for preloading
|
|
return $handler->makeEmptyContent();
|
|
}
|
|
|
|
return new WikitextContent( $msg
|
|
->params( $preloadParams )
|
|
->inContentLanguage()
|
|
->text()
|
|
);
|
|
}
|
|
|
|
// (T299544) Use SpecialMyLanguage redirect so that nonexistent translated pages can
|
|
// fall back to the corresponding page in a suitable language
|
|
$title = $this->getTargetTitleIfSpecialMyLanguage( $title );
|
|
|
|
# Check for existence to avoid getting MediaWiki:Noarticletext
|
|
if ( !$this->isPageExistingAndViewable( $title, $performer ) ) {
|
|
// TODO: somehow show a warning to the user!
|
|
return $handler->makeEmptyContent();
|
|
}
|
|
|
|
$page = $this->wikiPageFactory->newFromTitle( $title );
|
|
if ( $page->isRedirect() ) {
|
|
$redirTarget = $this->redirectLookup->getRedirectTarget( $title );
|
|
$redirTarget = Title::castFromLinkTarget( $redirTarget );
|
|
# Same as before
|
|
if ( !$this->isPageExistingAndViewable( $redirTarget, $performer ) ) {
|
|
// TODO: somehow show a warning to the user!
|
|
return $handler->makeEmptyContent();
|
|
}
|
|
$page = $this->wikiPageFactory->newFromTitle( $redirTarget );
|
|
}
|
|
|
|
$content = $page->getContent( RevisionRecord::RAW );
|
|
|
|
if ( !$content ) {
|
|
// TODO: somehow show a warning to the user!
|
|
return $handler->makeEmptyContent();
|
|
}
|
|
|
|
if ( $content->getModel() !== $handler->getModelID() ) {
|
|
$converted = $content->convert( $handler->getModelID() );
|
|
|
|
if ( !$converted ) {
|
|
// TODO: somehow show a warning to the user!
|
|
wfDebug( "Attempt to preload incompatible content: " .
|
|
"can't convert " . $content->getModel() .
|
|
" to " . $handler->getModelID() );
|
|
|
|
return $handler->makeEmptyContent();
|
|
}
|
|
|
|
$content = $converted;
|
|
}
|
|
|
|
return $this->contentTransformer->preloadTransform(
|
|
$content,
|
|
$title,
|
|
// The preload transformations don't depend on the user anyway
|
|
ParserOptions::newFromAnon(),
|
|
$preloadParams
|
|
);
|
|
}
|
|
}
|