29
0
mirror of https://github.com/joomla/joomla-cms.git synced 2024-06-28 08:03:40 +00:00

Fix table multiselect (#42330)

* Multiselect update

* Multiselect update

* Multiselect update

* Multiselect update

* Multiselect update

* Update build/media_source/system/js/multiselect.es6.js

Co-authored-by: Dimitris Grammatikogiannis <dg@dgrammatiko.dev>
This commit is contained in:
Fedir Zinchuk 2023-11-13 10:43:14 +02:00 committed by GitHub
parent 584d7b00b4
commit beb3b34c7c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 106 additions and 97 deletions

View File

@ -102,7 +102,7 @@
],
"uri": "system/multiselect.min.js",
"attributes": {
"defer": true
"type": "module"
}
},
{

View File

@ -6,108 +6,117 @@
/**
* JavaScript behavior to allow shift select in administrator grids
*/
((Joomla) => {
'use strict';
class JMultiSelect {
constructor(container) {
this.tableEl = container;
this.formEl = container.closest('form');
this.rowSelector = 'tr[class^="row"]';
this.boxSelector = 'input[type="checkbox"][name="cid[]"]';
this.checkallToggle = this.tableEl.querySelector('[name="checkall-toggle"]');
this.prevRow = null;
class JMultiSelect {
constructor(formElement) {
this.tableEl = document.querySelector(formElement);
if (this.tableEl) {
this.boxes = [].slice.call(this.tableEl.querySelectorAll('td input[type=checkbox]'));
this.rows = [].slice.call(document.querySelectorAll('tr[class^="row"]'));
this.checkallToggle = document.querySelector('[name="checkall-toggle"]');
this.onCheckallToggleClick = this.onCheckallToggleClick.bind(this);
this.onRowClick = this.onRowClick.bind(this);
if (this.checkallToggle) {
this.checkallToggle.addEventListener('click', this.onCheckallToggleClick);
}
if (this.rows.length) {
this.rows.forEach((row) => {
row.addEventListener('click', this.onRowClick);
});
}
// Use delegation listener, to allow dynamic tables
this.tableEl.addEventListener('click', (event) => {
if (!event.target.closest(this.rowSelector)) {
return;
}
}
this.onRowClick(event);
});
// Changes the background-color on every cell inside a <tr>
// eslint-disable-next-line class-methods-use-this
changeBg(row, isChecked) {
// Check if it should add or remove the background colour
if (isChecked) {
[].slice.call(row.querySelectorAll('td, th')).forEach((elementToMark) => {
elementToMark.classList.add('row-selected');
if (this.checkallToggle) {
this.checkallToggle.addEventListener('click', ({ target }) => {
const isChecked = target.checked;
this.getRows().forEach((row) => {
this.changeBg(row, isChecked);
});
} else {
[].slice.call(row.querySelectorAll('td, th')).forEach((elementToMark) => {
elementToMark.classList.remove('row-selected');
});
}
}
onCheckallToggleClick({ target }) {
const isChecked = target.checked;
this.rows.forEach((row) => {
this.changeBg(row, isChecked);
});
}
onRowClick({ target, shiftKey }) {
// Do not interfere with links or buttons
if (target.tagName && (target.tagName.toLowerCase() === 'a' || target.tagName.toLowerCase() === 'button')) {
return;
}
if (!this.boxes.length) {
return;
}
const closestRow = target.closest('tr');
const currentRowNum = this.rows.indexOf(closestRow);
const currentCheckBox = closestRow.querySelector('td input[type=checkbox]');
if (currentCheckBox) {
let isChecked = currentCheckBox.checked;
if (!(target.id === currentCheckBox.id)) {
// We will prevent selecting text to prevent artifacts
if (shiftKey) {
document.body.style['-webkit-user-select'] = 'none';
document.body.style['-moz-user-select'] = 'none';
document.body.style['-ms-user-select'] = 'none';
document.body.style['user-select'] = 'none';
}
currentCheckBox.checked = !currentCheckBox.checked;
isChecked = currentCheckBox.checked;
Joomla.isChecked(isChecked, this.tableEl.id);
}
this.changeBg(this.rows[currentRowNum], isChecked);
// Restore normality
if (shiftKey) {
document.body.style['-webkit-user-select'] = 'none';
document.body.style['-moz-user-select'] = 'none';
document.body.style['-ms-user-select'] = 'none';
document.body.style['user-select'] = 'none';
}
}
}
}
const onBoot = () => {
let formId = '#adminForm';
if (Joomla && Joomla.getOptions('js-multiselect', {}).formName) {
formId = `#${Joomla.getOptions('js-multiselect', {}).formName}`;
}
// eslint-disable-next-line no-new
new JMultiSelect(formId);
};
getRows() {
return Array.from(this.tableEl.querySelectorAll(this.rowSelector));
}
document.addEventListener('DOMContentLoaded', onBoot);
})(Joomla);
// Changes the row class depends on selection
// eslint-disable-next-line class-methods-use-this
changeBg(row, isChecked) {
row.classList.toggle('row-selected', isChecked);
}
// Handle click on a row
onRowClick({ target, shiftKey }) {
// Do not interfere with links, buttons, inputs
if (target.tagName && (target.tagName === 'A' || target.tagName === 'BUTTON'
|| target.tagName === 'SELECT' || target.tagName === 'TEXTAREA'
|| (target.tagName === 'INPUT' && !target.matches(this.boxSelector)))) {
return;
}
// Get clicked row and checkbox in it
const currentRow = target.closest(this.rowSelector);
const currentBox = target.matches(this.boxSelector) ? target : currentRow.querySelector(this.boxSelector);
if (!currentBox) {
return;
}
const isChecked = (currentBox !== target) ? !currentBox.checked : currentBox.checked;
if (isChecked !== currentBox.checked) {
currentBox.checked = isChecked;
Joomla.isChecked(isChecked, this.formEl);
}
this.changeBg(currentRow, isChecked);
// Select rows in range
if (shiftKey && this.prevRow) {
// Prevent text selection
document.getSelection().removeAllRanges();
// Re-query all rows, because they may be modified during sort operations
const rows = this.getRows();
const idxStart = rows.indexOf(this.prevRow);
const idxEnd = rows.indexOf(currentRow);
// Check for more than 2 row selected
if (idxStart >= 0 && idxEnd >= 0 && Math.abs(idxStart - idxEnd) > 1) {
const slice = idxStart < idxEnd ? rows.slice(idxStart, idxEnd + 1) : rows.slice(idxEnd, idxStart + 1);
slice.forEach((row) => {
if (row === currentRow) {
return;
}
const rowBox = row.querySelector(this.boxSelector);
if (rowBox && rowBox.checked !== isChecked) {
rowBox.checked = isChecked;
this.changeBg(row, isChecked);
Joomla.isChecked(isChecked, this.formEl);
}
});
}
}
this.prevRow = currentRow;
}
}
const onBoot = (container) => {
let selector = '#adminForm';
const confSelector = window.Joomla ? Joomla.getOptions('js-multiselect', {}).formName : '';
if (confSelector) {
const pref = confSelector[0];
selector = (pref !== '.' && pref !== '#') ? `#${confSelector}` : confSelector;
}
container.querySelectorAll(selector).forEach((formElement) => {
if (formElement && !('multiselect' in formElement.dataset)) {
formElement.dataset.multiselect = '';
// eslint-disable-next-line no-new
new JMultiSelect(formElement);
}
});
};
onBoot(document);
document.addEventListener('joomla:updated', ({ target }) => onBoot(target));