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 );
326 $userExists = ( $user && $user->isRegistered() );
327 if ( $userExists && $user->isHidden() && !$performer->isAllowed(
'hideuser' ) ) {
333 if ( !$userExists && !$ip ) {
334 $messages->addWithKey(
335 'userpage-userdoesnotexist',
339 'mw-userpage-userdoesnotexist'
345 $blockLogBox = LogEventsList::getBlockLogWarningBox(
347 $this->namespaceInfo,
353 if ( $blockLogBox !==
null ) {
354 $messages->addWithKey(
'blocked-notice-logextract', $blockLogBox );
362 private function addEditIntro(
363 IntroMessageList $messages,
365 ProperPageIdentity $page,
366 Authority $performer,
370 if ( ( $editIntro === null || $editIntro ===
'' ) && $section ===
'new' ) {
372 $editIntro =
'MediaWiki:addsection-editintro';
374 if ( $editIntro !==
null && $editIntro !==
'' ) {
375 $introTitle = Title::newFromText( $editIntro );
379 $introTitle = $this->getTargetTitleIfSpecialMyLanguage( $introTitle );
381 if ( $this->isPageExistingAndViewable( $introTitle, $performer ) ) {
382 $messages->addWithKey(
384 $localizer->
msg(
new RawMessage(
386 '<div class="mw-editintro">{{:' . $introTitle->getFullText() .
'}}</div>'
389 ->inContentLanguage()
396 if ( !$page->exists() ) {
397 $helpLink = $this->urlUtils->expand(
398 Skin::makeInternalOrExternalUrl(
399 $localizer->
msg(
'helppage' )->inContentLanguage()->text()
403 if ( $helpLink ===
null ) {
404 throw new LogicException(
'Help link was invalid, this should be impossible' );
406 if ( $performer->getUser()->isRegistered() ) {
408 $localizer->
msg(
'newarticletext', $helpLink ),
410 "<div class=\"mw-newarticletext plainlinks\">\n$1\n</div>"
414 $localizer->
msg(
'newarticletextanon', $helpLink ),
416 "<div class=\"mw-newarticletextanon plainlinks\">\n$1\n</div>"
422 private function addRecreateWarning(
423 IntroMessageList $messages,
425 ProperPageIdentity $page
427 # Give a notice
if the user is editing a deleted/moved page...
428 if ( !$page->exists() ) {
429 $dbr = $this->dbProvider->getReplicaDatabase();
431 $messages->addWithKey(
432 'recreate-moveddeleted-warn',
433 $this->getLogExtract( [
'delete',
'move',
'merge' ], $page,
'', [
435 'conds' => [ $dbr->expr(
'log_action',
'!=',
'revision' ) ],
436 'showIfEmpty' =>
false,
437 'msgKey' => [
'recreate-moveddeleted-warn' ],
443 private function addTalkPageText(
444 IntroMessageList $messages,
448 if ( $title->isTalkPage() ) {
449 $messages->add( $localizer->
msg(
'talkpagetext' ) );
453 private function addEditNotices(
454 IntroMessageList $messages,
457 ?RevisionRecord $revRecord
459 $editNotices = $title->getEditNotices( $revRecord ? $revRecord->getId() : 0 );
460 if ( count( $editNotices ) ) {
461 foreach ( $editNotices as $key => $html ) {
462 $messages->addWithKey( $key, $html );
465 $msg = $localizer->
msg(
'editnotice-notext' );
466 if ( !$msg->isDisabled() ) {
467 $messages->addWithKey(
471 [
'class' =>
'mw-editnotice-notext' ],
479 private function addOldRevisionWarning(
480 IntroMessageList $messages,
482 ?RevisionRecord $revRecord
484 if ( $revRecord && !$revRecord->isCurrent() ) {
486 $messages->addWithKey(
'editingold', Html::warningBox( $localizer->
msg(
'editingold' )->parse() ) );
490 private function addReadOnlyWarning(
491 IntroMessageList $messages,
494 if ( $this->readOnlyMode->isReadOnly() ) {
496 $localizer->
msg(
'readonlywarning', $this->readOnlyMode->getReason() ),
497 "<div id=\"mw-read-only-warning\">\n$1\n</div>"
502 private function addAnonEditWarning(
503 IntroMessageList $messages,
506 Authority $performer,
507 ?
string $returnToQuery,
510 if ( !$performer->
getUser()->isRegistered() ) {
511 $tempUserCreateActive = $this->tempUserCreator->shouldAutoCreate( $performer,
'edit' );
513 $messages->addWithKey(
516 $tempUserCreateActive ?
'autocreate-edit-warning' :
'anoneditwarning',
518 SpecialPage::getTitleFor(
'Userlogin' )->getFullURL( [
519 'returnto' => $title->getPrefixedDBkey(),
520 'returntoquery' => $returnToQuery,
523 SpecialPage::getTitleFor(
'CreateAccount' )->getFullURL( [
524 'returnto' => $title->getPrefixedDBkey(),
525 'returntoquery' => $returnToQuery,
528 Html::warningBox(
'$1',
'mw-anon-edit-warning' )
531 $messages->addWithKey(
533 $localizer->
msg( $tempUserCreateActive ?
'autocreate-preview-warning' :
'anonpreviewwarning' )
535 Html::warningBox(
'$1',
'mw-anon-preview-warning' ) );
544 private function isWrongCaseUserConfigPage( Title $title ): bool {
545 if ( $title->isUserCssConfigPage() || $title->isUserJsConfigPage() ) {
546 $name = $title->getSkinFromConfigSubpage();
547 $skins = array_merge(
548 array_keys( $this->skinFactory->getInstalledSkins() ),
551 return !in_array( $name, $skins,
true )
552 && in_array( strtolower( $name ), $skins,
true );
558 private function addUserConfigPageInfo(
559 IntroMessageList $messages,
562 Authority $performer,
565 if ( $title->isUserConfigPage() ) {
566 # Check the skin exists
567 if ( $this->isWrongCaseUserConfigPage( $title ) ) {
569 $localizer->
msg(
'userinvalidconfigtitle', $title->getSkinFromConfigSubpage() ),
570 Html::errorBox(
'$1',
'',
'mw-userinvalidconfigtitle' )
573 if ( $title->isSubpageOf( Title::makeTitle(
NS_USER, $performer->getUser()->getName() ) ) ) {
574 $isUserCssConfig = $title->isUserCssConfigPage();
575 $isUserJsonConfig = $title->isUserJsonConfigPage();
576 $isUserJsConfig = $title->isUserJsConfigPage();
579 if ( $isUserCssConfig && $this->config->get( MainConfigNames::AllowUserCss ) ) {
581 $localizer->
msg(
'usercssyoucanpreview' ),
582 "<div id='mw-usercssyoucanpreview'>\n$1\n</div>"
584 } elseif ( $isUserJsonConfig ) {
586 $localizer->
msg(
'userjsonyoucanpreview' ),
587 "<div id='mw-userjsonyoucanpreview'>\n$1\n</div>"
589 } elseif ( $isUserJsConfig && $this->config->get( MainConfigNames::AllowUserJs ) ) {
591 $localizer->
msg(
'userjsyoucanpreview' ),
592 "<div id='mw-userjsyoucanpreview'>\n$1\n</div>"
600 private function addPageProtectionWarningHeaders(
601 IntroMessageList $messages,
603 ProperPageIdentity $page
605 if ( $this->restrictionStore->isProtected( $page,
'edit' ) &&
606 $this->permManager->getNamespaceRestrictionLevels(
607 $page->getNamespace()
610 # Is the title semi-protected?
611 if ( $this->restrictionStore->isSemiProtected( $page ) ) {
612 $noticeMsg =
'semiprotectedpagewarning';
614 # Then it must be protected based on static groups (regular)
615 $noticeMsg =
'protectedpagewarning';
617 $messages->addWithKey(
619 $this->getLogExtract(
'protect', $page,
'', [
'lim' => 1,
'msgKey' => [ $noticeMsg ] ] )
622 if ( $this->restrictionStore->isCascadeProtected( $page ) ) {
623 # Is this page under cascading protection from some source pages?
624 $tlCascadeSources = $this->restrictionStore->getCascadeProtectionSources( $page )[2];
625 if ( $tlCascadeSources ) {
627 # Explain, and list the titles responsible
628 foreach ( $tlCascadeSources as
$source ) {
629 $htmlList .= Html::rawElement(
'li', [], $this->linkRenderer->makeLink(
$source ) );
631 $messages->addWithKey(
632 'cascadeprotectedwarning',
633 $localizer->
msg(
'cascadeprotectedwarning', count( $tlCascadeSources ) )->parse() .
634 ( $htmlList ? Html::rawElement(
'ul', [], $htmlList ) :
'' ),
635 Html::warningBox(
'$1',
'mw-cascadeprotectedwarning' )
639 if ( !$page->exists() && $this->restrictionStore->getRestrictions( $page,
'create' ) ) {
640 $messages->addWithKey(
641 'titleprotectedwarning',
642 $this->getLogExtract(
647 'showIfEmpty' =>
false,
648 'msgKey' => [
'titleprotectedwarning' ],
649 'wrap' =>
"<div class=\"mw-titleprotectedwarning\">\n$1</div>"
656 private function addHeaderCopyrightWarning(
657 IntroMessageList $messages,
661 $localizer->msg(
'editpage-head-copy-warn' ),
662 "<div class='editpage-head-copywarn'>\n$1\n</div>"