82 $this->config = $config;
83 $this->linkRenderer = $linkRenderer;
84 $this->permManager = $permManager;
85 $this->userNameUtils = $userNameUtils;
86 $this->tempUserCreator = $tempUserCreator;
87 $this->userFactory = $userFactory;
88 $this->restrictionStore = $restrictionStore;
89 $this->blockStore = $blockStore;
90 $this->readOnlyMode = $readOnlyMode;
91 $this->specialPageFactory = $specialPageFactory;
92 $this->repoGroup = $repoGroup;
93 $this->namespaceInfo = $namespaceInfo;
94 $this->skinFactory = $skinFactory;
95 $this->dbProvider = $dbProvider;
96 $this->urlUtils = $urlUtils;
111 private function getLogExtract( $types = [], $page =
'', $user =
'', $param = [] ): string {
113 LogEventsList::showLogExtract( $outString, $types, $page, $user, $param );
149 ?
string $returnToQuery,
151 ?
string $section =
null
153 $title =
Title::newFromPageIdentity( $page );
156 $this->addOldRevisionWarning( $messages, $localizer, $revRecord );
159 $this->addCodeEditingIntro( $messages, $localizer, $title, $performer );
160 $this->addSharedRepoHint( $messages, $localizer, $page );
161 $this->addUserWarnings( $messages, $localizer, $title, $performer );
162 $this->addEditIntro( $messages, $localizer, $page, $performer, $editIntro, $section );
163 $this->addRecreateWarning( $messages, $localizer, $page );
166 $this->addTalkPageText( $messages, $localizer, $title );
167 $this->addEditNotices( $messages, $localizer, $title, $revRecord );
169 $this->addReadOnlyWarning( $messages, $localizer );
170 $this->addAnonEditWarning( $messages, $localizer, $title, $performer, $returnToQuery, $preview );
171 $this->addUserConfigPageInfo( $messages, $localizer, $title, $performer, $preview );
172 $this->addPageProtectionWarningHeaders( $messages, $localizer, $page );
173 $this->addHeaderCopyrightWarning( $messages, $localizer );
175 return $messages->getList();
181 private function addCodeEditingIntro(
182 IntroMessageList $messages,
187 $isUserJsConfig = $title->isUserJsConfigPage();
188 $namespace = $title->getNamespace();
192 $title->isUserConfigPage() &&
193 $title->isSubpageOf( Title::makeTitle(
NS_USER, $performer->getUser()->getName() ) )
195 $isUserCssConfig = $title->isUserCssConfigPage();
196 $isUserJsonConfig = $title->isUserJsonConfigPage();
197 $isUserJsConfig = $title->isUserJsConfigPage();
199 if ( $isUserCssConfig ) {
200 $warning =
'usercssispublic';
201 } elseif ( $isUserJsonConfig ) {
202 $warning =
'userjsonispublic';
204 $warning =
'userjsispublic';
207 $warningText = $localizer->
msg( $warning )->parse();
208 $intro .= $warningText ? Html::rawElement(
210 [
'class' =>
'mw-userconfigpublic' ],
215 $codeMsg = $localizer->
msg(
'editpage-code-message' );
216 $codeMessageText = $codeMsg->isDisabled() ?
'' : $codeMsg->parseAsBlock();
221 $interfaceMsg = $localizer->
msg(
'editinginterface' );
222 $interfaceMsgText = $interfaceMsg->parse();
223 # Show a warning if editing an interface message
224 $intro .= $interfaceMsgText ? Html::rawElement(
226 [
'class' =>
'mw-editinginterface' ],
229 # If this is a default message (but not css, json, or js),
230 # show a hint that it is translatable on translatewiki.net
236 $defaultMessageText = $title->getDefaultMessageText();
237 if ( $defaultMessageText !==
false ) {
238 $translateInterfaceText = $localizer->
msg(
'translateinterface' )->parse();
239 $intro .= $translateInterfaceText ? Html::rawElement(
241 [
'class' =>
'mw-translateinterface' ],
242 $translateInterfaceText
248 if ( $isUserJsConfig ) {
249 $userConfigDangerousMsg = $localizer->
msg(
'userjsdangerous' )->parse();
250 $intro .= $userConfigDangerousMsg ? Html::rawElement(
252 [
'class' =>
'mw-userconfigdangerous' ],
253 $userConfigDangerousMsg
258 if ( $isJavaScript || $isCSS ) {
259 $intro .= $codeMessageText;
262 $messages->addWithKey(
263 'code-editing-intro',
269 Html::errorBox(
'$1' )
273 private function addSharedRepoHint(
274 IntroMessageList $messages,
276 ProperPageIdentity $page
278 $namespace = $page->getNamespace();
279 if ( $namespace ===
NS_FILE ) {
280 # Show a hint to shared repo
281 $file = $this->repoGroup->findFile( $page );
282 if ( $file && !$file->isLocal() ) {
283 $descUrl = $file->getDescriptionUrl();
284 # there must be a description url to show a hint to shared repo
286 if ( !$page->exists() ) {
289 'sharedupload-desc-create',
290 $file->getRepo()->getDisplayName(),
293 "<div class=\"mw-sharedupload-desc-create\">\n$1\n</div>"
298 'sharedupload-desc-edit',
299 $file->getRepo()->getDisplayName(),
302 "<div class=\"mw-sharedupload-desc-edit\">\n$1\n</div>"
310 private function addUserWarnings(
311 IntroMessageList $messages,
316 $namespace = $title->getNamespace();
317 # Show a warning message when someone creates/edits a user (talk) page but the user does not exist
318 # Show log extract when the user is currently blocked
320 $username = explode(
'/', $title->getText(), 2 )[0];
322 $validation = UserRigorOptions::RIGOR_NONE;
323 $user = $this->userFactory->newFromName( $username, $validation );
324 $ip = $this->userNameUtils->isIP( $username );
325 $block = $this->blockStore->newFromTarget( $user, $user );
327 $userExists = ( $user && $user->isRegistered() );
328 if ( $userExists && $user->isHidden() && !$performer->isAllowed(
'hideuser' ) ) {
334 if ( !$userExists && !$ip ) {
335 $messages->addWithKey(
336 'userpage-userdoesnotexist',
340 'mw-userpage-userdoesnotexist'
345 $block->getType() !== Block::TYPE_AUTO &&
347 $block->isSitewide() ||
348 $this->permManager->isBlockedFrom(
358 $messages->addWithKey(
359 'blocked-notice-logextract',
360 $this->getLogExtract(
362 $this->namespaceInfo->getCanonicalName(
NS_USER ) .
':' . $block->getTargetName(),
366 'showIfEmpty' =>
false,
368 'blocked-notice-logextract',
369 $user->getName() # Support GENDER in notice
381 private function addEditIntro(
382 IntroMessageList $messages,
384 ProperPageIdentity $page,
385 Authority $performer,
389 if ( ( $editIntro === null || $editIntro ===
'' ) && $section ===
'new' ) {
391 $editIntro =
'MediaWiki:addsection-editintro';
393 if ( $editIntro !==
null && $editIntro !==
'' ) {
394 $introTitle = Title::newFromText( $editIntro );
398 $introTitle = $this->getTargetTitleIfSpecialMyLanguage( $introTitle );
400 if ( $this->isPageExistingAndViewable( $introTitle, $performer ) ) {
401 $messages->addWithKey(
403 $localizer->
msg(
new RawMessage(
405 '<div class="mw-editintro">{{:' . $introTitle->getFullText() .
'}}</div>'
408 ->inContentLanguage()
415 if ( !$page->exists() ) {
416 $helpLink = $this->urlUtils->expand(
418 $localizer->
msg(
'helppage' )->inContentLanguage()->text()
422 if ( $performer->getUser()->isRegistered() ) {
424 $localizer->
msg(
'newarticletext', $helpLink ),
426 "<div class=\"mw-newarticletext plainlinks\">\n$1\n</div>"
430 $localizer->
msg(
'newarticletextanon', $helpLink ),
432 "<div class=\"mw-newarticletextanon plainlinks\">\n$1\n</div>"
438 private function addRecreateWarning(
439 IntroMessageList $messages,
441 ProperPageIdentity $page
443 # Give a notice
if the user is editing a deleted/moved page...
444 if ( !$page->exists() ) {
445 $dbr = $this->dbProvider->getReplicaDatabase();
447 $messages->addWithKey(
448 'recreate-moveddeleted-warn',
449 $this->getLogExtract( [
'delete',
'move',
'merge' ], $page,
'', [
451 'conds' => [ $dbr->expr(
'log_action',
'!=',
'revision' ) ],
452 'showIfEmpty' =>
false,
453 'msgKey' => [
'recreate-moveddeleted-warn' ],
459 private function addTalkPageText(
460 IntroMessageList $messages,
464 if ( $title->isTalkPage() ) {
465 $messages->add( $localizer->
msg(
'talkpagetext' ) );
469 private function addEditNotices(
470 IntroMessageList $messages,
473 ?RevisionRecord $revRecord
475 $editNotices = $title->getEditNotices( $revRecord ? $revRecord->getId() : 0 );
476 if ( count( $editNotices ) ) {
477 foreach ( $editNotices as $key => $html ) {
478 $messages->addWithKey( $key, $html );
481 $msg = $localizer->
msg(
'editnotice-notext' );
482 if ( !$msg->isDisabled() ) {
483 $messages->addWithKey(
487 [
'class' =>
'mw-editnotice-notext' ],
495 private function addOldRevisionWarning(
496 IntroMessageList $messages,
498 ?RevisionRecord $revRecord
500 if ( $revRecord && !$revRecord->isCurrent() ) {
502 $messages->addWithKey(
'editingold', Html::warningBox( $localizer->
msg(
'editingold' )->parse() ) );
506 private function addReadOnlyWarning(
507 IntroMessageList $messages,
510 if ( $this->readOnlyMode->isReadOnly() ) {
512 $localizer->
msg(
'readonlywarning', $this->readOnlyMode->getReason() ),
513 "<div id=\"mw-read-only-warning\">\n$1\n</div>"
518 private function addAnonEditWarning(
519 IntroMessageList $messages,
522 Authority $performer,
523 ?
string $returnToQuery,
526 if ( !$performer->
getUser()->isRegistered() ) {
527 $tempUserCreateActive = $this->tempUserCreator->shouldAutoCreate( $performer,
'edit' );
529 $messages->addWithKey(
532 $tempUserCreateActive ?
'autocreate-edit-warning' :
'anoneditwarning',
534 SpecialPage::getTitleFor(
'Userlogin' )->getFullURL( [
535 'returnto' => $title->getPrefixedDBkey(),
536 'returntoquery' => $returnToQuery,
539 SpecialPage::getTitleFor(
'CreateAccount' )->getFullURL( [
540 'returnto' => $title->getPrefixedDBkey(),
541 'returntoquery' => $returnToQuery,
544 Html::warningBox(
'$1',
'mw-anon-edit-warning' )
547 $messages->addWithKey(
549 $localizer->
msg( $tempUserCreateActive ?
'autocreate-preview-warning' :
'anonpreviewwarning' )
551 Html::warningBox(
'$1',
'mw-anon-preview-warning' ) );
560 private function isWrongCaseUserConfigPage( Title $title ): bool {
561 if ( $title->isUserCssConfigPage() || $title->isUserJsConfigPage() ) {
562 $name = $title->getSkinFromConfigSubpage();
563 $skins = array_merge(
564 array_keys( $this->skinFactory->getInstalledSkins() ),
567 return !in_array( $name, $skins,
true )
568 && in_array( strtolower( $name ), $skins,
true );
574 private function addUserConfigPageInfo(
575 IntroMessageList $messages,
578 Authority $performer,
581 if ( $title->isUserConfigPage() ) {
582 # Check the skin exists
583 if ( $this->isWrongCaseUserConfigPage( $title ) ) {
585 $localizer->
msg(
'userinvalidconfigtitle', $title->getSkinFromConfigSubpage() ),
586 Html::errorBox(
'$1',
'',
'mw-userinvalidconfigtitle' )
589 if ( $title->isSubpageOf( Title::makeTitle(
NS_USER, $performer->getUser()->getName() ) ) ) {
590 $isUserCssConfig = $title->isUserCssConfigPage();
591 $isUserJsonConfig = $title->isUserJsonConfigPage();
592 $isUserJsConfig = $title->isUserJsConfigPage();
595 if ( $isUserCssConfig && $this->config->get( MainConfigNames::AllowUserCss ) ) {
597 $localizer->
msg(
'usercssyoucanpreview' ),
598 "<div id='mw-usercssyoucanpreview'>\n$1\n</div>"
600 } elseif ( $isUserJsonConfig ) {
602 $localizer->
msg(
'userjsonyoucanpreview' ),
603 "<div id='mw-userjsonyoucanpreview'>\n$1\n</div>"
605 } elseif ( $isUserJsConfig && $this->config->get( MainConfigNames::AllowUserJs ) ) {
607 $localizer->
msg(
'userjsyoucanpreview' ),
608 "<div id='mw-userjsyoucanpreview'>\n$1\n</div>"
616 private function addPageProtectionWarningHeaders(
617 IntroMessageList $messages,
619 ProperPageIdentity $page
621 if ( $this->restrictionStore->isProtected( $page,
'edit' ) &&
622 $this->permManager->getNamespaceRestrictionLevels(
623 $page->getNamespace()
626 # Is the title semi-protected?
627 if ( $this->restrictionStore->isSemiProtected( $page ) ) {
628 $noticeMsg =
'semiprotectedpagewarning';
630 # Then it must be protected based on static groups (regular)
631 $noticeMsg =
'protectedpagewarning';
633 $messages->addWithKey(
635 $this->getLogExtract(
'protect', $page,
'', [
'lim' => 1,
'msgKey' => [ $noticeMsg ] ] )
638 if ( $this->restrictionStore->isCascadeProtected( $page ) ) {
639 # Is this page under cascading protection from some source pages?
640 $tlCascadeSources = $this->restrictionStore->getCascadeProtectionSources( $page )[2];
641 if ( $tlCascadeSources ) {
643 # Explain, and list the titles responsible
644 foreach ( $tlCascadeSources as
$source ) {
645 $htmlList .= Html::rawElement(
'li', [], $this->linkRenderer->makeLink(
$source ) );
647 $messages->addWithKey(
648 'cascadeprotectedwarning',
649 $localizer->
msg(
'cascadeprotectedwarning', count( $tlCascadeSources ) )->parse() .
650 ( $htmlList ? Html::rawElement(
'ul', [], $htmlList ) :
'' ),
651 Html::warningBox(
'$1',
'mw-cascadeprotectedwarning' )
655 if ( !$page->exists() && $this->restrictionStore->getRestrictions( $page,
'create' ) ) {
656 $messages->addWithKey(
657 'titleprotectedwarning',
658 $this->getLogExtract(
663 'showIfEmpty' =>
false,
664 'msgKey' => [
'titleprotectedwarning' ],
665 'wrap' =>
"<div class=\"mw-titleprotectedwarning\">\n$1</div>"
672 private function addHeaderCopyrightWarning(
673 IntroMessageList $messages,
677 $localizer->msg(
'editpage-head-copy-warn' ),
678 "<div class='editpage-head-copywarn'>\n$1\n</div>"