52 private readonly
Config $config,
82 private function getLogExtract( $types = [], $page =
'', $user =
'', $param = [] ): string {
84 LogEventsList::showLogExtract( $outString, $types, $page, $user, $param );
120 ?
string $returnToQuery,
122 ?
string $section =
null
124 $title =
Title::newFromPageIdentity( $page );
127 $this->addOldRevisionWarning( $messages, $localizer, $revRecord );
130 $this->addCodeEditingIntro( $messages, $localizer, $title, $performer );
131 $this->addSharedRepoHint( $messages, $localizer, $page );
132 $this->addUserWarnings( $messages, $localizer, $title, $performer );
133 $this->addEditIntro( $messages, $localizer, $page, $performer, $editIntro, $section );
134 $this->addRecreateWarning( $messages, $page );
137 $this->addTalkPageText( $messages, $localizer, $title );
138 $this->addEditNotices( $messages, $localizer, $title, $revRecord );
140 $this->addReadOnlyWarning( $messages, $localizer );
141 $this->addAnonEditWarning( $messages, $localizer, $title, $performer, $returnToQuery, $preview );
142 $this->addUserConfigPageInfo( $messages, $localizer, $title, $performer, $preview );
143 $this->addPageProtectionWarningHeaders( $messages, $localizer, $page );
144 $this->addHeaderCopyrightWarning( $messages, $localizer );
146 return $messages->getList();
152 private function addCodeEditingIntro(
153 IntroMessageList $messages,
154 MessageLocalizer $localizer,
158 $isUserJsConfig = $title->isUserJsConfigPage();
159 $namespace = $title->getNamespace();
163 $title->isUserConfigPage() &&
164 $title->isSubpageOf( Title::makeTitle(
NS_USER, $performer->getUser()->getName() ) )
166 $isUserCssConfig = $title->isUserCssConfigPage();
167 $isUserJsonConfig = $title->isUserJsonConfigPage();
168 $isUserJsConfig = $title->isUserJsConfigPage();
170 if ( $isUserCssConfig ) {
171 $warning =
'usercssispublic';
172 } elseif ( $isUserJsonConfig ) {
173 $warning =
'userjsonispublic';
175 $warning =
'userjsispublic';
178 $warningText = $localizer->msg( $warning )->parse();
179 $intro .= $warningText ? Html::rawElement(
181 [
'class' =>
'mw-userconfigpublic' ],
186 $codeMsg = $localizer->msg(
'editpage-code-message' );
187 $codeMessageText = $codeMsg->isDisabled() ?
'' : $codeMsg->parseAsBlock();
193 $interfaceMsg = $localizer->msg(
'editinginterface' );
194 if ( $isJavaScript ) {
195 $interfaceMsg = $localizer->msg(
'editinginterfacejs' );
197 $interfaceMsgText = $interfaceMsg->parse();
198 # Show a warning if editing an interface message
199 $intro .= $interfaceMsgText ? Html::rawElement(
201 [
'class' =>
'mw-editinginterface' ],
204 # If this is a default message (but not css, json, js or vue),
205 # show a hint that it is translatable on translatewiki.net
210 && $this->shadowPageLoader->getMessageProvider()->existsForLink( $title )
212 $translateInterfaceText = $localizer->msg(
'translateinterface' )->parse();
213 $intro .= $translateInterfaceText ? Html::rawElement(
215 [
'class' =>
'mw-translateinterface' ],
216 $translateInterfaceText
221 if ( $isUserJsConfig ) {
222 $userConfigDangerousMsg = $localizer->msg(
'userjsdangerous' )->parse();
223 $intro .= $userConfigDangerousMsg ? Html::rawElement(
225 [
'class' =>
'mw-userconfigdangerous' ],
226 $userConfigDangerousMsg
231 if ( $isJavaScript || $isCSS ) {
232 $intro .= $codeMessageText;
235 $messages->addWithKey(
236 'code-editing-intro',
242 Html::warningBox(
'$1' )
246 private function addSharedRepoHint(
247 IntroMessageList $messages,
248 MessageLocalizer $localizer,
249 ProperPageIdentity $page
251 $namespace = $page->getNamespace();
252 if ( $namespace ===
NS_FILE ) {
253 # Show a hint to shared repo
254 $file = $this->repoGroup->findFile( $page );
255 if ( $file && !$file->isLocal() ) {
256 $descUrl = $file->getDescriptionUrl();
257 # there must be a description url to show a hint to shared repo
259 if ( !$page->exists() ) {
262 'sharedupload-desc-create',
263 $file->getRepo()->getDisplayName(),
266 "<div class=\"mw-sharedupload-desc-create\">\n$1\n</div>"
271 'sharedupload-desc-edit',
272 $file->getRepo()->getDisplayName(),
275 "<div class=\"mw-sharedupload-desc-edit\">\n$1\n</div>"
283 private function addUserWarnings(
284 IntroMessageList $messages,
285 MessageLocalizer $localizer,
289 $namespace = $title->getNamespace();
290 # Show a warning message when someone creates/edits a user (talk) page but the user does not exist
291 # Show log extract when the user is currently blocked
293 $username = explode(
'/', $title->getText(), 2 )[0];
295 $validation = UserRigorOptions::RIGOR_NONE;
296 $user = $this->userFactory->newFromName( $username, $validation );
297 $ip = $this->userNameUtils->isIP( $username );
299 $userExists = ( $user && $user->isRegistered() );
300 if ( $userExists && $user->isHidden() && !$performer->isAllowed(
'hideuser' ) ) {
306 if ( !$userExists && !$ip ) {
307 $messages->addWithKey(
308 'userpage-userdoesnotexist',
311 $localizer->msg(
'userpage-userdoesnotexist',
wfEscapeWikiText( $username ) )->parse(),
312 'mw-userpage-userdoesnotexist'
318 $blockLogBox = LogEventsList::getBlockLogWarningBox(
320 $this->namespaceInfo,
326 if ( $blockLogBox !==
null ) {
327 $messages->addWithKey(
'blocked-notice-logextract', $blockLogBox );
335 private function addEditIntro(
336 IntroMessageList $messages,
337 MessageLocalizer $localizer,
338 ProperPageIdentity $page,
339 Authority $performer,
343 if ( ( $editIntro === null || $editIntro ===
'' ) && $section ===
'new' ) {
345 $editIntro =
'MediaWiki:addsection-editintro';
347 if ( $editIntro !==
null && $editIntro !==
'' ) {
348 $introTitle = Title::newFromText( $editIntro );
352 $introTitle = $this->getTargetTitleIfSpecialMyLanguage( $introTitle );
354 if ( $this->isPageExistingAndViewable( $introTitle, $performer ) ) {
355 $messages->addWithKey(
357 $localizer->msg(
new RawMessage(
359 '<div class="mw-editintro">{{:' . $introTitle->getFullText() .
'}}</div>'
362 ->inContentLanguage()
369 if ( !$page->exists() ) {
370 $helpLink = $this->urlUtils->expand(
371 Skin::makeInternalOrExternalUrl(
372 $localizer->msg(
'helppage' )->inContentLanguage()->text()
376 if ( $helpLink ===
null ) {
377 throw new LogicException(
'Help link was invalid, this should be impossible' );
379 if ( $performer->getUser()->isRegistered() ) {
381 $localizer->msg(
'newarticletext', $helpLink ),
383 "<div class=\"mw-newarticletext plainlinks\">\n$1\n</div>"
387 $localizer->msg(
'newarticletextanon', $helpLink ),
389 "<div class=\"mw-newarticletextanon plainlinks\">\n$1\n</div>"
395 private function addRecreateWarning(
396 IntroMessageList $messages,
397 ProperPageIdentity $page
399 # Give a notice
if the user is editing a deleted/moved page...
400 if ( !$page->exists() ) {
401 $dbr = $this->dbProvider->getReplicaDatabase();
403 $messages->addWithKey(
404 'recreate-moveddeleted-warn',
405 $this->getLogExtract( [
'delete',
'move',
'merge' ], $page,
'', [
407 'conds' => [ $dbr->expr(
'log_action',
'!=',
'revision' ) ],
408 'showIfEmpty' =>
false,
409 'msgKey' => [
'recreate-moveddeleted-warn' ],
415 private function addTalkPageText(
416 IntroMessageList $messages,
417 MessageLocalizer $localizer,
420 if ( $title->isTalkPage() ) {
421 $messages->add( $localizer->msg(
'talkpagetext' ) );
425 private function addEditNotices(
426 IntroMessageList $messages,
427 MessageLocalizer $localizer,
429 ?RevisionRecord $revRecord
431 $editNotices = $title->getEditNotices( $revRecord ? $revRecord->getId() : 0 );
432 if ( count( $editNotices ) ) {
433 foreach ( $editNotices as $key => $html ) {
434 $messages->addWithKey( $key, $html );
437 $msg = $localizer->msg(
'editnotice-notext' );
438 if ( !$msg->isDisabled() ) {
439 $messages->addWithKey(
443 [
'class' =>
'mw-editnotice-notext' ],
451 private function addOldRevisionWarning(
452 IntroMessageList $messages,
453 MessageLocalizer $localizer,
454 ?RevisionRecord $revRecord
456 if ( $revRecord && !$revRecord->isCurrent() ) {
458 $messages->addWithKey(
'editingold', Html::warningBox( $localizer->msg(
'editingold' )->parse() ) );
462 private function addReadOnlyWarning(
463 IntroMessageList $messages,
464 MessageLocalizer $localizer
466 if ( $this->readOnlyMode->isReadOnly() ) {
468 $localizer->msg(
'readonlywarning', $this->readOnlyMode->getReason() ),
469 "<div id=\"mw-read-only-warning\">\n$1\n</div>"
474 private function addAnonEditWarning(
475 IntroMessageList $messages,
476 MessageLocalizer $localizer,
478 Authority $performer,
479 ?
string $returnToQuery,
482 if ( !$performer->
getUser()->isRegistered() ) {
483 $tempUserCreateActive = $this->tempUserCreator->shouldAutoCreate( $performer,
'edit' );
485 $messages->addWithKey(
488 $tempUserCreateActive ?
'autocreate-edit-warning' :
'anoneditwarning',
490 SpecialPage::getTitleFor(
'Userlogin' )->getFullURL( [
491 'returnto' => $title->getPrefixedDBkey(),
492 'returntoquery' => $returnToQuery,
495 SpecialPage::getTitleFor(
'CreateAccount' )->getFullURL( [
496 'returnto' => $title->getPrefixedDBkey(),
497 'returntoquery' => $returnToQuery,
500 Html::warningBox(
'$1',
'mw-anon-edit-warning' )
503 $messages->addWithKey(
505 $localizer->msg( $tempUserCreateActive ?
'autocreate-preview-warning' :
'anonpreviewwarning' )
507 Html::warningBox(
'$1',
'mw-anon-preview-warning' ) );
516 private function isWrongCaseUserConfigPage( Title $title ): bool {
517 if ( $title->isUserCssConfigPage() || $title->isUserJsConfigPage() ) {
518 $name = $title->getSkinFromConfigSubpage();
519 $skins = array_merge(
520 array_keys( $this->skinFactory->getInstalledSkins() ),
523 return !in_array( $name, $skins,
true )
524 && in_array( strtolower( $name ), $skins,
true );
530 private function addUserConfigPageInfo(
531 IntroMessageList $messages,
532 MessageLocalizer $localizer,
534 Authority $performer,
537 if ( $title->isUserConfigPage() ) {
538 # Check the skin exists
539 if ( $this->isWrongCaseUserConfigPage( $title ) ) {
541 $localizer->msg(
'userinvalidconfigtitle', $title->getSkinFromConfigSubpage() ),
542 Html::errorBox(
'$1',
'',
'mw-userinvalidconfigtitle' )
545 if ( $title->isSubpageOf( Title::makeTitle(
NS_USER, $performer->getUser()->getName() ) ) ) {
546 $isUserCssConfig = $title->isUserCssConfigPage();
547 $isUserJsonConfig = $title->isUserJsonConfigPage();
548 $isUserJsConfig = $title->isUserJsConfigPage();
551 if ( $isUserCssConfig && $this->config->get( MainConfigNames::AllowUserCss ) ) {
553 $localizer->msg(
'usercssyoucanpreview' ),
554 "<div id='mw-usercssyoucanpreview'>\n$1\n</div>"
556 } elseif ( $isUserJsonConfig ) {
558 $localizer->msg(
'userjsonyoucanpreview' ),
559 "<div id='mw-userjsonyoucanpreview'>\n$1\n</div>"
561 } elseif ( $isUserJsConfig && $this->config->get( MainConfigNames::AllowUserJs ) ) {
563 $localizer->msg(
'userjsyoucanpreview' ),
564 "<div id='mw-userjsyoucanpreview'>\n$1\n</div>"
572 private function addPageProtectionWarningHeaders(
573 IntroMessageList $messages,
574 MessageLocalizer $localizer,
575 ProperPageIdentity $page
577 if ( $this->restrictionStore->isProtected( $page,
'edit' ) &&
578 $this->permManager->getNamespaceRestrictionLevels(
579 $page->getNamespace()
582 # Is the title semi-protected?
583 if ( $this->restrictionStore->isSemiProtected( $page ) ) {
584 $noticeMsg =
'semiprotectedpagewarning';
586 # Then it must be protected based on static groups (regular)
587 $noticeMsg =
'protectedpagewarning';
589 $messages->addWithKey(
591 $this->getLogExtract(
'protect', $page,
'', [
'lim' => 1,
'msgKey' => [ $noticeMsg ] ] )
594 if ( $this->restrictionStore->isCascadeProtected( $page ) ) {
595 # Is this page under cascading protection from some source pages?
596 $tlCascadeSources = $this->restrictionStore->getCascadeProtectionSources( $page )[2];
597 if ( $tlCascadeSources ) {
599 # Explain, and list the titles responsible
600 foreach ( $tlCascadeSources as
$source ) {
601 $htmlList .= Html::rawElement(
'li', [], $this->linkRenderer->makeLink(
$source ) );
603 $messages->addWithKey(
604 'cascadeprotectedwarning',
605 $localizer->msg(
'cascadeprotectedwarning', count( $tlCascadeSources ) )->parse() .
606 ( $htmlList ? Html::rawElement(
'ul', [], $htmlList ) :
'' ),
607 Html::warningBox(
'$1',
'mw-cascadeprotectedwarning' )
611 if ( !$page->exists() && $this->restrictionStore->getRestrictions( $page,
'create' ) ) {
612 $messages->addWithKey(
613 'titleprotectedwarning',
614 $this->getLogExtract(
619 'showIfEmpty' =>
false,
620 'msgKey' => [
'titleprotectedwarning' ],
621 'wrap' =>
"<div class=\"mw-titleprotectedwarning\">\n$1</div>"
628 private function addHeaderCopyrightWarning(
629 IntroMessageList $messages,
630 MessageLocalizer $localizer
633 $localizer->
msg(
'editpage-head-copy-warn' ),
634 "<div class='editpage-head-copywarn'>\n$1\n</div>"