51 private readonly
Config $config,
81 private function getLogExtract( $types = [], $page =
'', $user =
'', $param = [] ): string {
83 LogEventsList::showLogExtract( $outString, $types, $page, $user, $param );
119 ?
string $returnToQuery,
121 ?
string $section =
null
123 $title =
Title::newFromPageIdentity( $page );
126 $this->addOldRevisionWarning( $messages, $localizer, $revRecord );
129 $this->addCodeEditingIntro( $messages, $localizer, $title, $performer );
130 $this->addSharedRepoHint( $messages, $localizer, $page );
131 $this->addUserWarnings( $messages, $localizer, $title, $performer );
132 $this->addEditIntro( $messages, $localizer, $page, $performer, $editIntro, $section );
133 $this->addRecreateWarning( $messages, $page );
136 $this->addTalkPageText( $messages, $localizer, $title );
137 $this->addEditNotices( $messages, $localizer, $title, $revRecord );
139 $this->addReadOnlyWarning( $messages, $localizer );
140 $this->addAnonEditWarning( $messages, $localizer, $title, $performer, $returnToQuery, $preview );
141 $this->addUserConfigPageInfo( $messages, $localizer, $title, $performer, $preview );
142 $this->addPageProtectionWarningHeaders( $messages, $localizer, $page );
143 $this->addHeaderCopyrightWarning( $messages, $localizer );
145 return $messages->getList();
151 private function addCodeEditingIntro(
152 IntroMessageList $messages,
153 MessageLocalizer $localizer,
157 $isUserJsConfig = $title->isUserJsConfigPage();
158 $namespace = $title->getNamespace();
162 $title->isUserConfigPage() &&
163 $title->isSubpageOf( Title::makeTitle(
NS_USER, $performer->getUser()->getName() ) )
165 $isUserCssConfig = $title->isUserCssConfigPage();
166 $isUserJsonConfig = $title->isUserJsonConfigPage();
167 $isUserJsConfig = $title->isUserJsConfigPage();
169 if ( $isUserCssConfig ) {
170 $warning =
'usercssispublic';
171 } elseif ( $isUserJsonConfig ) {
172 $warning =
'userjsonispublic';
174 $warning =
'userjsispublic';
177 $warningText = $localizer->msg( $warning )->parse();
178 $intro .= $warningText ? Html::rawElement(
180 [
'class' =>
'mw-userconfigpublic' ],
185 $codeMsg = $localizer->msg(
'editpage-code-message' );
186 $codeMessageText = $codeMsg->isDisabled() ?
'' : $codeMsg->parseAsBlock();
192 $interfaceMsg = $localizer->msg(
'editinginterface' );
193 $interfaceMsgText = $interfaceMsg->parse();
194 # Show a warning if editing an interface message
195 $intro .= $interfaceMsgText ? Html::rawElement(
197 [
'class' =>
'mw-editinginterface' ],
200 # If this is a default message (but not css, json, js or vue),
201 # show a hint that it is translatable on translatewiki.net
207 $defaultMessageText = $title->getDefaultMessageText();
208 if ( $defaultMessageText !==
false ) {
209 $translateInterfaceText = $localizer->msg(
'translateinterface' )->parse();
210 $intro .= $translateInterfaceText ? Html::rawElement(
212 [
'class' =>
'mw-translateinterface' ],
213 $translateInterfaceText
219 if ( $isUserJsConfig ) {
220 $userConfigDangerousMsg = $localizer->msg(
'userjsdangerous' )->parse();
221 $intro .= $userConfigDangerousMsg ? Html::rawElement(
223 [
'class' =>
'mw-userconfigdangerous' ],
224 $userConfigDangerousMsg
229 if ( $isJavaScript || $isCSS ) {
230 $intro .= $codeMessageText;
233 $messages->addWithKey(
234 'code-editing-intro',
240 Html::errorBox(
'$1' )
244 private function addSharedRepoHint(
245 IntroMessageList $messages,
246 MessageLocalizer $localizer,
247 ProperPageIdentity $page
249 $namespace = $page->getNamespace();
250 if ( $namespace ===
NS_FILE ) {
251 # Show a hint to shared repo
252 $file = $this->repoGroup->findFile( $page );
253 if ( $file && !$file->isLocal() ) {
254 $descUrl = $file->getDescriptionUrl();
255 # there must be a description url to show a hint to shared repo
257 if ( !$page->exists() ) {
260 'sharedupload-desc-create',
261 $file->getRepo()->getDisplayName(),
264 "<div class=\"mw-sharedupload-desc-create\">\n$1\n</div>"
269 'sharedupload-desc-edit',
270 $file->getRepo()->getDisplayName(),
273 "<div class=\"mw-sharedupload-desc-edit\">\n$1\n</div>"
281 private function addUserWarnings(
282 IntroMessageList $messages,
283 MessageLocalizer $localizer,
287 $namespace = $title->getNamespace();
288 # Show a warning message when someone creates/edits a user (talk) page but the user does not exist
289 # Show log extract when the user is currently blocked
291 $username = explode(
'/', $title->getText(), 2 )[0];
293 $validation = UserRigorOptions::RIGOR_NONE;
294 $user = $this->userFactory->newFromName( $username, $validation );
295 $ip = $this->userNameUtils->isIP( $username );
297 $userExists = ( $user && $user->isRegistered() );
298 if ( $userExists && $user->isHidden() && !$performer->isAllowed(
'hideuser' ) ) {
304 if ( !$userExists && !$ip ) {
305 $messages->addWithKey(
306 'userpage-userdoesnotexist',
309 $localizer->msg(
'userpage-userdoesnotexist',
wfEscapeWikiText( $username ) )->parse(),
310 'mw-userpage-userdoesnotexist'
316 $blockLogBox = LogEventsList::getBlockLogWarningBox(
318 $this->namespaceInfo,
324 if ( $blockLogBox !==
null ) {
325 $messages->addWithKey(
'blocked-notice-logextract', $blockLogBox );
333 private function addEditIntro(
334 IntroMessageList $messages,
335 MessageLocalizer $localizer,
336 ProperPageIdentity $page,
337 Authority $performer,
341 if ( ( $editIntro === null || $editIntro ===
'' ) && $section ===
'new' ) {
343 $editIntro =
'MediaWiki:addsection-editintro';
345 if ( $editIntro !==
null && $editIntro !==
'' ) {
346 $introTitle = Title::newFromText( $editIntro );
350 $introTitle = $this->getTargetTitleIfSpecialMyLanguage( $introTitle );
352 if ( $this->isPageExistingAndViewable( $introTitle, $performer ) ) {
353 $messages->addWithKey(
355 $localizer->msg(
new RawMessage(
357 '<div class="mw-editintro">{{:' . $introTitle->getFullText() .
'}}</div>'
360 ->inContentLanguage()
367 if ( !$page->exists() ) {
368 $helpLink = $this->urlUtils->expand(
369 Skin::makeInternalOrExternalUrl(
370 $localizer->msg(
'helppage' )->inContentLanguage()->text()
374 if ( $helpLink ===
null ) {
375 throw new LogicException(
'Help link was invalid, this should be impossible' );
377 if ( $performer->getUser()->isRegistered() ) {
379 $localizer->msg(
'newarticletext', $helpLink ),
381 "<div class=\"mw-newarticletext plainlinks\">\n$1\n</div>"
385 $localizer->msg(
'newarticletextanon', $helpLink ),
387 "<div class=\"mw-newarticletextanon plainlinks\">\n$1\n</div>"
393 private function addRecreateWarning(
394 IntroMessageList $messages,
395 ProperPageIdentity $page
397 # Give a notice
if the user is editing a deleted/moved page...
398 if ( !$page->exists() ) {
399 $dbr = $this->dbProvider->getReplicaDatabase();
401 $messages->addWithKey(
402 'recreate-moveddeleted-warn',
403 $this->getLogExtract( [
'delete',
'move',
'merge' ], $page,
'', [
405 'conds' => [ $dbr->expr(
'log_action',
'!=',
'revision' ) ],
406 'showIfEmpty' =>
false,
407 'msgKey' => [
'recreate-moveddeleted-warn' ],
413 private function addTalkPageText(
414 IntroMessageList $messages,
415 MessageLocalizer $localizer,
418 if ( $title->isTalkPage() ) {
419 $messages->add( $localizer->msg(
'talkpagetext' ) );
423 private function addEditNotices(
424 IntroMessageList $messages,
425 MessageLocalizer $localizer,
427 ?RevisionRecord $revRecord
429 $editNotices = $title->getEditNotices( $revRecord ? $revRecord->getId() : 0 );
430 if ( count( $editNotices ) ) {
431 foreach ( $editNotices as $key => $html ) {
432 $messages->addWithKey( $key, $html );
435 $msg = $localizer->msg(
'editnotice-notext' );
436 if ( !$msg->isDisabled() ) {
437 $messages->addWithKey(
441 [
'class' =>
'mw-editnotice-notext' ],
449 private function addOldRevisionWarning(
450 IntroMessageList $messages,
451 MessageLocalizer $localizer,
452 ?RevisionRecord $revRecord
454 if ( $revRecord && !$revRecord->isCurrent() ) {
456 $messages->addWithKey(
'editingold', Html::warningBox( $localizer->msg(
'editingold' )->parse() ) );
460 private function addReadOnlyWarning(
461 IntroMessageList $messages,
462 MessageLocalizer $localizer
464 if ( $this->readOnlyMode->isReadOnly() ) {
466 $localizer->msg(
'readonlywarning', $this->readOnlyMode->getReason() ),
467 "<div id=\"mw-read-only-warning\">\n$1\n</div>"
472 private function addAnonEditWarning(
473 IntroMessageList $messages,
474 MessageLocalizer $localizer,
476 Authority $performer,
477 ?
string $returnToQuery,
480 if ( !$performer->
getUser()->isRegistered() ) {
481 $tempUserCreateActive = $this->tempUserCreator->shouldAutoCreate( $performer,
'edit' );
483 $messages->addWithKey(
486 $tempUserCreateActive ?
'autocreate-edit-warning' :
'anoneditwarning',
488 SpecialPage::getTitleFor(
'Userlogin' )->getFullURL( [
489 'returnto' => $title->getPrefixedDBkey(),
490 'returntoquery' => $returnToQuery,
493 SpecialPage::getTitleFor(
'CreateAccount' )->getFullURL( [
494 'returnto' => $title->getPrefixedDBkey(),
495 'returntoquery' => $returnToQuery,
498 Html::warningBox(
'$1',
'mw-anon-edit-warning' )
501 $messages->addWithKey(
503 $localizer->msg( $tempUserCreateActive ?
'autocreate-preview-warning' :
'anonpreviewwarning' )
505 Html::warningBox(
'$1',
'mw-anon-preview-warning' ) );
514 private function isWrongCaseUserConfigPage( Title $title ): bool {
515 if ( $title->isUserCssConfigPage() || $title->isUserJsConfigPage() ) {
516 $name = $title->getSkinFromConfigSubpage();
517 $skins = array_merge(
518 array_keys( $this->skinFactory->getInstalledSkins() ),
521 return !in_array( $name, $skins,
true )
522 && in_array( strtolower( $name ), $skins,
true );
528 private function addUserConfigPageInfo(
529 IntroMessageList $messages,
530 MessageLocalizer $localizer,
532 Authority $performer,
535 if ( $title->isUserConfigPage() ) {
536 # Check the skin exists
537 if ( $this->isWrongCaseUserConfigPage( $title ) ) {
539 $localizer->msg(
'userinvalidconfigtitle', $title->getSkinFromConfigSubpage() ),
540 Html::errorBox(
'$1',
'',
'mw-userinvalidconfigtitle' )
543 if ( $title->isSubpageOf( Title::makeTitle(
NS_USER, $performer->getUser()->getName() ) ) ) {
544 $isUserCssConfig = $title->isUserCssConfigPage();
545 $isUserJsonConfig = $title->isUserJsonConfigPage();
546 $isUserJsConfig = $title->isUserJsConfigPage();
549 if ( $isUserCssConfig && $this->config->get( MainConfigNames::AllowUserCss ) ) {
551 $localizer->msg(
'usercssyoucanpreview' ),
552 "<div id='mw-usercssyoucanpreview'>\n$1\n</div>"
554 } elseif ( $isUserJsonConfig ) {
556 $localizer->msg(
'userjsonyoucanpreview' ),
557 "<div id='mw-userjsonyoucanpreview'>\n$1\n</div>"
559 } elseif ( $isUserJsConfig && $this->config->get( MainConfigNames::AllowUserJs ) ) {
561 $localizer->msg(
'userjsyoucanpreview' ),
562 "<div id='mw-userjsyoucanpreview'>\n$1\n</div>"
570 private function addPageProtectionWarningHeaders(
571 IntroMessageList $messages,
572 MessageLocalizer $localizer,
573 ProperPageIdentity $page
575 if ( $this->restrictionStore->isProtected( $page,
'edit' ) &&
576 $this->permManager->getNamespaceRestrictionLevels(
577 $page->getNamespace()
580 # Is the title semi-protected?
581 if ( $this->restrictionStore->isSemiProtected( $page ) ) {
582 $noticeMsg =
'semiprotectedpagewarning';
584 # Then it must be protected based on static groups (regular)
585 $noticeMsg =
'protectedpagewarning';
587 $messages->addWithKey(
589 $this->getLogExtract(
'protect', $page,
'', [
'lim' => 1,
'msgKey' => [ $noticeMsg ] ] )
592 if ( $this->restrictionStore->isCascadeProtected( $page ) ) {
593 # Is this page under cascading protection from some source pages?
594 $tlCascadeSources = $this->restrictionStore->getCascadeProtectionSources( $page )[2];
595 if ( $tlCascadeSources ) {
597 # Explain, and list the titles responsible
598 foreach ( $tlCascadeSources as
$source ) {
599 $htmlList .= Html::rawElement(
'li', [], $this->linkRenderer->makeLink(
$source ) );
601 $messages->addWithKey(
602 'cascadeprotectedwarning',
603 $localizer->msg(
'cascadeprotectedwarning', count( $tlCascadeSources ) )->parse() .
604 ( $htmlList ? Html::rawElement(
'ul', [], $htmlList ) :
'' ),
605 Html::warningBox(
'$1',
'mw-cascadeprotectedwarning' )
609 if ( !$page->exists() && $this->restrictionStore->getRestrictions( $page,
'create' ) ) {
610 $messages->addWithKey(
611 'titleprotectedwarning',
612 $this->getLogExtract(
617 'showIfEmpty' =>
false,
618 'msgKey' => [
'titleprotectedwarning' ],
619 'wrap' =>
"<div class=\"mw-titleprotectedwarning\">\n$1</div>"
626 private function addHeaderCopyrightWarning(
627 IntroMessageList $messages,
628 MessageLocalizer $localizer
631 $localizer->
msg(
'editpage-head-copy-warn' ),
632 "<div class='editpage-head-copywarn'>\n$1\n</div>"