resources/js/ext.translate.special.aggregategroups.js
( function () {
'use strict';
function getApiParams( $target ) {
return {
action: 'aggregategroups',
aggregategroup: $target.parents( '.mw-tpa-group' ).data( 'groupid' )
};
}
function dissociate( event ) {
var $target = $( event.target ),
api = new mw.Api();
function successFunction() {
$target.parent( 'li' ).remove();
}
var params = $.extend( getApiParams( $target ), {
do: 'dissociate',
group: $target.data( 'groupid' )
} );
api.postWithToken( 'csrf', params )
.done( successFunction )
.fail( function ( code, data ) {
// eslint-disable-next-line no-alert
alert( data.error && data.error.info );
} );
}
function associate( event, subGroupId ) {
var $target = $( event.target ),
$parent = $target.parents( '.mw-tpa-group' ),
parentId = $parent.data( 'id' ),
subgroupName = $parent
.find( '.tes-entity-selector' )
.find( 'input[type="text"]' )
.val(),
api = new mw.Api();
// Clear the selected group value
$parent.find( '.tes-entity-selector' ).find( 'input[type="text"]' ).val( '' );
var successFunction = function ( data ) {
var aAttr, $a, spanAttr, $span, $ol;
aAttr = {
href: data.aggregategroups.groupUrl,
title: subgroupName
};
$a = $( '<a>', aAttr ).text( subgroupName );
spanAttr = {
class: 'tp-aggregate-remove-button',
'data-groupid': subGroupId
};
$span = $( '<span>', spanAttr );
$ol = $( '#mw-tpa-grouplist-' + parentId );
$ol.append( $( '<li>' ).append( $a, $span ) );
$span.on( 'click', dissociate );
};
// Get the label for the value and make API request if valid
if ( subGroupId ) {
var params = $.extend( getApiParams( $target ), {
do: 'associate',
group: subGroupId
} );
api.postWithToken( 'csrf', params )
.done( successFunction )
.fail( function ( code, data ) {
// eslint-disable-next-line no-alert
alert( data.error && data.error.info );
} );
} else {
// eslint-disable-next-line no-alert
alert( mw.msg( 'tpt-invalid-group' ) );
}
}
function removeGroup( event ) {
var $target = $( event.target ),
api = new mw.Api();
function successFunction() {
$( event.target ).parents( '.mw-tpa-group' ).remove();
}
// XXX: 'confirm' is nonstandard.
if ( typeof window.confirm === 'function' &&
// eslint-disable-next-line no-alert
window.confirm( mw.msg( 'tpt-aggregategroup-remove-confirm' ) ) ) {
var params = $.extend( getApiParams( $target ), {
do: 'remove'
} );
api.postWithToken( 'csrf', params )
.done( successFunction )
.fail( function ( code, data ) {
// eslint-disable-next-line no-alert
alert( data.error && data.error.info );
} );
}
}
function editGroup( event ) {
var $target = $( event.target ),
$parent = $target.closest( '.mw-tpa-group' ),
aggregateGroupId = $parent.data( 'groupid' ),
$displayGroup = $parent.children( '.tp-display-group' ),
$editGroup = $parent.children( '.tp-edit-group' ),
$aggGroupNameInputName = $editGroup.children( 'input.tp-aggregategroup-edit-name' ),
$aggGroupNameInputDesc = $editGroup.children( 'input.tp-aggregategroup-edit-description' ),
$aggGroupNameInputLanguage = $editGroup.children( 'select.tp-aggregategroup-edit-source-language' ),
aggregateGroupName = $aggGroupNameInputName.val(),
aggregateGroupDesc = $aggGroupNameInputDesc.val(),
aggregateGroupLanguage = $aggGroupNameInputLanguage.val(),
api = new mw.Api();
var successFunction = function () {
// Replace the text by the new text without altering the other 2 span tags
$displayGroup.children( '.tp-name' ).contents().filter( function () {
return this.nodeType === 3;
} ).replaceWith( aggregateGroupName );
$displayGroup.children( '.tp-desc' ).text( aggregateGroupDesc );
$displayGroup.removeClass( 'hidden' );
$editGroup.addClass( 'hidden' );
};
var params = {
action: 'aggregategroups',
do: 'update',
groupname: aggregateGroupName,
groupdescription: aggregateGroupDesc,
aggregategroup: aggregateGroupId,
groupsourcelanguagecode: aggregateGroupLanguage
};
api.postWithToken( 'csrf', params )
.done( successFunction )
.fail( function ( code, data ) {
// eslint-disable-next-line no-alert
alert( data.error.info );
} );
}
function cancelEditGroup( event ) {
var $parent = $( event.target ).closest( '.mw-tpa-group' );
$parent.children( '.tp-display-group' ).removeClass( 'hidden' );
$parent.children( '.tp-edit-group' ).addClass( 'hidden' );
}
function getToggleAllGroupsLink() {
var $toggleLink = $( '<a>' )
.addClass( 'js-tp-toggle-all-groups' )
.attr( 'href', '#' )
.text( mw.msg( 'tpt-aggregategroup-expand-all-groups' ) );
var $toggleLinkParent = $( '<div>' )
.append( '[', $toggleLink, ']' );
$toggleLink.on( 'click', function ( event ) {
var $target = $( event.target );
var isExpanded = $target.hasClass( 'expanded' );
var $groupContainers = $( '.js-mw-tpa-group' );
for ( var i = 0; i < $groupContainers.length; i++ ) {
var $groupContainer = $groupContainers.eq( i );
var isContainerOpen = $groupContainer.hasClass( 'mw-tpa-group-open' );
if ( isExpanded === isContainerOpen ) {
toggleGroupContainer( $groupContainer );
}
}
$target.toggleClass( 'expanded' )
.text( mw.msg( isExpanded ?
'tpt-aggregategroup-expand-all-groups' :
'tpt-aggregategroup-collapse-all-groups'
) );
event.preventDefault();
} );
return $toggleLinkParent;
}
function toggleGroupContainer( $groupContainer ) {
var $toggleTrigger = $groupContainer.find( '.js-tp-toggle-groups' );
var isOpen = $groupContainer.hasClass( 'mw-tpa-group-open' );
changeGroupToggleIconState( $toggleTrigger, !isOpen );
$groupContainer.toggleClass( 'mw-tpa-group-open' );
}
function changeGroupToggleIconState( $icon, isOpen ) {
var title = mw.msg( 'tpt-aggregategroup-expand-group' );
var ariaExpanded = 'false';
if ( isOpen ) {
title = mw.msg( 'tpt-aggregategroup-collapse-group' );
ariaExpanded = 'true';
}
$icon.attr( 'title', title )
.attr( 'aria-expanded', ariaExpanded );
}
$( function () {
var api = new mw.Api(),
lastSelectedGroup = null;
function onEntityItemSelect( selectedItem ) {
// Remove selections made in other entity selectors on the page
$( '.tes-entity-selector' )
.not( this.$element )
.find( 'input[type="text"]' )
.val( '' );
lastSelectedGroup = selectedItem;
// Clear the request cache so that the entity selector requests for data again
// This way the recently selected group can be removed from the menu items displayed
this.requestCache = {};
}
function associateSelectedGroup( event ) {
if ( lastSelectedGroup ) {
associate( event, lastSelectedGroup.data );
lastSelectedGroup = null;
} else {
// eslint-disable-next-line no-alert
alert( mw.msg( 'tpt-invalid-group' ) );
}
}
var $subGroups = $( '.tp-sub-groups' ), $button;
$subGroups.each( function () {
$button = $( '<button>' )
.addClass( 'tp-aggregate-add-button' )
.text( mw.msg( 'tpt-aggregategroup-add' ) );
$( this ).append( getEntitySelector( onEntityItemSelect, filterSelectedGroups ).$element, $button );
} );
$( '.tp-aggregate-add-button' ).on( 'click', associateSelectedGroup );
$( '.tp-aggregate-remove-button' ).on( 'click', dissociate );
$( '.tp-aggregate-remove-ag-button' ).on( 'click', removeGroup );
$( '.tp-aggregategroup-update' ).on( 'click', editGroup );
$( '.tp-aggregategroup-update-cancel' ).on( 'click', cancelEditGroup );
$( 'a.tpt-add-new-group' ).on( 'click', function ( event ) {
$( 'div.tpt-add-new-group' ).removeClass( 'hidden' );
// Link has anchor which goes top of the page
event.preventDefault();
} );
$( '.tp-aggregate-edit-ag-button' ).on( 'click', function ( event ) {
var $parent = $( event.target ).closest( '.mw-tpa-group' );
$parent.children( '.tp-display-group' ).addClass( 'hidden' );
$parent.children( '.tp-edit-group' ).removeClass( 'hidden' );
} );
$( '#tpt-aggregategroups-save' ).on( 'click', function () {
var $aggGroupNameInputName = $( 'input.tp-aggregategroup-add-name' ),
$aggGroupNameInputDesc = $( 'input.tp-aggregategroup-add-description' ),
$aggGroupNameInputLanguage = $( 'select.tp-aggregategroup-add-source-language' ),
aggregateGroupName = $aggGroupNameInputName.val(),
aggregateGroupDesc = $aggGroupNameInputDesc.val(),
aggregateGroupLanguage = $aggGroupNameInputLanguage.val();
// Empty the fields. If they are not emptied, then when another group
// is added, the values will appear again.
$aggGroupNameInputName.val( '' );
$aggGroupNameInputDesc.val( '' );
$aggGroupNameInputLanguage.val( '-' );
var successFunction = function ( data ) {
var aggregateGroupId = data.aggregategroups.aggregategroupId;
var subGroupId = 'tp-subgroup-' + aggregateGroupId;
var $removeSpan = $( '<span>' ).attr( 'id', aggregateGroupId )
.addClass( 'tp-aggregate-remove-ag-button' );
var $editSpan = $( '<span>' ).attr( 'id', aggregateGroupId )
.addClass( 'tp-aggregate-edit-ag-button' );
var $toggleIcon = $( '<a>' ).addClass( 'js-tp-toggle-groups tp-toggle-group-icon' )
.attr( 'aria-controls', subGroupId )
.attr( 'role', 'button' );
var isOpen = true;
changeGroupToggleIconState( $toggleIcon, isOpen );
// Prints the name and the two spans in a single row
var $displayHeader = $( '<h2>' ).addClass( 'tp-name' ).text( aggregateGroupName )
.append( $editSpan, $removeSpan )
.prepend( $toggleIcon );
var $divDisplay = $( '<div>' ).addClass( 'tp-display-group' )
.append( $displayHeader )
.append( $( '<p>' ).addClass( 'tp-desc' ).text( aggregateGroupDesc ) );
var $saveButton = $( '<input>' )
.attr( {
type: 'button',
class: 'tp-aggregategroup-update'
} )
.val( mw.msg( 'tpt-aggregategroup-update' ) );
var $cancelButton = $( '<input>' )
.attr( {
type: 'button',
class: 'tp-aggregategroup-update-cancel'
} )
.val( mw.msg( 'tpt-aggregategroup-update-cancel' ) );
var $sourceLanguages = $( '.tp-aggregategroup-add-source-language' ).clone();
var $divEdit = $( '<div>' )
.addClass( 'tp-edit-group hidden' )
.append( $( '<label>' )
.text( mw.msg( 'tpt-aggregategroup-edit-name' ) ) )
.append( $( '<input>' )
.attr( {
class: 'tp-aggregategroup-edit-name',
id: 'tp-agg-name'
} )
.val( aggregateGroupName )
)
.append(
$( '<br>' ),
$( '<label>' )
.text( mw.msg( 'tpt-aggregategroup-edit-description' ) )
)
.append( $( '<input>' )
.attr( {
class: 'tp-aggregategroup-edit-description',
id: 'tp-agg-desc'
} )
.val( aggregateGroupDesc )
)
.append(
$( '<br>' ),
$( '<label>' )
.text( mw.msg( 'tpt-aggregategroup-select-source-language' ) )
)
.append( $sourceLanguages
.removeClass( 'tp-aggregategroup-add-source-language' )
.addClass( 'tp-aggregategroup-edit-source-language' )
.val( aggregateGroupLanguage )
)
.append( $( '<br>' ) )
.append( $saveButton, $cancelButton );
var $div = $( '<div>' )
.addClass( 'mw-tpa-group js-mw-tpa-group mw-tpa-group-open' )
.append( $divDisplay, $divEdit )
.data( { groupid: aggregateGroupId, id: aggregateGroupId } );
var $subGroupContents = $( '<div>' ).addClass( 'tp-sub-groups' )
.attr( 'id', subGroupId )
.append( $( '<ol id=\'mw-tpa-grouplist-' + aggregateGroupId + '\'>' ) );
var $addButton = $( '<input>' )
.attr( {
type: 'button',
class: 'tp-aggregate-add-button',
id: aggregateGroupId
} )
.val( mw.msg( 'tpt-aggregategroup-add' ) );
$addButton.on( 'click', associateSelectedGroup );
var entitySelector = getEntitySelector( onEntityItemSelect, filterSelectedGroups );
$subGroupContents.append( entitySelector.$element, $addButton );
$div.append( $subGroupContents );
$editSpan.on( 'click', function ( event ) {
var $parent = $( event.target ).closest( '.mw-tpa-group' );
$parent.children( '.tp-display-group' ).addClass( 'hidden' );
$parent.children( '.tp-edit-group' ).removeClass( 'hidden' );
} );
$saveButton.on( 'click', editGroup );
$cancelButton.on( 'click', cancelEditGroup );
$removeSpan.on( 'click', removeGroup );
$( 'div.tpt-add-new-group' ).addClass( 'hidden' );
$( 'div.mw-tpa-groups' ).prepend( $div );
};
var params = {
action: 'aggregategroups',
do: 'add',
groupname: aggregateGroupName,
groupdescription: aggregateGroupDesc,
groupsourcelanguagecode: aggregateGroupLanguage
};
api.postWithToken( 'csrf', params )
.done( successFunction )
.fail( function ( code, data ) {
// eslint-disable-next-line no-alert
alert( data.error && data.error.info );
} );
} );
$( '#tpt-aggregategroups-close' ).on( 'click', function ( event ) {
$( 'div.tpt-add-new-group' ).addClass( 'hidden' );
event.preventDefault();
} );
$( '#mw-content-text' ).on( 'click', '.js-tp-toggle-groups', function ( event ) {
var $target = $( event.target );
var $groupContainer = $target.parents( '.js-mw-tpa-group' );
toggleGroupContainer( $groupContainer );
} );
$( 'div.mw-tpa-group' ).first().before( getToggleAllGroupsLink() );
} );
var entitySelectorLimit = 50;
function getEntitySelector( onSelect, filterResults ) {
var EntitySelector = require( 'ext.translate.entity.selector' );
return new EntitySelector( {
onSelect: onSelect,
entityType: [ 'groups' ],
groupTypes: [ 'translatable-pages', 'message-bundles' ],
limit: entitySelectorLimit,
allowSuggestionsWhenEmpty: true,
filterResults: filterResults
} );
}
function filterSelectedGroups( apiResult ) {
var filteredGroups = [];
var alreadySelectedGroups = getSelectedGroups( this.$element );
for ( var i = 0; i < apiResult.groups.length; ++i ) {
var currentGroup = apiResult.groups[ i ];
if ( alreadySelectedGroups[ currentGroup.label ] !== true ) {
filteredGroups.push( currentGroup );
}
if ( filteredGroups.length === entitySelectorLimit ) {
return { groups: filteredGroups };
}
}
return { groups: filteredGroups };
}
function getSelectedGroups( $entitySelector ) {
var exclude = {};
$entitySelector.closest( '.mw-tpa-group' ).find( 'li' ).each(
function ( _key, data ) {
// Need to trim to remove the trailing whitespace
// Can't use innerText not supported by Firefox
exclude[ $( data ).text().trim() ] = true;
}
);
return exclude;
}
}() );