103 private $watch =
false;
138 parent::__construct(
'Movepage' );
139 $this->movePageFactory = $movePageFactory;
140 $this->permManager = $permManager;
141 $this->userOptionsLookup = $userOptionsLookup;
142 $this->dbProvider = $dbProvider;
143 $this->contentHandlerFactory = $contentHandlerFactory;
144 $this->nsInfo = $nsInfo;
145 $this->linkBatchFactory = $linkBatchFactory;
146 $this->repoGroup = $repoGroup;
147 $this->wikiPageFactory = $wikiPageFactory;
148 $this->searchEngineFactory = $searchEngineFactory;
149 $this->watchlistManager = $watchlistManager;
150 $this->watchedItemStore = $watchedItemStore;
151 $this->restrictionStore = $restrictionStore;
152 $this->titleFactory = $titleFactory;
153 $this->deletePageFactory = $deletePageFactory;
169 $target = $par ?? $request->getText(
'target' );
170 $oldTitleText = $request->getText(
'wpOldTitle', $target );
171 $this->oldTitle = Title::newFromText( $oldTitleText );
173 if ( !$this->oldTitle ) {
177 $this->
getOutput()->addBacklinkSubtitle( $this->oldTitle );
179 $this->
getOutput()->addModuleStyles(
'mediawiki.codex.messagebox.styles' );
181 if ( !$this->oldTitle->exists() ) {
185 $newTitleTextMain = $request->getText(
'wpNewTitleMain' );
186 $newTitleTextNs = $request->getInt(
'wpNewTitleNs', $this->oldTitle->getNamespace() );
189 $newTitleText_bc = $request->getText(
'wpNewTitle' );
190 $this->newTitle = strlen( $newTitleText_bc ) > 0
191 ? Title::newFromText( $newTitleText_bc )
192 : Title::makeTitleSafe( $newTitleTextNs, $newTitleTextMain );
195 $isSubmit = $request->getRawVal(
'action' ) ===
'submit' && $request->wasPosted();
197 $reasonList = $request->getText(
'wpReasonList',
'other' );
198 $reason = $request->getText(
'wpReason' );
199 if ( $reasonList ===
'other' ) {
202 $this->reason = $reasonList . $this->
msg(
'colon-separator' )->inContentLanguage()->text() .
$reason;
204 $this->reason = $reasonList;
209 $this->moveTalk = $request->getBool(
'wpMovetalk', $def );
210 $this->fixRedirects = $request->getBool(
'wpFixRedirects', $def );
211 $this->leaveRedirect = $request->getBool(
'wpLeaveRedirect', $def );
213 $this->moveSubpages = $request->getBool(
'wpMovesubpages', $def );
214 $this->deleteAndMove = $request->getBool(
'wpDeleteAndMove' );
215 $this->moveOverShared = $request->getBool(
'wpMoveOverSharedFile' );
216 $this->watch = $request->getCheck(
'wpWatch' ) && $user->isRegistered();
220 if ( $isSubmit && $user->matchEditToken( $request->getVal(
'wpEditToken' ) ) ) {
222 $permStatus = $this->permManager->getPermissionStatus(
'move', $user, $this->oldTitle,
223 PermissionManager::RIGOR_SECURE );
225 $user->scheduleSpreadBlock();
226 if ( !$permStatus->isGood() ) {
232 $permStatus = $this->permManager->getPermissionStatus(
'move', $user, $this->oldTitle,
233 PermissionManager::RIGOR_FULL );
234 if ( !$permStatus->isGood() ) {
235 $user->scheduleSpreadBlock();
248 private function showForm( ?
StatusValue $status =
null ) {
249 $this->
getSkin()->setRelevantTitle( $this->oldTitle );
252 $out->setPageTitleMsg( $this->
msg(
'move-page' )->plaintextParams( $this->oldTitle->getPrefixedText() ) );
253 $out->addModuleStyles( [
255 'mediawiki.interface.helpers.styles'
257 $out->addModules(
'mediawiki.misc-authed-ooui' );
260 $handler = $this->contentHandlerFactory
261 ->getContentHandler( $this->oldTitle->getContentModel() );
262 $createRedirect = $handler->supportsRedirects() && !(
270 $out->addWikiMsg(
'movepagetext' );
272 $out->addWikiMsg( $createRedirect ?
273 'movepagetext-noredirectfixer' :
274 'movepagetext-noredirectsupport' );
277 if ( $this->oldTitle->getNamespace() ===
NS_USER && !$this->oldTitle->isSubpage() ) {
280 $out->msg(
'moveuserpage-warning' )->parse(),
281 'mw-moveuserpage-warning'
284 } elseif ( $this->oldTitle->getNamespace() ===
NS_CATEGORY ) {
287 $out->msg(
'movecategorypage-warning' )->parse(),
288 'mw-movecategorypage-warning'
300 # Show the current title as a default
301 # when the form is first opened.
303 } elseif ( !$status ) {
304 # If a title was supplied, probably from the move log revert
305 # link, check for validity. We can then show some diagnostic
306 # information and save a click.
307 $mp = $this->movePageFactory->newMovePage( $this->oldTitle,
$newTitle );
308 $status = $mp->isValidMove();
309 $status->merge( $mp->probablyCanMove( $this->getAuthority() ) );
315 if ( count( $status->getMessages() ) == 1 ) {
316 if ( $status->hasMessage(
'articleexists' )
317 && $this->permManager->quickUserCan(
'delete', $user,
$newTitle )
326 } elseif ( $status->hasMessage(
'redirectexists' ) && (
328 $this->permManager->quickUserCan(
'delete-redirect', $user,
$newTitle ) ||
329 $this->permManager->quickUserCan(
'delete', $user,
$newTitle ) )
338 } elseif ( $status->hasMessage(
'file-exists-sharedrepo' )
339 && $this->permManager->userHasRight( $user,
'reupload-shared' )
351 $oldTalk = $this->oldTitle->getTalkPageIfDefined();
352 $oldTitleSubpages = $this->oldTitle->hasSubpages();
353 $oldTitleTalkSubpages = $this->oldTitle->getTalkPageIfDefined()->hasSubpages();
355 $canMoveSubpage = ( $oldTitleSubpages || $oldTitleTalkSubpages ) &&
356 $this->permManager->quickUserCan(
362 # We also want to be able to move assoc. subpage talk-pages even if base page
363 # has no associated talk page, so || with $oldTitleTalkSubpages.
364 $considerTalk = !$this->oldTitle->isTalkPage() &&
366 || ( $oldTitleTalkSubpages && $canMoveSubpage ) );
369 $queryBuilder = $this->dbProvider->getReplicaDatabase()->newSelectQueryBuilder()
372 ->where( [
'rd_namespace' => $this->oldTitle->getNamespace() ] )
373 ->andWhere( [
'rd_title' => $this->oldTitle->getDBkey() ] )
374 ->andWhere( [
'rd_interwiki' =>
'' ] );
376 $hasRedirects = (bool)$queryBuilder->caller( __METHOD__ )->fetchField();
378 $hasRedirects =
false;
381 $messages = $status->getMessages();
383 if ( $status instanceof PermissionStatus ) {
384 $action_desc = $this->
msg(
'action-move' )->plain();
385 $errMsgHtml = $this->
msg(
'permissionserrorstext-withaction',
386 count( $messages ), $action_desc )->parseAsBlock();
388 $errMsgHtml = $this->
msg(
'cannotmove', count( $messages ) )->parseAsBlock();
391 if ( count( $messages ) == 1 ) {
392 $errMsgHtml .= $this->
msg( $messages[0] )->parseAsBlock();
396 foreach ( $messages as $msg ) {
397 $errStr[] = $this->
msg( $msg )->parse();
400 $errMsgHtml .=
'<ul><li>' . implode(
"</li>\n<li>", $errStr ) .
"</li></ul>\n";
402 $out->addHTML( Html::errorBox( $errMsgHtml ) );
405 if ( $this->restrictionStore->isProtected( $this->oldTitle,
'move' ) ) {
406 # Is the title semi-protected?
407 if ( $this->restrictionStore->isSemiProtected( $this->oldTitle,
'move' ) ) {
408 $noticeMsg =
'semiprotectedpagemovewarning';
410 # Then it must be protected based on static groups (regular)
411 $noticeMsg =
'protectedpagemovewarning';
413 LogEventsList::showLogExtract(
418 [
'lim' => 1,
'msgKey' => $noticeMsg ]
425 $immovableNamespaces = [];
426 foreach ( $this->
getLanguage()->getNamespaces() as $nsId => $_ ) {
427 if ( !$this->nsInfo->isMovable( $nsId ) ) {
428 $immovableNamespaces[] = $nsId;
435 $fields[] =
new FieldLayout(
436 new ComplexTitleInputWidget( [
437 'id' =>
'wpNewTitle',
439 'id' =>
'wpNewTitleNs',
440 'name' =>
'wpNewTitleNs',
442 'exclude' => $immovableNamespaces,
445 'id' =>
'wpNewTitleMain',
446 'name' =>
'wpNewTitleMain',
449 'suggestions' =>
false,
454 'label' => $this->msg(
'newtitle' )->text(),
459 $options = Html::listDropdownOptions(
460 $this->
msg(
'movepage-reason-dropdown' )
461 ->page( $this->oldTitle )
462 ->inContentLanguage()
464 [
'other' => $this->
msg(
'movereasonotherlist' )->text() ]
466 $options = Html::listDropdownOptionsOoui( $options );
468 $fields[] =
new FieldLayout(
469 new DropdownInputWidget( [
470 'name' =>
'wpReasonList',
471 'inputId' =>
'wpReasonList',
473 'value' => $this->
getRequest()->getText(
'wpReasonList',
'other' ),
474 'options' => $options,
477 'label' => $this->
msg(
'movereason' )->text(),
485 $fields[] =
new FieldLayout(
486 new TextInputWidget( [
487 'name' =>
'wpReason',
489 'maxLength' => CommentStore::COMMENT_CHARACTER_LIMIT,
491 'value' => $this->
getRequest()->getText(
'wpReason' ),
494 'label' => $this->
msg(
'moveotherreason' )->text(),
499 if ( $considerTalk ) {
500 $fields[] =
new FieldLayout(
501 new CheckboxInputWidget( [
502 'name' =>
'wpMovetalk',
503 'id' =>
'wpMovetalk',
505 'selected' => $this->moveTalk,
508 'label' => $this->
msg(
'movetalk' )->text(),
509 'help' =>
new HtmlSnippet( $this->
msg(
'movepagetalktext' )->parseAsBlock() ),
510 'helpInline' =>
true,
512 'id' =>
'wpMovetalk-field',
517 if ( $this->permManager->userHasRight( $user,
'suppressredirect' ) ) {
518 if ( $createRedirect ) {
525 $fields[] =
new FieldLayout(
526 new CheckboxInputWidget( [
527 'name' =>
'wpLeaveRedirect',
528 'id' =>
'wpLeaveRedirect',
530 'selected' => $isChecked,
531 'disabled' => $isDisabled,
534 'label' => $this->
msg(
'move-leave-redirect' )->text(),
540 if ( $hasRedirects ) {
541 $fields[] =
new FieldLayout(
542 new CheckboxInputWidget( [
543 'name' =>
'wpFixRedirects',
544 'id' =>
'wpFixRedirects',
546 'selected' => $this->fixRedirects,
549 'label' => $this->
msg(
'fix-double-redirects' )->text(),
555 if ( $canMoveSubpage ) {
557 $fields[] =
new FieldLayout(
558 new CheckboxInputWidget( [
559 'name' =>
'wpMovesubpages',
560 'id' =>
'wpMovesubpages',
562 'selected' => $this->moveSubpages,
565 'label' =>
new HtmlSnippet(
567 ( $this->oldTitle->hasSubpages()
569 :
'move-talk-subpages' )
570 )->numParams( $maximumMovedPages )->params( $maximumMovedPages )->parse()
577 # Don't allow watching if user is not logged in
578 if ( $user->isRegistered() ) {
579 $watchChecked = ( $this->watch || $this->userOptionsLookup->getBoolOption( $user,
'watchmoves' )
580 || $this->watchlistManager->isWatched( $user, $this->oldTitle ) );
581 $fields[] =
new FieldLayout(
582 new CheckboxInputWidget( [
584 'id' =>
'watch', # ew
587 'selected' => $watchChecked,
590 'label' => $this->
msg(
'move-watch' )->text(),
595 # Add a dropdown for watchlist expiry times in the form, T261230
597 $expiryOptions = WatchAction::getExpiryOptions(
599 $this->watchedItemStore->getWatchedItem( $user, $this->oldTitle )
601 # Reformat the options to match what DropdownInputWidget wants.
603 foreach ( $expiryOptions[
'options'] as $label => $value ) {
604 $options[] = [
'data' => $value,
'label' => $label ];
607 $fields[] =
new FieldLayout(
608 new DropdownInputWidget( [
609 'name' =>
'wpWatchlistExpiry',
610 'id' =>
'wpWatchlistExpiry',
612 'options' => $options,
615 'label' => $this->
msg(
'confirm-watch-label' )->text(),
616 'id' =>
'wpWatchlistExpiryLabel',
626 $hiddenFields .= Html::hidden(
'wpMoveOverSharedFile',
'1' );
630 $fields[] =
new FieldLayout(
631 new CheckboxInputWidget( [
632 'name' =>
'wpDeleteAndMove',
633 'id' =>
'wpDeleteAndMove',
637 'label' => $this->
msg(
'delete_and_move_confirm', $newTitle->
getPrefixedText() )->text(),
643 $fields[] =
new FieldLayout(
644 new ButtonInputWidget( [
646 'value' => $this->
msg(
'movepagebtn' )->text(),
647 'label' => $this->
msg(
'movepagebtn' )->text(),
648 'flags' => [
'primary',
'progressive' ],
656 $fieldset =
new FieldsetLayout( [
657 'label' => $this->
msg(
'move-page-legend' )->text(),
658 'id' =>
'mw-movepage-table',
662 $form =
new FormLayout( [
664 'action' => $this->
getPageTitle()->getLocalURL(
'action=submit' ),
667 $form->appendContent(
671 Html::hidden(
'wpOldTitle', $this->oldTitle->getPrefixedText() ) .
672 Html::hidden(
'wpEditToken', $user->getEditToken() )
678 'classes' => [
'movepage-wrapper' ],
685 if ( $this->
getAuthority()->isAllowed(
'editinterface' ) ) {
687 $this->
msg(
'movepage-reason-dropdown' )->inContentLanguage()->
getTitle(),
688 $this->
msg(
'movepage-edit-reasonlist' )->text(),
690 [
'action' =>
'edit' ]
692 $out->addHTML( Html::rawElement(
'p', [
'class' =>
'mw-movepage-editreasons' ], $link ) );
695 $this->showLogFragment( $this->oldTitle );
696 $this->showSubpages( $this->oldTitle );
699 private function doSubmit() {
702 if ( $user->pingLimiter(
'move' ) ) {
703 throw new ThrottledError;
709 # don't allow moving to pages with # in
710 if ( !$nt || $nt->hasFragment() ) {
711 $this->showForm( StatusValue::newFatal(
'badtitletext' ) );
716 # Show a warning if the target file exists on a shared repo
717 if ( $nt->getNamespace() ===
NS_FILE
718 && !( $this->moveOverShared && $this->permManager->userHasRight( $user,
'reupload-shared' ) )
719 && !$this->repoGroup->getLocalRepo()->findFile( $nt )
720 && $this->repoGroup->findFile( $nt )
722 $this->showForm( StatusValue::newFatal(
'file-exists-sharedrepo' ) );
727 # Delete to make way if requested
728 if ( $this->deleteAndMove ) {
729 $redir2 = $nt->isSingleRevRedirect();
731 $permStatus = $this->permManager->getPermissionStatus(
732 $redir2 ?
'delete-redirect' :
'delete',
735 if ( !$permStatus->isGood() ) {
737 if ( !$this->permManager->userCan(
'delete', $user, $nt ) ) {
739 $this->showForm( $permStatus );
748 $this->showForm( $permStatus );
753 $page = $this->wikiPageFactory->newFromTitle( $nt );
754 $delPage = $this->deletePageFactory->newDeletePage( $page, $user );
757 if ( $delPage->isBatchedDelete( 5 ) ) {
758 $this->showForm( StatusValue::newFatal(
'movepage-delete-first' ) );
763 $reason = $this->
msg(
'delete_and_move_reason', $ot )->inContentLanguage()->text();
766 if ( $nt->getNamespace() ===
NS_FILE ) {
767 $file = $this->repoGroup->getLocalRepo()->newFile( $nt );
768 $file->load( IDBAccessObject::READ_LATEST );
769 if ( $file->exists() ) {
770 $file->deleteFile(
$reason, $user,
false );
774 $deletionLog = $redir2 ?
'delete_redir2' :
'delete';
775 $deleteStatus = $delPage
776 ->setLogSubtype( $deletionLog )
778 ->forceImmediate(
true )
781 if ( !$deleteStatus->isGood() ) {
782 $this->showForm( $deleteStatus );
788 $handler = $this->contentHandlerFactory->getContentHandler( $ot->getContentModel() );
790 if ( !$handler->supportsRedirects() || (
796 $createRedirect =
false;
797 } elseif ( $this->permManager->userHasRight( $user,
'suppressredirect' ) ) {
800 $createRedirect =
true;
803 # Do the actual move.
804 $mp = $this->movePageFactory->newMovePage( $ot, $nt );
806 if ( $ot->isTalkPage() || $nt->isTalkPage() ) {
807 $this->moveTalk =
false;
809 if ( $this->moveSubpages ) {
810 $this->moveSubpages = $this->permManager->userCan(
'move-subpages', $user, $ot );
813 # check whether the requested actions are permitted / possible
814 $permStatus = $mp->authorizeMove( $this->
getAuthority(), $this->reason );
815 if ( !$permStatus->isOK() ) {
816 $this->showForm( $permStatus );
819 $status = $mp->moveIfAllowed( $this->
getAuthority(), $this->reason, $createRedirect );
820 if ( !$status->isOK() ) {
821 $this->showForm( $status );
830 $out->setPageTitleMsg( $this->
msg(
'pagemovedsub' ) );
833 $oldLink = $linkRenderer->makeLink(
836 [
'id' =>
'movepage-oldlink' ],
837 [
'redirect' =>
'no' ]
839 $newLink = $linkRenderer->makeKnownLink(
842 [
'id' =>
'movepage-newlink' ]
844 $oldText = $ot->getPrefixedText();
845 $newText = $nt->getPrefixedText();
847 if ( $status->getValue()[
'redirectRevision'] !==
null ) {
848 $msgName =
'movepage-moved-redirect';
850 $msgName =
'movepage-moved-noredirect';
853 $out->addHTML( $this->
msg(
'movepage-moved' )->rawParams( $oldLink,
854 $newLink )->params( $oldText, $newText )->parseAsBlock() );
855 $out->addWikiMsg( $msgName );
857 $this->
getHookRunner()->onSpecialMovepageAfterMove( $this, $ot, $nt );
874 $dbr = $this->dbProvider->getReplicaDatabase();
875 if ( $this->moveSubpages && (
876 $this->nsInfo->hasSubpages( $nt->getNamespace() ) || (
878 && $this->nsInfo->hasSubpages( $nt->getTalkPage()->getNamespace() )
885 new LikeValue( $ot->getDBkey() .
'/', $dbr->anyString() )
886 )->or(
'page_title',
'=', $ot->getDBkey() )
888 $conds[
'page_namespace'] = [];
889 if ( $this->nsInfo->hasSubpages( $nt->getNamespace() ) ) {
890 $conds[
'page_namespace'][] = $ot->getNamespace();
892 if ( $this->moveTalk &&
893 $this->nsInfo->hasSubpages( $nt->getTalkPage()->getNamespace() )
895 $conds[
'page_namespace'][] = $ot->getTalkPage()->getNamespace();
897 } elseif ( $this->moveTalk ) {
899 'page_namespace' => $ot->getTalkPage()->getNamespace(),
900 'page_title' => $ot->getDBkey()
908 if ( $conds !==
null ) {
909 $extraPages = $this->titleFactory->newTitleArrayFromResult(
910 $dbr->newSelectQueryBuilder()
911 ->select( [
'page_id',
'page_namespace',
'page_title' ] )
914 ->caller( __METHOD__ )->fetchResultSet()
920 foreach ( $extraPages as $oldSubpage ) {
921 if ( $ot->equals( $oldSubpage ) || $nt->equals( $oldSubpage ) ) {
922 # Already did this one.
926 $newPageName = preg_replace(
927 '#^' . preg_quote( $ot->getDBkey(),
'#' ) .
'#',
928 StringUtils::escapeRegexReplacement( $nt->getDBkey() ), # T23234
929 $oldSubpage->getDBkey()
932 if ( $oldSubpage->isSubpage() && ( $ot->isTalkPage() xor $nt->isTalkPage() ) ) {
934 $newNs = $nt->getNamespace();
935 } elseif ( $oldSubpage->isTalkPage() ) {
936 $newNs = $nt->getTalkPage()->getNamespace();
938 $newNs = $nt->getSubjectPage()->getNamespace();
941 # T16385: we need makeTitleSafe because the new page names may
942 # be longer than 255 characters.
943 $newSubpage = Title::makeTitleSafe( $newNs, $newPageName );
944 if ( !$newSubpage ) {
945 $oldLink = $linkRenderer->makeKnownLink( $oldSubpage );
946 $extraOutput[] = $this->
msg(
'movepage-page-unmoved' )->rawParams( $oldLink )
947 ->params( Title::makeName( $newNs, $newPageName ) )->escaped();
951 $mp = $this->movePageFactory->newMovePage( $oldSubpage, $newSubpage );
952 # This was copy-pasted from Renameuser, bleh.
953 if ( $newSubpage->exists() && !$mp->isValidMove()->isOK() ) {
954 $link = $linkRenderer->makeKnownLink( $newSubpage );
955 $extraOutput[] = $this->
msg(
'movepage-page-exists' )->rawParams( $link )->escaped();
957 $status = $mp->moveIfAllowed( $this->
getAuthority(), $this->reason, $createRedirect );
959 if ( $status->isOK() ) {
960 if ( $this->fixRedirects ) {
963 $oldLink = $linkRenderer->makeLink(
967 [
'redirect' =>
'no' ]
970 $newLink = $linkRenderer->makeKnownLink( $newSubpage );
971 $extraOutput[] = $this->
msg(
'movepage-page-moved' )
972 ->rawParams( $oldLink, $newLink )->escaped();
977 if ( $count >= $maximumMovedPages ) {
978 $extraOutput[] = $this->
msg(
'movepage-max-pages' )
979 ->numParams( $maximumMovedPages )->escaped();
983 $oldLink = $linkRenderer->makeKnownLink( $oldSubpage );
984 $newLink = $linkRenderer->makeLink( $newSubpage );
985 $extraOutput[] = $this->
msg(
'movepage-page-unmoved' )
986 ->rawParams( $oldLink, $newLink )->escaped();
991 if ( $extraOutput !== [] ) {
992 $out->addHTML(
"<ul>\n<li>" . implode(
"</li>\n<li>", $extraOutput ) .
"</li>\n</ul>" );
995 # Deal with watches (we don't watch subpages)
996 # Get text from expiry selection dropdown, T261230
997 $expiry = $this->
getRequest()->getText(
'wpWatchlistExpiry' );
999 $expiry = ExpiryDef::normalizeExpiry( $expiry, TS_ISO_8601 );
1004 $this->watchlistManager->setWatch(
1011 $this->watchlistManager->setWatch(
1019 private function showLogFragment( Title $title ) {
1020 $moveLogPage =
new LogPage(
'move' );
1022 $out->addHTML(
Html::element(
'h2', [], $moveLogPage->getName()->text() ) );
1023 LogEventsList::showLogExtract( $out,
'move', $title );
1032 private function showSubpages( $title ) {
1034 $nsHasSubpages = $this->nsInfo->hasSubpages( $title->getNamespace() );
1035 $subpages = $title->getSubpages( $maximumMovedPages + 1 );
1036 $count = $subpages instanceof TitleArrayFromResult ? $subpages->count() : 0;
1038 $titleIsTalk = $title->isTalkPage();
1039 $subpagesTalk = $title->getTalkPage()->getSubpages( $maximumMovedPages + 1 );
1040 $countTalk = $subpagesTalk instanceof TitleArrayFromResult ? $subpagesTalk->count() : 0;
1041 $totalCount = $count + $countTalk;
1043 if ( !$nsHasSubpages && $countTalk == 0 ) {
1049 [
'movesubpage', ( $titleIsTalk ? $count : $totalCount ) ]
1052 if ( $nsHasSubpages ) {
1053 $this->showSubpagesList(
1054 $subpages, $count,
'movesubpagetext',
'movesubpagetext-truncated',
true
1058 if ( !$titleIsTalk && $countTalk > 0 ) {
1059 $this->showSubpagesList(
1060 $subpagesTalk, $countTalk,
'movesubpagetalktext',
'movesubpagetalktext-truncated'
1065 private function showSubpagesList(
1066 TitleArrayFromResult $subpages,
int $pagecount,
string $msg,
string $truncatedMsg,
bool $noSubpageMsg =
false
1071 if ( $pagecount == 0 && $noSubpageMsg ) {
1072 $out->addWikiMsg(
'movenosubpage' );
1078 if ( $pagecount > $maximumMovedPages ) {
1079 $subpages = $this->truncateSubpagesList( $subpages );
1080 $out->addWikiMsg( $truncatedMsg, $this->
getLanguage()->formatNum( $maximumMovedPages ) );
1082 $out->addWikiMsg( $msg, $this->
getLanguage()->formatNum( $pagecount ) );
1084 $out->addHTML(
"<ul>\n" );
1086 $this->linkBatchFactory->newLinkBatch( $subpages )
1087 ->setCaller( __METHOD__ )
1091 foreach ( $subpages as $subpage ) {
1092 $link = $linkRenderer->makeLink( $subpage );
1093 $out->addHTML(
"<li>$link</li>\n" );
1095 $out->addHTML(
"</ul>\n" );
1098 private function truncateSubpagesList( iterable $subpages ): array {
1100 foreach ( $subpages as $subpage ) {
1101 $returnArray[] = $subpage;
1106 return $returnArray;
1118 return $this->prefixSearchString( $search, $limit, $offset, $this->searchEngineFactory );