263 lines
9.3 KiB
JavaScript
263 lines
9.3 KiB
JavaScript
/**
|
|
* @file
|
|
* Block behaviors.
|
|
*/
|
|
|
|
(function($, window, Drupal) {
|
|
/**
|
|
* Provide the summary information for the block settings vertical tabs.
|
|
*
|
|
* @type {Drupal~behavior}
|
|
*
|
|
* @prop {Drupal~behaviorAttach} attach
|
|
* Attaches the behavior for the block settings summaries.
|
|
*/
|
|
Drupal.behaviors.blockSettingsSummary = {
|
|
attach() {
|
|
// The drupalSetSummary method required for this behavior is not available
|
|
// on the Blocks administration page, so we need to make sure this
|
|
// behavior is processed only if drupalSetSummary is defined.
|
|
if (typeof $.fn.drupalSetSummary === 'undefined') {
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* Create a summary for checkboxes in the provided context.
|
|
*
|
|
* @param {HTMLDocument|HTMLElement} context
|
|
* A context where one would find checkboxes to summarize.
|
|
*
|
|
* @return {string}
|
|
* A string with the summary.
|
|
*/
|
|
function checkboxesSummary(context) {
|
|
const vals = [];
|
|
const $checkboxes = $(context).find(
|
|
'input[type="checkbox"]:checked + label',
|
|
);
|
|
const il = $checkboxes.length;
|
|
for (let i = 0; i < il; i++) {
|
|
vals.push($($checkboxes[i]).html());
|
|
}
|
|
if (!vals.length) {
|
|
vals.push(Drupal.t('Not restricted'));
|
|
}
|
|
return vals.join(', ');
|
|
}
|
|
|
|
$(
|
|
'[data-drupal-selector="edit-visibility-node-type"], [data-drupal-selector="edit-visibility-language"], [data-drupal-selector="edit-visibility-user-role"]',
|
|
).drupalSetSummary(checkboxesSummary);
|
|
|
|
$(
|
|
'[data-drupal-selector="edit-visibility-request-path"]',
|
|
).drupalSetSummary(context => {
|
|
const $pages = $(context).find(
|
|
'textarea[name="visibility[request_path][pages]"]',
|
|
);
|
|
if (!$pages.val()) {
|
|
return Drupal.t('Not restricted');
|
|
}
|
|
|
|
return Drupal.t('Restricted to certain pages');
|
|
});
|
|
},
|
|
};
|
|
|
|
/**
|
|
* Move a block in the blocks table between regions via select list.
|
|
*
|
|
* This behavior is dependent on the tableDrag behavior, since it uses the
|
|
* objects initialized in that behavior to update the row.
|
|
*
|
|
* @type {Drupal~behavior}
|
|
*
|
|
* @prop {Drupal~behaviorAttach} attach
|
|
* Attaches the tableDrag behaviour for blocks in block administration.
|
|
*/
|
|
Drupal.behaviors.blockDrag = {
|
|
attach(context, settings) {
|
|
// tableDrag is required and we should be on the blocks admin page.
|
|
if (
|
|
typeof Drupal.tableDrag === 'undefined' ||
|
|
typeof Drupal.tableDrag.blocks === 'undefined'
|
|
) {
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* Function to check empty regions and toggle classes based on this.
|
|
*
|
|
* @param {jQuery} table
|
|
* The jQuery object representing the table to inspect.
|
|
* @param {jQuery} rowObject
|
|
* The jQuery object representing the table row.
|
|
*/
|
|
function checkEmptyRegions(table, rowObject) {
|
|
table.find('tr.region-message').each(function() {
|
|
const $this = $(this);
|
|
// If the dragged row is in this region, but above the message row,
|
|
// swap it down one space.
|
|
if ($this.prev('tr').get(0) === rowObject.element) {
|
|
// Prevent a recursion problem when using the keyboard to move rows
|
|
// up.
|
|
if (
|
|
rowObject.method !== 'keyboard' ||
|
|
rowObject.direction === 'down'
|
|
) {
|
|
rowObject.swap('after', this);
|
|
}
|
|
}
|
|
// This region has become empty.
|
|
if (
|
|
$this.next('tr').is(':not(.draggable)') ||
|
|
$this.next('tr').length === 0
|
|
) {
|
|
$this.removeClass('region-populated').addClass('region-empty');
|
|
}
|
|
// This region has become populated.
|
|
else if ($this.is('.region-empty')) {
|
|
$this.removeClass('region-empty').addClass('region-populated');
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Function to update the last placed row with the correct classes.
|
|
*
|
|
* @param {jQuery} table
|
|
* The jQuery object representing the table to inspect.
|
|
* @param {jQuery} rowObject
|
|
* The jQuery object representing the table row.
|
|
*/
|
|
function updateLastPlaced(table, rowObject) {
|
|
// Remove the color-success class from new block if applicable.
|
|
table.find('.color-success').removeClass('color-success');
|
|
|
|
const $rowObject = $(rowObject);
|
|
if (!$rowObject.is('.drag-previous')) {
|
|
table.find('.drag-previous').removeClass('drag-previous');
|
|
$rowObject.addClass('drag-previous');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Update block weights in the given region.
|
|
*
|
|
* @param {jQuery} table
|
|
* Table with draggable items.
|
|
* @param {string} region
|
|
* Machine name of region containing blocks to update.
|
|
*/
|
|
function updateBlockWeights(table, region) {
|
|
// Calculate minimum weight.
|
|
let weight = -Math.round(table.find('.draggable').length / 2);
|
|
// Update the block weights.
|
|
table
|
|
.find(`.region-${region}-message`)
|
|
.nextUntil('.region-title')
|
|
.find('select.block-weight')
|
|
.val(
|
|
// Increment the weight before assigning it to prevent using the
|
|
// absolute minimum available weight. This way we always have an
|
|
// unused upper and lower bound, which makes manually setting the
|
|
// weights easier for users who prefer to do it that way.
|
|
() => ++weight,
|
|
);
|
|
}
|
|
|
|
const table = $('#blocks');
|
|
// Get the blocks tableDrag object.
|
|
const tableDrag = Drupal.tableDrag.blocks;
|
|
// Add a handler for when a row is swapped, update empty regions.
|
|
tableDrag.row.prototype.onSwap = function(swappedRow) {
|
|
checkEmptyRegions(table, this);
|
|
updateLastPlaced(table, this);
|
|
};
|
|
|
|
// Add a handler so when a row is dropped, update fields dropped into
|
|
// new regions.
|
|
tableDrag.onDrop = function() {
|
|
const dragObject = this;
|
|
const $rowElement = $(dragObject.rowObject.element);
|
|
// Use "region-message" row instead of "region" row because
|
|
// "region-{region_name}-message" is less prone to regexp match errors.
|
|
const regionRow = $rowElement.prevAll('tr.region-message').get(0);
|
|
const regionName = regionRow.className.replace(
|
|
/([^ ]+[ ]+)*region-([^ ]+)-message([ ]+[^ ]+)*/,
|
|
'$2',
|
|
);
|
|
const regionField = $rowElement.find('select.block-region-select');
|
|
// Check whether the newly picked region is available for this block.
|
|
if (regionField.find(`option[value=${regionName}]`).length === 0) {
|
|
// If not, alert the user and keep the block in its old region
|
|
// setting.
|
|
window.alert(Drupal.t('The block cannot be placed in this region.'));
|
|
// Simulate that there was a selected element change, so the row is
|
|
// put back to from where the user tried to drag it.
|
|
regionField.trigger('change');
|
|
}
|
|
|
|
// Update region and weight fields if the region has been changed.
|
|
if (!regionField.is(`.block-region-${regionName}`)) {
|
|
const weightField = $rowElement.find('select.block-weight');
|
|
const oldRegionName = weightField[0].className.replace(
|
|
/([^ ]+[ ]+)*block-weight-([^ ]+)([ ]+[^ ]+)*/,
|
|
'$2',
|
|
);
|
|
regionField
|
|
.removeClass(`block-region-${oldRegionName}`)
|
|
.addClass(`block-region-${regionName}`);
|
|
weightField
|
|
.removeClass(`block-weight-${oldRegionName}`)
|
|
.addClass(`block-weight-${regionName}`);
|
|
regionField.val(regionName);
|
|
}
|
|
|
|
updateBlockWeights(table, regionName);
|
|
};
|
|
|
|
// Add the behavior to each region select list.
|
|
$(context)
|
|
.find('select.block-region-select')
|
|
.once('block-region-select')
|
|
.on('change', function(event) {
|
|
// Make our new row and select field.
|
|
const row = $(this).closest('tr');
|
|
const select = $(this);
|
|
// Find the correct region and insert the row as the last in the
|
|
// region.
|
|
tableDrag.rowObject = new tableDrag.row(row[0]);
|
|
const regionMessage = table.find(
|
|
`.region-${select[0].value}-message`,
|
|
);
|
|
const regionItems = regionMessage.nextUntil(
|
|
'.region-message, .region-title',
|
|
);
|
|
if (regionItems.length) {
|
|
regionItems.last().after(row);
|
|
}
|
|
// We found that regionMessage is the last row.
|
|
else {
|
|
regionMessage.after(row);
|
|
}
|
|
updateBlockWeights(table, select[0].value);
|
|
// Modify empty regions with added or removed fields.
|
|
checkEmptyRegions(table, tableDrag.rowObject);
|
|
// Update last placed block indication.
|
|
updateLastPlaced(table, row);
|
|
// Show unsaved changes warning.
|
|
if (!tableDrag.changed) {
|
|
$(Drupal.theme('tableDragChangedWarning'))
|
|
.insertBefore(tableDrag.table)
|
|
.hide()
|
|
.fadeIn('slow');
|
|
tableDrag.changed = true;
|
|
}
|
|
// Remove focus from selectbox.
|
|
select.trigger('blur');
|
|
});
|
|
},
|
|
};
|
|
})(jQuery, window, Drupal);
|