55 parent::__construct(
'Tags' );
85 $out->setPageTitle( $this->
msg(
'tags-title' ) );
86 $out->wrapWikiMsg(
"<div class='mw-tags-intro'>\n$1\n</div>",
'tags-intro' );
89 $userCanManage = $this->permissionManager->userHasRight( $user,
'managechangetags' );
90 $userCanDelete = $this->permissionManager->userHasRight( $user,
'deletechangetags' );
91 $userCanEditInterface = $this->permissionManager->userHasRight( $user,
'editinterface' );
94 if ( $userCanManage ) {
98 'label' => $this->
msg(
'tags-create-tag-name' )->plain(),
104 'label' => $this->
msg(
'tags-create-reason' )->plain(),
107 'IgnoreWarnings' => [
113 ->setAction( $this->
getPageTitle(
'create' )->getLocalURL() )
114 ->setWrapperLegendMsg(
'tags-create-heading' )
115 ->setHeaderText( $this->
msg(
'tags-create-explanation' )->parseAsBlock() )
116 ->setSubmitCallback( [ $this,
'processCreateTagForm' ] )
117 ->setSubmitTextMsg(
'tags-create-submit' )
127 if ( $out->getRedirect() !==
'' ) {
136 $this->explicitlyDefinedTags = array_fill_keys(
138 $this->softwareDefinedTags = array_fill_keys(
142 $definedTags = array_keys( $this->explicitlyDefinedTags + $this->softwareDefinedTags );
145 if ( !$tagStats && !$definedTags ) {
151 Xml::tags(
'th',
null, $this->
msg(
'tags-display-header' )->parse() ) .
152 Xml::tags(
'th',
null, $this->
msg(
'tags-description-header' )->parse() ) .
153 Xml::tags(
'th',
null, $this->
msg(
'tags-source-header' )->parse() ) .
154 Xml::tags(
'th',
null, $this->
msg(
'tags-active-header' )->parse() ) .
155 Xml::tags(
'th',
null, $this->
msg(
'tags-hitcount-header' )->parse() ) .
156 ( ( $userCanManage || $userCanDelete ) ?
157 Xml::tags(
'th', [
'class' =>
'unsortable' ],
158 $this->
msg(
'tags-actions-header' )->parse() ) :
164 $this->softwareActivatedTags = array_fill_keys(
168 foreach ( $tagStats as $tag => $hitcount ) {
169 $tbody .= $this->
doTagRow( $tag, $hitcount, $userCanManage,
170 $userCanDelete, $userCanEditInterface );
173 foreach ( $definedTags as $tag ) {
174 if ( !isset( $tagStats[$tag] ) ) {
175 $tbody .= $this->
doTagRow( $tag, 0, $userCanManage, $userCanDelete, $userCanEditInterface );
179 $out->addModuleStyles(
'jquery.tablesorter.styles' );
180 $out->addModules(
'jquery.tablesorter' );
183 [
'class' =>
'mw-datatable sortable mw-tags-table' ],
190 $tag, $hitcount, $showManageActions, $showDeleteActions, $showEditLinks
197 if ( $showEditLinks ) {
200 $this->
msg(
"tag-$tag" )->inContentLanguage()->
getTitle(),
201 $this->
msg(
'tags-edit' )->text(),
203 [
'action' =>
'edit' ]
205 $disp .= $this->
msg(
'parentheses' )->rawParams( $editLink )->escaped();
207 $newRow .=
Xml::tags(
'td',
null, $disp );
209 $msg = $this->
msg(
"tag-$tag-description" );
210 $desc = !$msg->exists() ?
'' : $msg->parse();
211 if ( $showEditLinks ) {
214 $this->
msg(
"tag-$tag-description" )->inContentLanguage()->
getTitle(),
215 $this->
msg(
'tags-edit' )->text(),
217 [
'action' =>
'edit' ]
219 $desc .= $this->
msg(
'parentheses' )->rawParams( $editDescLink )->escaped();
221 $newRow .=
Xml::tags(
'td',
null, $desc );
224 $isSoftware = isset( $this->softwareDefinedTags[$tag] );
225 $isExplicit = isset( $this->explicitlyDefinedTags[$tag] );
228 $sourceMsgs[] = $this->
msg(
'tags-source-extension' )->escaped();
231 $sourceMsgs[] = $this->
msg(
'tags-source-manual' )->escaped();
233 if ( !$sourceMsgs ) {
234 $sourceMsgs[] = $this->
msg(
'tags-source-none' )->escaped();
238 $isActive = $isExplicit || isset( $this->softwareActivatedTags[$tag] );
239 $activeMsg = ( $isActive ?
'tags-active-yes' :
'tags-active-no' );
240 $newRow .=
Xml::tags(
'td',
null, $this->
msg( $activeMsg )->escaped() );
242 $hitcountLabelMsg = $this->
msg(
'tags-hitcount' )->numParams( $hitcount );
243 if ( $this->
getConfig()->
get(
'UseTagFilter' ) ) {
246 $hitcountLabelMsg->text(),
248 [
'tagfilter' => $tag ]
251 $hitcountLabel = $hitcountLabelMsg->escaped();
255 $newRow .=
Xml::tags(
'td', [
'data-sort-value' => $hitcount ], $hitcountLabel );
262 $this->
msg(
'tags-delete' )->text(),
267 if ( $showManageActions ) {
271 $this->
msg(
'tags-activate' )->text(),
279 $this->
msg(
'tags-deactivate' )->text(),
285 if ( $showDeleteActions || $showManageActions ) {
289 return Xml::tags(
'tr',
null, $newRow ) .
"\n";
294 $out = $context->getOutput();
296 $tag = trim( strval( $data[
'Tag'] ) );
297 $ignoreWarnings = isset( $data[
'IgnoreWarnings'] ) && $data[
'IgnoreWarnings'] ===
'1';
299 $context->getUser(), $ignoreWarnings );
301 if ( $status->isGood() ) {
304 } elseif ( $status->isOK() ) {
309 'default' => $data[
'Tag'],
313 'default' => $data[
'Reason'],
315 'IgnoreWarnings' => [
323 $context->getRequest()->unsetVal(
'wpEditToken' );
325 $headerText = $this->
msg(
'tags-create-warnings-above', $tag,
326 count( $status->getWarningsArray() ) )->parseAsBlock() .
327 $out->parseAsInterface( $status->getWikiText() ) .
328 $this->
msg(
'tags-create-warnings-below' )->parseAsBlock();
331 ->setAction( $this->
getPageTitle(
'create' )->getLocalURL() )
332 ->setWrapperLegendMsg(
'tags-create-heading' )
333 ->setHeaderText( $headerText )
334 ->setSubmitCallback( [ $this,
'processCreateTagForm' ] )
335 ->setSubmitTextMsg(
'htmlform-yes' )
341 $out->wrapWikiTextAsInterface(
'error', $status->getWikiText() );
348 if ( !$this->permissionManager->userHasRight( $user,
'deletechangetags' ) ) {
353 $out->setPageTitle( $this->
msg(
'tags-delete-title' ) );
358 if ( !$canDeleteResult->isGood() ) {
359 $out->wrapWikiTextAsInterface(
'error', $canDeleteResult->getWikiText() );
360 if ( !$canDeleteResult->isOK() ) {
365 $preText = $this->
msg(
'tags-delete-explanation-initial', $tag )->parseAsBlock();
367 if ( isset( $tagUsage[$tag] ) && $tagUsage[$tag] > 0 ) {
368 $preText .= $this->
msg(
'tags-delete-explanation-in-use', $tag,
369 $tagUsage[$tag] )->parseAsBlock();
371 $preText .= $this->
msg(
'tags-delete-explanation-warning', $tag )->parseAsBlock();
374 $this->softwareActivatedTags = array_fill_keys(
376 if ( isset( $this->softwareActivatedTags[$tag] ) ) {
377 $preText .= $this->
msg(
'tags-delete-explanation-active', $tag )->parseAsBlock();
381 $fields[
'Reason'] = [
383 'label' => $this->
msg(
'tags-delete-reason' )->plain(),
386 $fields[
'HiddenTag'] = [
394 ->setAction( $this->
getPageTitle(
'delete' )->getLocalURL() )
395 ->setSubmitCallback(
function ( $data, $form ) {
398 ->setSubmitTextMsg(
'tags-delete-submit' )
399 ->setSubmitDestructive()
400 ->addPreText( $preText )
405 $actionStr = $activate ?
'activate' :
'deactivate';
408 if ( !$this->permissionManager->userHasRight( $user,
'managechangetags' ) ) {
414 $out->setPageTitle( $this->
msg(
"tags-$actionStr-title" ) );
418 $func = $activate ?
'canActivateTag' :
'canDeactivateTag';
419 $result = ChangeTags::$func( $tag, $user );
420 if ( !$result->isGood() ) {
421 $out->wrapWikiTextAsInterface(
'error', $result->getWikiText() );
422 if ( !$result->isOK() ) {
428 $preText = $this->
msg(
"tags-$actionStr-question", $tag )->parseAsBlock();
432 $fields[
'Reason'] = [
434 'label' => $this->
msg(
"tags-$actionStr-reason" )->plain(),
437 $fields[
'HiddenTag'] = [
445 ->setAction( $this->
getPageTitle( $actionStr )->getLocalURL() )
446 ->setSubmitCallback(
function ( $data, $form ) use ( $actionStr ) {
450 ->setSubmitTextMsg(
"tags-$actionStr-submit" )
451 ->addPreText( $preText )
463 $out = $context->getOutput();
465 $tag = $data[
'HiddenTag'];
467 $status = call_user_func( [ ChangeTags::class,
"{$action}TagWithChecks" ],
468 $tag, $data[
'Reason'], $context->getUser(),
true );
470 if ( $status->isGood() ) {
473 } elseif ( $status->isOK() && $action ===
'delete' ) {
475 $out->addWikiTextAsInterface( $this->
msg(
'tags-delete-warnings-after-delete', $tag,
476 count( $status->getWarningsArray() ) )->text() .
"\n" .
477 $status->getWikitext() );
481 $out->wrapWikiTextAsInterface(
'error', $status->getWikitext() );