| 12
 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
		);
	}
}
 |