56 parent::__construct(
'Tags' );
57 $this->changeTagsStore = $changeTagsStore;
84 private function showTagList() {
86 $out->setPageTitleMsg( $this->
msg(
'tags-title' ) );
87 $out->wrapWikiMsg(
"<div class='mw-tags-intro'>\n$1\n</div>",
'tags-intro' );
90 $userCanManage = $authority->isAllowed(
'managechangetags' );
91 $userCanDelete = $authority->isAllowed(
'deletechangetags' );
92 $userCanEditInterface = $authority->isAllowed(
'editinterface' );
95 if ( $userCanManage ) {
99 'label' => $this->
msg(
'tags-create-tag-name' )->plain(),
104 'maxlength' => CommentStore::COMMENT_CHARACTER_LIMIT,
105 'label' => $this->
msg(
'tags-create-reason' )->plain(),
108 'IgnoreWarnings' => [
113 HTMLForm::factory(
'ooui', $fields, $this->
getContext() )
114 ->setAction( $this->
getPageTitle(
'create' )->getLocalURL() )
115 ->setWrapperLegendMsg(
'tags-create-heading' )
116 ->setHeaderHtml( $this->
msg(
'tags-create-explanation' )->parseAsBlock() )
117 ->setSubmitCallback( [ $this,
'processCreateTagForm' ] )
118 ->setSubmitTextMsg(
'tags-create-submit' )
128 if ( $out->getRedirect() !==
'' ) {
134 $tagStats = $this->changeTagsStore->tagUsageStatistics();
137 $this->explicitlyDefinedTags = array_fill_keys(
138 $this->changeTagsStore->listExplicitlyDefinedTags(),
true );
139 $this->softwareDefinedTags = array_fill_keys(
140 $this->changeTagsStore->listSoftwareDefinedTags(),
true );
143 $definedTags = array_keys( $this->explicitlyDefinedTags + $this->softwareDefinedTags );
146 if ( !$tagStats && !$definedTags ) {
151 $thead = Xml::tags(
'tr',
null, Xml::tags(
'th',
null, $this->
msg(
'tags-tag' )->parse() ) .
152 Xml::tags(
'th',
null, $this->
msg(
'tags-display-header' )->parse() ) .
153 Xml::tags(
'th',
null, $this->
msg(
'tags-description-header' )->parse() ) .
154 Xml::tags(
'th',
null, $this->
msg(
'tags-source-header' )->parse() ) .
155 Xml::tags(
'th',
null, $this->
msg(
'tags-active-header' )->parse() ) .
156 Xml::tags(
'th',
null, $this->
msg(
'tags-hitcount-header' )->parse() ) .
157 ( ( $userCanManage || $userCanDelete ) ?
158 Xml::tags(
'th', [
'class' =>
'unsortable' ],
159 $this->
msg(
'tags-actions-header' )->parse() ) :
165 $this->softwareActivatedTags = array_fill_keys(
166 $this->changeTagsStore->listSoftwareActivatedTags(),
true );
169 foreach ( $tagStats as $tag => $hitcount ) {
170 $tbody .= $this->doTagRow( $tag, $hitcount, $userCanManage,
171 $userCanDelete, $userCanEditInterface );
174 foreach ( $definedTags as $tag ) {
175 if ( !isset( $tagStats[$tag] ) ) {
176 $tbody .= $this->doTagRow( $tag, 0, $userCanManage, $userCanDelete, $userCanEditInterface );
180 $out->addModuleStyles( [
181 'jquery.tablesorter.styles',
182 'mediawiki.pager.styles'
184 $out->addModules(
'jquery.tablesorter' );
185 $out->addHTML( Xml::tags(
187 [
'class' =>
'mw-datatable sortable mw-tags-table' ],
188 Xml::tags(
'thead',
null, $thead ) .
189 Xml::tags(
'tbody',
null, $tbody )
193 private function doTagRow(
194 $tag, $hitcount, $showManageActions, $showDeleteActions, $showEditLinks
197 $newRow .= Xml::tags(
'td',
null,
Xml::element(
'code',
null, $tag ) );
201 if ( $disp ===
false ) {
202 $disp =
Xml::element(
'em',
null, $this->
msg(
'tags-hidden' )->text() );
204 if ( $showEditLinks ) {
206 $editLink = $linkRenderer->makeLink(
207 $this->
msg(
"tag-$tag" )->inContentLanguage()->
getTitle(),
208 $this->
msg(
'tags-edit' )->text(),
210 [
'action' =>
'edit' ]
212 $disp .= $this->
msg(
'parentheses' )->rawParams( $editLink )->escaped();
214 $newRow .= Xml::tags(
'td',
null, $disp );
216 $msg = $this->
msg(
"tag-$tag-description" );
217 $desc = !$msg->exists() ?
'' : $msg->parse();
218 if ( $showEditLinks ) {
220 $editDescLink = $linkRenderer->makeLink(
221 $this->
msg(
"tag-$tag-description" )->inContentLanguage()->
getTitle(),
222 $this->
msg(
'tags-edit' )->text(),
224 [
'action' =>
'edit' ]
226 $desc .= $this->
msg(
'parentheses' )->rawParams( $editDescLink )->escaped();
228 $newRow .= Xml::tags(
'td',
null, $desc );
231 $isSoftware = isset( $this->softwareDefinedTags[$tag] );
232 $isExplicit = isset( $this->explicitlyDefinedTags[$tag] );
235 $sourceMsgs[] = $this->
msg(
'tags-source-extension' )->escaped();
238 $sourceMsgs[] = $this->
msg(
'tags-source-manual' )->escaped();
240 if ( !$sourceMsgs ) {
241 $sourceMsgs[] = $this->
msg(
'tags-source-none' )->escaped();
243 $newRow .= Xml::tags(
'td',
null, implode(
Xml::element(
'br' ), $sourceMsgs ) );
245 $isActive = $isExplicit || isset( $this->softwareActivatedTags[$tag] );
246 $activeMsg = ( $isActive ?
'tags-active-yes' :
'tags-active-no' );
247 $newRow .= Xml::tags(
'td',
null, $this->
msg( $activeMsg )->escaped() );
249 $hitcountLabelMsg = $this->
msg(
'tags-hitcount' )->numParams( $hitcount );
251 $hitcountLabel = $linkRenderer->makeLink(
253 $hitcountLabelMsg->text(),
255 [
'tagfilter' => $tag ]
258 $hitcountLabel = $hitcountLabelMsg->escaped();
262 $newRow .= Xml::tags(
'td', [
'data-sort-value' => $hitcount ], $hitcountLabel );
267 $actionLinks[] = $linkRenderer->makeKnownLink(
269 $this->
msg(
'tags-delete' )->text(),
274 if ( $showManageActions ) {
276 $actionLinks[] = $linkRenderer->makeKnownLink(
278 $this->
msg(
'tags-activate' )->text(),
284 $actionLinks[] = $linkRenderer->makeKnownLink(
286 $this->
msg(
'tags-deactivate' )->text(),
292 if ( $showDeleteActions || $showManageActions ) {
293 $newRow .= Xml::tags(
'td',
null, $this->
getLanguage()->pipeList( $actionLinks ) );
296 return Xml::tags(
'tr',
null, $newRow ) .
"\n";
301 $out = $context->getOutput();
303 $tag = trim( strval( $data[
'Tag'] ) );
304 $ignoreWarnings = isset( $data[
'IgnoreWarnings'] ) && $data[
'IgnoreWarnings'] ===
'1';
306 $context->getAuthority(), $ignoreWarnings );
308 if ( $status->isGood() ) {
311 } elseif ( $status->isOK() ) {
315 'IgnoreWarnings' => [
321 $headerText = $this->
msg(
'tags-create-warnings-above', $tag,
322 count( $status->getMessages(
'warning' ) ) )->parseAsBlock() .
323 $out->parseAsInterface( $status->getWikiText() ) .
324 $this->
msg(
'tags-create-warnings-below' )->parseAsBlock();
327 ->setSubmitTextMsg(
'htmlform-yes' );
332 $out->wrapWikiTextAsInterface(
'error', $status->getWikiText() );
339 if ( !$authority->isAllowed(
'deletechangetags' ) ) {
344 $out->setPageTitleMsg( $this->
msg(
'tags-delete-title' ) );
349 if ( !$canDeleteResult->isGood() ) {
350 $out->wrapWikiTextAsInterface(
'error', $canDeleteResult->getWikiText() );
351 if ( !$canDeleteResult->isOK() ) {
356 $preText = $this->
msg(
'tags-delete-explanation-initial', $tag )->parseAsBlock();
357 $tagUsage = $this->changeTagsStore->tagUsageStatistics();
358 if ( isset( $tagUsage[$tag] ) && $tagUsage[$tag] > 0 ) {
359 $preText .= $this->
msg(
'tags-delete-explanation-in-use', $tag,
360 $tagUsage[$tag] )->parseAsBlock();
362 $preText .= $this->
msg(
'tags-delete-explanation-warning', $tag )->parseAsBlock();
365 $this->softwareActivatedTags = array_fill_keys(
366 $this->changeTagsStore->listSoftwareActivatedTags(),
true );
367 if ( isset( $this->softwareActivatedTags[$tag] ) ) {
368 $preText .= $this->
msg(
'tags-delete-explanation-active', $tag )->parseAsBlock();
372 $fields[
'Reason'] = [
374 'label' => $this->
msg(
'tags-delete-reason' )->plain(),
377 $fields[
'HiddenTag'] = [
384 HTMLForm::factory(
'ooui', $fields, $this->
getContext() )
385 ->setAction( $this->
getPageTitle(
'delete' )->getLocalURL() )
386 ->setSubmitCallback(
function ( $data, $form ) {
389 ->setSubmitTextMsg(
'tags-delete-submit' )
390 ->setSubmitDestructive()
391 ->addPreHtml( $preText )
396 $actionStr = $activate ?
'activate' :
'deactivate';
399 if ( !$authority->isAllowed(
'managechangetags' ) ) {
405 $out->setPageTitleMsg( $this->
msg(
"tags-$actionStr-title" ) );
414 if ( !$result->isGood() ) {
415 $out->wrapWikiTextAsInterface(
'error', $result->getWikiText() );
416 if ( !$result->isOK() ) {
422 $preText = $this->
msg(
"tags-$actionStr-question", $tag )->parseAsBlock();
426 $fields[
'Reason'] = [
428 'label' => $this->
msg(
"tags-$actionStr-reason" )->plain(),
431 $fields[
'HiddenTag'] = [
438 HTMLForm::factory(
'ooui', $fields, $this->
getContext() )
439 ->setAction( $this->
getPageTitle( $actionStr )->getLocalURL() )
440 ->setSubmitCallback(
function ( $data, $form ) use ( $actionStr ) {
444 ->setSubmitTextMsg(
"tags-$actionStr-submit" )
445 ->addPreHtml( $preText )
457 $out = $context->getOutput();
459 $tag = $data[
'HiddenTag'];
461 $status = call_user_func( [ ChangeTags::class,
"{$action}TagWithChecks" ],
462 $tag, $data[
'Reason'], $context->getUser(),
true );
464 if ( $status->isGood() ) {
467 } elseif ( $status->isOK() && $action ===
'delete' ) {
469 $out->addWikiTextAsInterface( $this->
msg(
'tags-delete-warnings-after-delete', $tag,
470 count( $status->getMessages(
'warning' ) ) )->text() .
"\n" .
471 $status->getWikitext() );
475 $out->wrapWikiTextAsInterface(
'error', $status->getWikitext() );
504class_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.