first commit

This commit is contained in:
2024-07-15 12:33:27 +02:00
commit ce50ae282b
22084 changed files with 2623791 additions and 0 deletions

View File

@@ -0,0 +1,463 @@
/**
* @file
* Extends methods from core/misc/tabledrag.js.
*/
(function ($) {
// Save the original prototype.
var prototype = Drupal.tableDrag.prototype;
/**
* Provides table and field manipulation.
*
* @constructor
*
* @param {HTMLElement} table
* DOM object for the table to be made draggable.
* @param {object} tableSettings
* Settings for the table added via drupal_add_dragtable().
*/
Drupal.tableDrag = function (table, tableSettings) {
var self = this;
var $table = $(table);
/**
* @type {jQuery}
*/
this.$table = $(table);
/**
*
* @type {HTMLElement}
*/
this.table = table;
/**
* @type {object}
*/
this.tableSettings = tableSettings;
/**
* Used to hold information about a current drag operation.
*
* @type {?HTMLElement}
*/
this.dragObject = null;
/**
* Provides operations for row manipulation.
*
* @type {?HTMLElement}
*/
this.rowObject = null;
/**
* Remember the previous element.
*
* @type {?HTMLElement}
*/
this.oldRowElement = null;
/**
* Used to determine up or down direction from last mouse move.
*
* @type {number}
*/
this.oldY = 0;
/**
* Whether anything in the entire table has changed.
*
* @type {bool}
*/
this.changed = false;
/**
* Maximum amount of allowed parenting.
*
* @type {number}
*/
this.maxDepth = 0;
/**
* Direction of the table.
*
* @type {number}
*/
this.rtl = $(this.table).css('direction') === 'rtl' ? -1 : 1;
/**
*
* @type {bool}
*/
this.striping = $(this.table).data('striping') === 1;
/**
* Configure the scroll settings.
*
* @type {object}
*
* @prop {number} amount
* @prop {number} interval
* @prop {number} trigger
*/
this.scrollSettings = {amount: 4, interval: 50, trigger: 70};
/**
*
* @type {?number}
*/
this.scrollInterval = null;
/**
*
* @type {number}
*/
this.scrollY = 0;
/**
*
* @type {number}
*/
this.windowHeight = 0;
/**
* @type {?HTMLElement}
*/
this.$toggleWeightButton = null;
/**
* Check this table's settings to see if there are parent relationships in
* this table. For efficiency, large sections of code can be skipped if we
* don't need to track horizontal movement and indentations.
*
* @type {bool}
*/
this.indentEnabled = false;
for (var group in tableSettings) {
if (tableSettings.hasOwnProperty(group)) {
for (var n in tableSettings[group]) {
if (tableSettings[group].hasOwnProperty(n)) {
if (tableSettings[group][n].relationship === 'parent') {
this.indentEnabled = true;
}
if (tableSettings[group][n].limit > 0) {
this.maxDepth = tableSettings[group][n].limit;
}
}
}
}
}
if (this.indentEnabled) {
/**
* Total width of indents, set in makeDraggable.
*
* @type {number}
*/
this.indentCount = 1;
// Find the width of indentations to measure mouse movements against.
// Because the table doesn't need to start with any indentations, we
// manually append 2 indentations in the first draggable row, measure
// the offset, then remove.
var indent = Drupal.theme('tableDragIndentation');
var testRow = $('<tr/>').addClass('draggable').appendTo(table);
var testCell = $('<td/>').appendTo(testRow).prepend(indent).prepend(indent);
var $indentation = testCell.find('.js-indentation');
/**
*
* @type {number}
*/
this.indentAmount = $indentation.get(1).offsetLeft - $indentation.get(0).offsetLeft;
testRow.remove();
}
// Make each applicable row draggable.
// Match immediate children of the parent element to allow nesting.
$table.find('> tr.draggable, > tbody > tr.draggable').each(function () { self.makeDraggable(this); });
// Add a link before the table for users to show or hide weight columns.
self.$toggleWeightButton = $(Drupal.theme('btn-sm', {
'class': ['tabledrag-toggle-weight'],
'data-drupal-selector': ['tabledrag-toggle-weight'],
title: Drupal.t('Re-order rows by numerical weight instead of dragging.'),
'data-toggle': 'tooltip'
}));
self.$toggleWeightButton
.on('click', $.proxy(function (e) {
e.preventDefault();
this.toggleColumns();
}, this))
.wrap('<div class="tabledrag-toggle-weight-wrapper"></div>')
.parent();
$table.before(self.$toggleWeightButton);
// Initialize the specified columns (for example, weight or parent columns)
// to show or hide according to user preference. This aids accessibility
// so that, e.g., screen reader users can choose to enter weight values and
// manipulate form elements directly, rather than using drag-and-drop..
self.initColumns();
// Add event bindings to the document. The self variable is passed along
// as event handlers do not have direct access to the tableDrag object.
$(document).on('touchmove', function (event) { return self.dragRow(event.originalEvent.touches[0], self); });
$(document).on('touchend', function (event) { return self.dropRow(event.originalEvent.touches[0], self); });
$(document).on('mousemove pointermove', function (event) { return self.dragRow(event, self); });
$(document).on('mouseup pointerup', function (event) { return self.dropRow(event, self); });
// React to localStorage event showing or hiding weight columns.
$(window).on('storage', $.proxy(function (e) {
// Only react to 'Drupal.tableDrag.showWeight' value change.
if (e.originalEvent.key === 'Drupal.tableDrag.showWeight') {
// This was changed in another window, get the new value for this
// window.
showWeight = JSON.parse(e.originalEvent.newValue);
this.displayColumns(showWeight);
}
}, this));
};
// Restore the original prototype.
Drupal.tableDrag.prototype = prototype;
/**
* Take an item and add event handlers to make it become draggable.
*
* @param {HTMLElement} item
*/
Drupal.tableDrag.prototype.makeDraggable = function (item) {
var self = this;
var $item = $(item);
// Add a class to the title link
$item.find('td:first-of-type').find('a').addClass('menu-item__link');
// Create the handle.
var handle = $('<a href="#" class="tabledrag-handle"/>');
// Insert the handle after indentations (if any).
var $indentationLast = $item.find('td:first-of-type').find('.js-indentation').eq(-1);
if ($indentationLast.length) {
$indentationLast.after(handle);
// Update the total width of indentation in this entire table.
self.indentCount = Math.max($item.find('.js-indentation').length, self.indentCount);
}
else {
$item.find('td').eq(0).prepend(handle);
}
// Add the glyphicon to the handle.
handle
.attr('title', Drupal.t('Drag to re-order'))
.attr('data-toggle', 'tooltip')
.append(Drupal.theme('bootstrapIcon', 'move'))
;
handle.on('mousedown touchstart pointerdown', function (event) {
event.preventDefault();
if (event.originalEvent.type === 'touchstart') {
event = event.originalEvent.touches[0];
}
self.dragStart(event, self, item);
});
// Prevent the anchor tag from jumping us to the top of the page.
handle.on('click', function (e) {
e.preventDefault();
});
// Set blur cleanup when a handle is focused.
handle.on('focus', function () {
self.safeBlur = true;
});
// On blur, fire the same function as a touchend/mouseup. This is used to
// update values after a row has been moved through the keyboard support.
handle.on('blur', function (event) {
if (self.rowObject && self.safeBlur) {
self.dropRow(event, self);
}
});
// Add arrow-key support to the handle.
handle.on('keydown', function (event) {
// If a rowObject doesn't yet exist and this isn't the tab key.
if (event.keyCode !== 9 && !self.rowObject) {
self.rowObject = new self.row(item, 'keyboard', self.indentEnabled, self.maxDepth, true);
}
var keyChange = false;
var groupHeight;
switch (event.keyCode) {
// Left arrow.
case 37:
// Safari left arrow.
case 63234:
keyChange = true;
self.rowObject.indent(-1 * self.rtl);
break;
// Up arrow.
case 38:
// Safari up arrow.
case 63232:
var $previousRow = $(self.rowObject.element).prev('tr:first-of-type');
var previousRow = $previousRow.get(0);
while (previousRow && $previousRow.is(':hidden')) {
$previousRow = $(previousRow).prev('tr:first-of-type');
previousRow = $previousRow.get(0);
}
if (previousRow) {
// Do not allow the onBlur cleanup.
self.safeBlur = false;
self.rowObject.direction = 'up';
keyChange = true;
if ($(item).is('.tabledrag-root')) {
// Swap with the previous top-level row.
groupHeight = 0;
while (previousRow && $previousRow.find('.js-indentation').length) {
$previousRow = $(previousRow).prev('tr:first-of-type');
previousRow = $previousRow.get(0);
groupHeight += $previousRow.is(':hidden') ? 0 : previousRow.offsetHeight;
}
if (previousRow) {
self.rowObject.swap('before', previousRow);
// No need to check for indentation, 0 is the only valid one.
window.scrollBy(0, -groupHeight);
}
}
else if (self.table.tBodies[0].rows[0] !== previousRow || $previousRow.is('.draggable')) {
// Swap with the previous row (unless previous row is the first
// one and undraggable).
self.rowObject.swap('before', previousRow);
self.rowObject.interval = null;
self.rowObject.indent(0);
window.scrollBy(0, -parseInt(item.offsetHeight, 10));
}
// Regain focus after the DOM manipulation.
handle.trigger('focus');
}
break;
// Right arrow.
case 39:
// Safari right arrow.
case 63235:
keyChange = true;
self.rowObject.indent(self.rtl);
break;
// Down arrow.
case 40:
// Safari down arrow.
case 63233:
var $nextRow = $(self.rowObject.group).eq(-1).next('tr:first-of-type');
var nextRow = $nextRow.get(0);
while (nextRow && $nextRow.is(':hidden')) {
$nextRow = $(nextRow).next('tr:first-of-type');
nextRow = $nextRow.get(0);
}
if (nextRow) {
// Do not allow the onBlur cleanup.
self.safeBlur = false;
self.rowObject.direction = 'down';
keyChange = true;
if ($(item).is('.tabledrag-root')) {
// Swap with the next group (necessarily a top-level one).
groupHeight = 0;
var nextGroup = new self.row(nextRow, 'keyboard', self.indentEnabled, self.maxDepth, false);
if (nextGroup) {
$(nextGroup.group).each(function () {
groupHeight += $(this).is(':hidden') ? 0 : this.offsetHeight;
});
var nextGroupRow = $(nextGroup.group).eq(-1).get(0);
self.rowObject.swap('after', nextGroupRow);
// No need to check for indentation, 0 is the only valid one.
window.scrollBy(0, parseInt(groupHeight, 10));
}
}
else {
// Swap with the next row.
self.rowObject.swap('after', nextRow);
self.rowObject.interval = null;
self.rowObject.indent(0);
window.scrollBy(0, parseInt(item.offsetHeight, 10));
}
// Regain focus after the DOM manipulation.
handle.trigger('focus');
}
break;
}
if (self.rowObject && self.rowObject.changed === true) {
$(item).addClass('drag');
if (self.oldRowElement) {
$(self.oldRowElement).removeClass('drag-previous');
}
self.oldRowElement = item;
if (self.striping === true) {
self.restripeTable();
}
self.onDrag();
}
// Returning false if we have an arrow key to prevent scrolling.
if (keyChange) {
return false;
}
});
// Compatibility addition, return false on keypress to prevent unwanted
// scrolling. IE and Safari will suppress scrolling on keydown, but all
// other browsers need to return false on keypress.
// http://www.quirksmode.org/js/keys.html
handle.on('keypress', function (event) {
switch (event.keyCode) {
// Left arrow.
case 37:
// Up arrow.
case 38:
// Right arrow.
case 39:
// Down arrow.
case 40:
return false;
}
});
};
/**
* Add an asterisk or other marker to the changed row.
*/
Drupal.tableDrag.prototype.row.prototype.markChanged = function () {
var $cell = $('td:first', this.element);
// Find the first appropriate place to insert the marker.
var $target = $($cell.find('.file-size').get(0) || $cell.find('.file').get(0) || $cell.find('.tabledrag-handle').get(0));
if (!$cell.find('.tabledrag-changed').length) {
$target.after(' ' + Drupal.theme('tableDragChangedMarker') + ' ');
}
};
$.extend(Drupal.theme, /** @lends Drupal.theme */{
/**
* @return {string}
*/
tableDragChangedMarker: function () {
return Drupal.theme('bootstrapIcon', 'warning-sign', {'class': ['tabledrag-changed', 'text-warning']});
},
/**
* @return {string}
*/
tableDragChangedWarning: function () {
return '<div class="tabledrag-changed-warning alert alert-sm alert-warning messages warning">' + Drupal.theme('tableDragChangedMarker') + ' ' + Drupal.t('You have unsaved changes.') + '</div>';
}
});
})(jQuery);