57 parent::__construct(
'Tags' );
58 $this->changeTagsStore = $changeTagsStore;
65 $this->
getOutput()->addModuleStyles(
'mediawiki.codex.messagebox.styles' );
86 private function showTagList() {
88 $out->setPageTitleMsg( $this->
msg(
'tags-title' ) );
89 $out->wrapWikiMsg(
"<div class='mw-tags-intro'>\n$1\n</div>",
'tags-intro' );
92 $userCanManage = $authority->isAllowed(
'managechangetags' );
93 $userCanDelete = $authority->isAllowed(
'deletechangetags' );
94 $userCanEditInterface = $authority->isAllowed(
'editinterface' );
97 if ( $userCanManage ) {
101 'label' => $this->
msg(
'tags-create-tag-name' )->plain(),
106 'maxlength' => CommentStore::COMMENT_CHARACTER_LIMIT,
107 'label' => $this->
msg(
'tags-create-reason' )->plain(),
110 'IgnoreWarnings' => [
115 HTMLForm::factory(
'ooui', $fields, $this->
getContext() )
116 ->setAction( $this->
getPageTitle(
'create' )->getLocalURL() )
117 ->setWrapperLegendMsg(
'tags-create-heading' )
118 ->setHeaderHtml( $this->
msg(
'tags-create-explanation' )->parseAsBlock() )
119 ->setSubmitCallback( [ $this,
'processCreateTagForm' ] )
120 ->setSubmitTextMsg(
'tags-create-submit' )
130 if ( $out->getRedirect() !==
'' ) {
136 $tagStats = $this->changeTagsStore->tagUsageStatistics();
139 $this->explicitlyDefinedTags = array_fill_keys(
140 $this->changeTagsStore->listExplicitlyDefinedTags(),
true );
141 $this->softwareDefinedTags = array_fill_keys(
142 $this->changeTagsStore->listSoftwareDefinedTags(),
true );
145 $definedTags = array_keys( $this->explicitlyDefinedTags + $this->softwareDefinedTags );
148 if ( !$tagStats && !$definedTags ) {
153 $thead = Xml::tags(
'tr',
null, Xml::tags(
'th',
null, $this->
msg(
'tags-tag' )->parse() ) .
154 Xml::tags(
'th',
null, $this->
msg(
'tags-display-header' )->parse() ) .
155 Xml::tags(
'th',
null, $this->
msg(
'tags-description-header' )->parse() ) .
156 Xml::tags(
'th',
null, $this->
msg(
'tags-source-header' )->parse() ) .
157 Xml::tags(
'th',
null, $this->
msg(
'tags-active-header' )->parse() ) .
158 Xml::tags(
'th',
null, $this->
msg(
'tags-hitcount-header' )->parse() ) .
159 ( ( $userCanManage || $userCanDelete ) ?
160 Xml::tags(
'th', [
'class' =>
'unsortable' ],
161 $this->
msg(
'tags-actions-header' )->parse() ) :
167 $this->softwareActivatedTags = array_fill_keys(
168 $this->changeTagsStore->listSoftwareActivatedTags(),
true );
171 foreach ( $tagStats as $tag => $hitcount ) {
172 $tbody .= $this->doTagRow( $tag, $hitcount, $userCanManage,
173 $userCanDelete, $userCanEditInterface );
176 foreach ( $definedTags as $tag ) {
177 if ( !isset( $tagStats[$tag] ) ) {
178 $tbody .= $this->doTagRow( $tag, 0, $userCanManage, $userCanDelete, $userCanEditInterface );
182 $out->addModuleStyles( [
183 'jquery.tablesorter.styles',
184 'mediawiki.pager.styles'
186 $out->addModules(
'jquery.tablesorter' );
187 $out->addHTML( Xml::tags(
189 [
'class' =>
'mw-datatable sortable mw-tags-table' ],
190 Xml::tags(
'thead',
null, $thead ) .
191 Xml::tags(
'tbody',
null, $tbody )
195 private function doTagRow(
196 $tag, $hitcount, $showManageActions, $showDeleteActions, $showEditLinks
199 $newRow .= Xml::tags(
'td',
null,
Xml::element(
'code',
null, $tag ) );
203 if ( $disp ===
false ) {
204 $disp =
Xml::element(
'em',
null, $this->
msg(
'tags-hidden' )->text() );
206 if ( $showEditLinks ) {
208 $editLink = $linkRenderer->makeLink(
210 $this->
msg(
'tags-edit' )->text(),
212 [
'action' =>
'edit' ]
214 $helpEditLink = $linkRenderer->makeLink(
215 $this->
msg(
"tag-$tag-helppage" )->inContentLanguage()->
getTitle(),
216 $this->
msg(
'tags-helppage-edit' )->text(),
218 [
'action' =>
'edit' ]
220 $disp .= $this->
msg(
'parentheses' )->rawParams(
221 $this->
getLanguage()->pipeList( [ $editLink, $helpEditLink ] )
224 $newRow .= Xml::tags(
'td',
null, $disp );
226 $msg = $this->
msg(
"tag-$tag-description" );
227 $desc = !$msg->exists() ?
'' : $msg->parse();
228 if ( $showEditLinks ) {
230 $editDescLink = $linkRenderer->makeLink(
231 $this->
msg(
"tag-$tag-description" )->inContentLanguage()->
getTitle(),
232 $this->
msg(
'tags-edit' )->text(),
234 [
'action' =>
'edit' ]
236 $desc .= $this->
msg(
'parentheses' )->rawParams( $editDescLink )->escaped();
238 $newRow .= Xml::tags(
'td',
null, $desc );
241 $isSoftware = isset( $this->softwareDefinedTags[$tag] );
242 $isExplicit = isset( $this->explicitlyDefinedTags[$tag] );
245 $sourceMsgs[] = $this->
msg(
'tags-source-extension' )->escaped();
248 $sourceMsgs[] = $this->
msg(
'tags-source-manual' )->escaped();
250 if ( !$sourceMsgs ) {
251 $sourceMsgs[] = $this->
msg(
'tags-source-none' )->escaped();
253 $newRow .= Xml::tags(
'td',
null, implode(
Xml::element(
'br' ), $sourceMsgs ) );
255 $isActive = $isExplicit || isset( $this->softwareActivatedTags[$tag] );
256 $activeMsg = ( $isActive ?
'tags-active-yes' :
'tags-active-no' );
257 $newRow .= Xml::tags(
'td',
null, $this->
msg( $activeMsg )->escaped() );
259 $hitcountLabelMsg = $this->
msg(
'tags-hitcount' )->numParams( $hitcount );
261 $hitcountLabel = $linkRenderer->makeLink(
263 $hitcountLabelMsg->text(),
265 [
'tagfilter' => $tag ]
268 $hitcountLabel = $hitcountLabelMsg->escaped();
272 $newRow .= Xml::tags(
'td', [
'data-sort-value' => $hitcount ], $hitcountLabel );
277 $actionLinks[] = $linkRenderer->makeKnownLink(
279 $this->
msg(
'tags-delete' )->text(),
284 if ( $showManageActions ) {
286 $actionLinks[] = $linkRenderer->makeKnownLink(
288 $this->
msg(
'tags-activate' )->text(),
294 $actionLinks[] = $linkRenderer->makeKnownLink(
296 $this->
msg(
'tags-deactivate' )->text(),
302 if ( $showDeleteActions || $showManageActions ) {
303 $newRow .= Xml::tags(
'td',
null, $this->
getLanguage()->pipeList( $actionLinks ) );
306 return Xml::tags(
'tr',
null, $newRow ) .
"\n";
311 $out = $context->getOutput();
313 $tag = trim( strval( $data[
'Tag'] ) );
314 $ignoreWarnings = isset( $data[
'IgnoreWarnings'] ) && $data[
'IgnoreWarnings'] ===
'1';
316 $context->getAuthority(), $ignoreWarnings );
318 if ( $status->isGood() ) {
321 } elseif ( $status->isOK() ) {
325 'IgnoreWarnings' => [
331 $headerText = $this->
msg(
'tags-create-warnings-above', $tag,
332 count( $status->getMessages(
'warning' ) ) )->parseAsBlock() .
333 $out->parseAsInterface( $status->getWikiText() ) .
334 $this->
msg(
'tags-create-warnings-below' )->parseAsBlock();
337 ->setSubmitTextMsg(
'htmlform-yes' );
342 foreach ( $status->getMessages() as $msg ) {
343 $out->addHTML( Html::errorBox(
344 $this->
msg( $msg )->parse()
353 if ( !$authority->isAllowed(
'deletechangetags' ) ) {
358 $out->setPageTitleMsg( $this->
msg(
'tags-delete-title' ) );
363 if ( !$canDeleteResult->isGood() ) {
364 foreach ( $canDeleteResult->getMessages() as $msg ) {
365 $out->addHTML( Html::errorBox(
366 $this->
msg( $msg )->parse()
369 if ( !$canDeleteResult->isOK() ) {
374 $preText = $this->
msg(
'tags-delete-explanation-initial', $tag )->parseAsBlock();
375 $tagUsage = $this->changeTagsStore->tagUsageStatistics();
376 if ( isset( $tagUsage[$tag] ) && $tagUsage[$tag] > 0 ) {
377 $preText .= $this->
msg(
'tags-delete-explanation-in-use', $tag,
378 $tagUsage[$tag] )->parseAsBlock();
380 $preText .= $this->
msg(
'tags-delete-explanation-warning', $tag )->parseAsBlock();
383 $this->softwareActivatedTags = array_fill_keys(
384 $this->changeTagsStore->listSoftwareActivatedTags(),
true );
385 if ( isset( $this->softwareActivatedTags[$tag] ) ) {
386 $preText .= $this->
msg(
'tags-delete-explanation-active', $tag )->parseAsBlock();
390 $fields[
'Reason'] = [
392 'label' => $this->
msg(
'tags-delete-reason' )->plain(),
395 $fields[
'HiddenTag'] = [
402 HTMLForm::factory(
'ooui', $fields, $this->
getContext() )
403 ->setAction( $this->
getPageTitle(
'delete' )->getLocalURL() )
404 ->setSubmitCallback(
function ( $data, $form ) {
407 ->setSubmitTextMsg(
'tags-delete-submit' )
408 ->setSubmitDestructive()
409 ->addPreHtml( $preText )
414 $actionStr = $activate ?
'activate' :
'deactivate';
417 if ( !$authority->isAllowed(
'managechangetags' ) ) {
423 $out->setPageTitleMsg( $this->
msg(
"tags-$actionStr-title" ) );
432 if ( !$result->isGood() ) {
433 foreach ( $result->getMessages() as $msg ) {
434 $out->addHTML( Html::errorBox(
435 $this->
msg( $msg )->parse()
438 if ( !$result->isOK() ) {
444 $preText = $this->
msg(
"tags-$actionStr-question", $tag )->parseAsBlock();
448 $fields[
'Reason'] = [
450 'label' => $this->
msg(
"tags-$actionStr-reason" )->plain(),
453 $fields[
'HiddenTag'] = [
460 HTMLForm::factory(
'ooui', $fields, $this->
getContext() )
461 ->setAction( $this->
getPageTitle( $actionStr )->getLocalURL() )
462 ->setSubmitCallback(
function ( $data, $form ) use ( $actionStr ) {
466 ->setSubmitTextMsg(
"tags-$actionStr-submit" )
467 ->addPreHtml( $preText )
479 $out = $context->getOutput();
481 $tag = $data[
'HiddenTag'];
483 $status = call_user_func( [ ChangeTags::class,
"{$action}TagWithChecks" ],
484 $tag, $data[
'Reason'], $context->getUser(),
true );
486 if ( $status->isGood() ) {
489 } elseif ( $status->isOK() && $action ===
'delete' ) {
491 $out->addWikiTextAsInterface( $this->
msg(
'tags-delete-warnings-after-delete', $tag,
492 count( $status->getMessages(
'warning' ) ) )->text() .
"\n" .
493 $status->getWikitext() );
497 foreach ( $status->getMessages() as $msg ) {
498 $out->addHTML( Html::errorBox(
499 $this->
msg( $msg )->parse()
530class_alias( SpecialTags::class,
'SpecialTags' );
getContext()
Get the base IContextSource object.
A class containing constants representing the names of configuration variables.
const UseTagFilter
Name constant for the UseTagFilter setting, for use with Config::get()
Parent class for all special pages.
setHeaders()
Sets headers - this should be called from the execute() method of all derived classes!
static getTitleFor( $name, $subpage=false, $fragment='')
Get a localised Title object for a specified special page name If you don't need a full Title object,...
getPageTitle( $subpage=false)
Get a self-referential title object.
getConfig()
Shortcut to get main config object.
getContext()
Gets the context this SpecialPage is executed in.
getRequest()
Get the WebRequest being used for this instance.
msg( $key,... $params)
Wrapper around wfMessage that sets the current context.
getOutput()
Get the OutputPage being used for this instance.
getAuthority()
Shortcut to get the Authority executing this instance.
getLanguage()
Shortcut to get user's language.
outputHeader( $summaryMessageKey='')
Outputs a summary message on top of special pages By default the message key is the canonical name of...
addHelpLink( $to, $overrideBaseUrl=false)
Adds help link with an icon via page indicators.
Show an error when a user tries to do something they do not have the necessary permissions for.