1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
|
<?php
namespace MediaWiki\EditPage;
use MediaWiki\Content\Content;
use MediaWiki\Content\IContentHandlerFactory;
use MediaWiki\Content\Transform\ContentTransformer;
use MediaWiki\HookContainer\HookContainer;
use MediaWiki\HookContainer\HookRunner;
use MediaWiki\Page\PageReference;
use MediaWiki\Page\ProperPageIdentity;
use MediaWiki\Page\RedirectLookup;
use MediaWiki\Page\WikiPageFactory;
use MediaWiki\Parser\ParserOptions;
use MediaWiki\Permissions\Authority;
use MediaWiki\Revision\RevisionRecord;
use MediaWiki\SpecialPage\SpecialPageFactory;
use MediaWiki\Title\Title;
use MessageCache;
use Wikimedia\Assert\Assert;
/**
* 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 ) {
if ( ( $preload === null || $preload === '' ) && $section === 'new' ) {
// Custom preload text for new sections
$preload = 'MediaWiki:addsection-preload';
}
$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 $contextPage
* @param Authority $performer
* @param string|null $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 $contextPage,
Authority $performer,
?string $preload,
array $preloadParams
): Content {
$contextTitle = Title::newFromPageIdentity( $contextPage );
$contentModel = $contextTitle->getContentModel();
$handler = $this->contentHandlerFactory->getContentHandler( $contentModel );
// T297725: Don't trick users into making edits to e.g. .js subpages
if ( !$handler->supportsPreloadContent() || $preload === null || $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( MessageCache::normalizeKey( $title->getText() ) );
if ( $msg->isDisabled() ) {
// Message is disabled and should not be used for preloading
return $handler->makeEmptyContent();
}
return $this->transform(
$handler->unserializeContent( $msg
->page( $title )
->params( $preloadParams )
->inContentLanguage()
->plain()
),
$title
);
}
// (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->transform( $content, $title, $preloadParams );
}
private function transform(
Content $content,
PageReference $title,
array $preloadParams = []
) {
return $this->contentTransformer->preloadTransform(
$content,
$title,
// The preload transformations don't depend on the user anyway
ParserOptions::newFromAnon(),
$preloadParams
);
}
}
|