setHeaders();
$this->addHelpLink( 'Help:Extension:Translate/Page translation administration' );
$out = $this->getOutput();
$out->addModuleStyles( 'ext.translate.specialpages.styles' );
// Check permissions
if ( $this->getUser()->isAllowed( 'translate-manage' ) ) {
$this->hasPermission = true;
}
$groupsPreload = array_merge(
MessageGroups::getGroupsByType( WikiPageMessageGroup::class ),
MessageGroups::getGroupsByType( AggregateMessageGroup::class )
);
TranslateMetadata::preloadGroups( array_keys( $groupsPreload ) );
$groups = MessageGroups::getAllGroups();
uasort( $groups, [ MessageGroups::class, 'groupLabelSort' ] );
$aggregates = [];
$pages = [];
foreach ( $groups as $group ) {
if ( $group instanceof WikiPageMessageGroup ) {
$pages[] = $group;
} elseif ( $group instanceof AggregateMessageGroup ) {
$subgroups = TranslateMetadata::getSubgroups( $group->getId() );
if ( $subgroups !== null ) {
$aggregates[] = $group;
}
}
}
if ( !count( $pages ) ) {
// @todo Use different message
$out->addWikiMsg( 'tpt-list-nopages' );
return;
}
$this->showAggregateGroups( $aggregates );
}
/**
* @param AggregateMessageGroup $group
* @return string
*/
protected function showAggregateGroup( $group ) {
$out = '';
$id = $group->getId();
$label = $group->getLabel();
$desc = $group->getDescription( $this->getContext() );
$div = Html::openElement( 'div', [
'class' => 'mw-tpa-group',
'data-groupid' => $id,
'data-id' => $this->htmlIdForGroup( $group ),
] );
$out .= $div;
$edit = '';
$remove = '';
$editGroup = '';
$select = '';
$addButton = '';
// Add divs for editing Aggregate Groups
if ( $this->hasPermission ) {
// Group edit and remove buttons
$edit = Html::element( 'span', [ 'class' => 'tp-aggregate-edit-ag-button' ] );
$remove = Html::element( 'span', [ 'class' => 'tp-aggregate-remove-ag-button' ] );
// Edit group div
$editGroupNameLabel = $this->msg( 'tpt-aggregategroup-edit-name' )->escaped();
$editGroupName = Html::input(
'tp-agg-name',
$label,
'text',
[ 'class' => 'tp-aggregategroup-edit-name', 'maxlength' => '200' ]
);
$editGroupDescriptionLabel = $this->msg( 'tpt-aggregategroup-edit-description' )->escaped();
$editGroupDescription = Html::input(
'tp-agg-desc',
$desc,
'text',
[ 'class' => 'tp-aggregategroup-edit-description' ]
);
$saveButton = Xml::submitButton(
$this->msg( 'tpt-aggregategroup-update' )->text(),
[ 'class' => 'tp-aggregategroup-update' ]
);
$cancelButton = Xml::submitButton(
$this->msg( 'tpt-aggregategroup-update-cancel' )->text(),
[ 'class' => 'tp-aggregategroup-update-cancel' ]
);
$editGroup = Html::rawElement(
'div',
[
'class' => 'tp-edit-group hidden'
],
$editGroupNameLabel .
$editGroupName . '
' .
$editGroupDescriptionLabel .
$editGroupDescription .
$saveButton .
$cancelButton
);
// Subgroups selector
$select = Html::input(
'tp-subgroups-input',
'',
'text',
[ 'class' => 'tp-group-input' ]
);
$addButton = Html::element( 'input',
[ 'type' => 'button',
'value' => $this->msg( 'tpt-aggregategroup-add' )->text(),
'class' => 'tp-aggregate-add-button' ]
);
}
// Aggregate Group info div
$groupName = Html::rawElement( 'h2',
[ 'class' => 'tp-name' ],
htmlspecialchars( $label ) . $edit . $remove
);
$groupDesc = Html::element( 'p',
[ 'class' => 'tp-desc' ],
$desc
);
$groupInfo = Html::rawElement( 'div',
[ 'class' => 'tp-display-group' ],
$groupName .
$groupDesc
);
$out .= $groupInfo;
$out .= $editGroup;
$out .= $this->listSubgroups( $group );
$out .= $select . $addButton;
$out .= '';
return $out;
}
/** @param array $aggregates */
protected function showAggregateGroups( array $aggregates ) {
$out = $this->getOutput();
$out->addModules( 'ext.translate.special.aggregategroups' );
$nojs = Html::element(
'div',
[ 'class' => 'tux-nojs errorbox' ],
$this->msg( 'tux-nojs' )->plain()
);
$out->addHTML( $nojs );
/** @var AggregateMessageGroup $group */
foreach ( $aggregates as $group ) {
$out->addHTML( $this->showAggregateGroup( $group ) );
}
// Add new group if user has permissions
if ( $this->hasPermission ) {
$out->addHTML( "
" .
$this->msg( 'tpt-aggregategroup-add-new' )->escaped() .
'' );
$newGroupNameLabel = $this->msg( 'tpt-aggregategroup-new-name' )->escaped();
$newGroupName = Html::element(
'input',
[ 'class' => 'tp-aggregategroup-add-name', 'maxlength' => '200' ]
);
$newGroupDescriptionLabel = $this->msg( 'tpt-aggregategroup-new-description' )->escaped();
$newGroupDescription = Html::element( 'input',
[ 'class' => 'tp-aggregategroup-add-description' ]
);
$saveButton = Html::element( 'input', [
'type' => 'button',
'value' => $this->msg( 'tpt-aggregategroup-save' )->text(),
'id' => 'tpt-aggregategroups-save',
'class' => 'tp-aggregate-save-button'
] );
$newGroupDiv = Html::rawElement(
'div',
[ 'class' => 'tpt-add-new-group hidden' ],
"$newGroupNameLabel $newGroupName
" .
"$newGroupDescriptionLabel $newGroupDescription
$saveButton"
);
$out->addHTML( $newGroupDiv );
}
}
/**
* @param AggregateMessageGroup $parent
* @return string
*/
protected function listSubgroups( AggregateMessageGroup $parent ) {
$id = $this->htmlIdForGroup( $parent, 'mw-tpa-grouplist-' );
$out = Html::openElement( 'ol', [ 'id' => $id ] );
// Not calling $parent->getGroups() because it has done filtering already
$subgroupIds = TranslateMetadata::getSubgroups( $parent->getId() ) ?? [];
// Get the respective groups and sort them
$subgroups = MessageGroups::getGroupsById( $subgroupIds );
'@phan-var WikiPageMessageGroup[] $subgroups';
uasort( $subgroups, [ MessageGroups::class, 'groupLabelSort' ] );
// Avoid potentially thousands of separate database queries
$lb = new LinkBatch();
foreach ( $subgroups as $group ) {
$lb->addObj( $group->getTitle() );
}
$lb->setCaller( __METHOD__ );
$lb->execute();
// Add missing invalid group ids back, not returned by getGroupsById
foreach ( $subgroupIds as $id ) {
if ( !isset( $subgroups[$id] ) ) {
$subgroups[$id] = null;
}
}
foreach ( $subgroups as $id => $group ) {
$remove = '';
if ( $this->hasPermission ) {
$remove = Html::element( 'span',
[
'class' => 'tp-aggregate-remove-button',
'data-groupid' => $id,
]
);
}
if ( $group ) {
$text = $this->getLinkRenderer()->makeKnownLink( $group->getTitle() );
$note = MessageGroups::getPriority( $id );
} else {
$text = htmlspecialchars( $id );
$note = $this->msg( 'tpt-aggregategroup-invalid-group' )->escaped();
}
$out .= Html::rawElement( 'li', [], "$text$remove $note" );
}
$out .= Html::closeElement( 'ol' );
return $out;
}
/**
* @param MessageGroup $group
* @param string $prefix
* @return string
*/
protected function htmlIdForGroup( MessageGroup $group, $prefix = '' ) {
$id = sha1( $group->getId() );
$id = substr( $id, 5, 8 );
return $prefix . $id;
}
}