559 lines
16 KiB
JavaScript
559 lines
16 KiB
JavaScript
(function (window, document) {
|
||
'use strict';
|
||
|
||
var DropdownGrid = {};
|
||
var activeRoot = null;
|
||
var activeClone = null;
|
||
var selectionCounter = 1;
|
||
|
||
DropdownGrid.initAll = function () {
|
||
var grids = document.querySelectorAll('[data-dropdown-grid="true"]');
|
||
|
||
for (var i = 0; i < grids.length; i++) {
|
||
DropdownGrid.init(grids[i]);
|
||
}
|
||
};
|
||
|
||
DropdownGrid.init = function (root) {
|
||
if (!root)
|
||
return;
|
||
|
||
if (root.getAttribute('data-dropdown-grid-init') === 'true')
|
||
return;
|
||
|
||
root.setAttribute('data-dropdown-grid-init', 'true');
|
||
|
||
DropdownGrid.initializeSelectedOrder(root.querySelector('.dropdown-grid-table-box'));
|
||
|
||
var input = root.querySelector('[data-dropdown-search="true"]');
|
||
|
||
if (input) {
|
||
input.removeAttribute('readonly');
|
||
input.removeAttribute('disabled');
|
||
|
||
input.addEventListener('mousedown', function (e) {
|
||
e.stopPropagation();
|
||
});
|
||
|
||
input.addEventListener('click', function (e) {
|
||
e.stopPropagation();
|
||
|
||
if (activeRoot !== root) {
|
||
DropdownGrid.show(root, true);
|
||
}
|
||
});
|
||
|
||
input.addEventListener('focus', function () {
|
||
if (activeRoot !== root) {
|
||
DropdownGrid.show(root, true);
|
||
}
|
||
});
|
||
|
||
input.addEventListener('input', function () {
|
||
if (activeRoot !== root) {
|
||
DropdownGrid.show(root, false);
|
||
}
|
||
|
||
DropdownGrid.filter(root, input.value);
|
||
});
|
||
|
||
input.addEventListener('keydown', function (e) {
|
||
if (e.key === 'Escape') {
|
||
e.preventDefault();
|
||
DropdownGrid.hideAll(true);
|
||
input.blur();
|
||
}
|
||
});
|
||
}
|
||
|
||
root.addEventListener('click', function (e) {
|
||
e.stopPropagation();
|
||
|
||
var target = e.target;
|
||
|
||
if (target.classList.contains('dropdown-grid-chip-remove')) {
|
||
e.preventDefault();
|
||
DropdownGrid.removeValue(root, target.getAttribute('data-value'));
|
||
}
|
||
});
|
||
|
||
DropdownGrid.updateDisplay(root);
|
||
DropdownGrid.moveSelectedRowsTop(root.querySelector('.dropdown-grid-table-box'));
|
||
};
|
||
|
||
DropdownGrid.show = function (root, clearInput) {
|
||
var input = root.querySelector('[data-dropdown-search="true"]');
|
||
var originalGrid = root.querySelector('.dropdown-grid-table-box');
|
||
|
||
if (!input || !originalGrid)
|
||
return;
|
||
|
||
DropdownGrid.hideAll(false);
|
||
|
||
DropdownGrid.moveSelectedRowsTop(originalGrid);
|
||
|
||
activeRoot = root;
|
||
activeClone = originalGrid.cloneNode(true);
|
||
|
||
activeClone.classList.add('dropdown-grid-floating');
|
||
activeClone.setAttribute('data-dropdown-grid-floating', 'true');
|
||
activeClone.style.display = 'block';
|
||
|
||
document.body.appendChild(activeClone);
|
||
|
||
if (clearInput === true)
|
||
input.value = '';
|
||
|
||
DropdownGrid.positionClone(root);
|
||
DropdownGrid.bindCloneEvents(root, activeClone);
|
||
DropdownGrid.syncCloneFromOriginal(root, activeClone);
|
||
DropdownGrid.moveSelectedRowsTop(activeClone);
|
||
DropdownGrid.syncCloneFromOriginal(root, activeClone);
|
||
DropdownGrid.filter(root, input.value);
|
||
|
||
setTimeout(function () {
|
||
input.focus();
|
||
}, 0);
|
||
};
|
||
|
||
DropdownGrid.hideAll = function (restoreText) {
|
||
var rootToRestore = activeRoot;
|
||
|
||
var clones = document.querySelectorAll('[data-dropdown-grid-floating="true"]');
|
||
|
||
for (var i = 0; i < clones.length; i++) {
|
||
if (clones[i].parentNode)
|
||
clones[i].parentNode.removeChild(clones[i]);
|
||
}
|
||
|
||
if (restoreText === true && rootToRestore) {
|
||
DropdownGrid.restoreInputText(rootToRestore);
|
||
}
|
||
|
||
activeRoot = null;
|
||
activeClone = null;
|
||
};
|
||
|
||
DropdownGrid.positionClone = function (root) {
|
||
if (!activeClone)
|
||
return;
|
||
|
||
var input = root.querySelector('[data-dropdown-search="true"]');
|
||
|
||
if (!input)
|
||
return;
|
||
|
||
var rect = input.getBoundingClientRect();
|
||
|
||
activeClone.style.position = 'fixed';
|
||
activeClone.style.left = rect.left + 'px';
|
||
activeClone.style.top = (rect.bottom + 2) + 'px';
|
||
activeClone.style.minWidth = rect.width + 'px';
|
||
activeClone.style.zIndex = '999999';
|
||
};
|
||
|
||
DropdownGrid.bindCloneEvents = function (root, clone) {
|
||
clone.addEventListener('mousedown', function (e) {
|
||
e.stopPropagation();
|
||
});
|
||
|
||
clone.addEventListener('click', function (e) {
|
||
e.stopPropagation();
|
||
|
||
var target = e.target;
|
||
var row = DropdownGrid.getRow(target);
|
||
|
||
if (target.classList.contains('dropdown-grid-select-all')) {
|
||
setTimeout(function () {
|
||
DropdownGrid.cloneSelectAllChanged(root, clone, target.checked);
|
||
}, 0);
|
||
|
||
return;
|
||
}
|
||
|
||
if (!row)
|
||
return;
|
||
|
||
var check = row.querySelector('.dropdown-grid-check');
|
||
|
||
if (!check)
|
||
return;
|
||
|
||
if (target !== check) {
|
||
e.preventDefault();
|
||
check.checked = !check.checked;
|
||
}
|
||
|
||
setTimeout(function () {
|
||
DropdownGrid.applyValue(root, check.value, check.checked);
|
||
}, 0);
|
||
});
|
||
};
|
||
|
||
DropdownGrid.applyValue = function (root, value, checked) {
|
||
var multiple = root.getAttribute('data-multiple') === 'true';
|
||
var originalGrid = root.querySelector('.dropdown-grid-table-box');
|
||
|
||
if (!originalGrid)
|
||
return;
|
||
|
||
if (!multiple && checked) {
|
||
DropdownGrid.setAllChecks(originalGrid, false);
|
||
|
||
if (activeRoot === root && activeClone) {
|
||
DropdownGrid.setAllChecks(activeClone, false);
|
||
}
|
||
}
|
||
|
||
var realCheck = originalGrid.querySelector(
|
||
'.dropdown-grid-check[value="' + cssEscape(value) + '"]'
|
||
);
|
||
|
||
if (realCheck) {
|
||
realCheck.checked = checked;
|
||
|
||
var realRow = DropdownGrid.getRow(realCheck);
|
||
|
||
if (checked && realRow) {
|
||
realRow.setAttribute('data-selected-order', selectionCounter++);
|
||
} else if (realRow) {
|
||
realRow.removeAttribute('data-selected-order');
|
||
}
|
||
}
|
||
|
||
DropdownGrid.refreshHidden(root);
|
||
DropdownGrid.updateDisplay(root);
|
||
|
||
DropdownGrid.moveSelectedRowsTop(originalGrid);
|
||
|
||
if (activeRoot === root && activeClone) {
|
||
DropdownGrid.rebuildClone(root);
|
||
|
||
var input = root.querySelector('[data-dropdown-search="true"]');
|
||
|
||
if (input)
|
||
DropdownGrid.filter(root, input.value);
|
||
}
|
||
};
|
||
|
||
DropdownGrid.rebuildClone = function (root) {
|
||
var originalGrid = root.querySelector('.dropdown-grid-table-box');
|
||
|
||
if (!originalGrid || !activeClone)
|
||
return;
|
||
|
||
var oldClone = activeClone;
|
||
|
||
activeClone = originalGrid.cloneNode(true);
|
||
activeClone.classList.add('dropdown-grid-floating');
|
||
activeClone.setAttribute('data-dropdown-grid-floating', 'true');
|
||
activeClone.style.display = 'block';
|
||
|
||
if (oldClone.parentNode) {
|
||
oldClone.parentNode.replaceChild(activeClone, oldClone);
|
||
} else {
|
||
document.body.appendChild(activeClone);
|
||
}
|
||
|
||
DropdownGrid.positionClone(root);
|
||
DropdownGrid.bindCloneEvents(root, activeClone);
|
||
DropdownGrid.syncCloneFromOriginal(root, activeClone);
|
||
DropdownGrid.moveSelectedRowsTop(activeClone);
|
||
DropdownGrid.syncCloneFromOriginal(root, activeClone);
|
||
};
|
||
|
||
DropdownGrid.setAllChecks = function (container, checked) {
|
||
if (!container)
|
||
return;
|
||
|
||
var checks = container.querySelectorAll('.dropdown-grid-check');
|
||
|
||
for (var i = 0; i < checks.length; i++) {
|
||
checks[i].checked = checked;
|
||
|
||
var row = DropdownGrid.getRow(checks[i]);
|
||
|
||
if (row)
|
||
row.removeAttribute('data-selected-order');
|
||
}
|
||
};
|
||
|
||
DropdownGrid.getRow = function (target) {
|
||
while (target && target !== document) {
|
||
if (target.tagName && target.tagName.toLowerCase() === 'tr')
|
||
return target;
|
||
|
||
target = target.parentNode;
|
||
}
|
||
|
||
return null;
|
||
};
|
||
|
||
DropdownGrid.cloneSelectAllChanged = function (root, clone, checked) {
|
||
var cloneRows = clone.querySelectorAll('tbody tr');
|
||
|
||
for (var i = 0; i < cloneRows.length; i++) {
|
||
if (cloneRows[i].style.display === 'none')
|
||
continue;
|
||
|
||
var cloneCheck = cloneRows[i].querySelector('.dropdown-grid-check');
|
||
|
||
if (!cloneCheck)
|
||
continue;
|
||
|
||
DropdownGrid.applyValue(root, cloneCheck.value, checked);
|
||
}
|
||
|
||
DropdownGrid.refreshHidden(root);
|
||
DropdownGrid.updateDisplay(root);
|
||
DropdownGrid.moveSelectedRowsTop(root.querySelector('.dropdown-grid-table-box'));
|
||
|
||
if (activeClone) {
|
||
DropdownGrid.rebuildClone(root);
|
||
}
|
||
};
|
||
|
||
DropdownGrid.syncCloneFromOriginal = function (root, clone) {
|
||
if (!clone)
|
||
return;
|
||
|
||
var originalChecks = root.querySelectorAll('.dropdown-grid-table-box .dropdown-grid-check');
|
||
|
||
for (var i = 0; i < originalChecks.length; i++) {
|
||
var cloneCheck = clone.querySelector(
|
||
'.dropdown-grid-check[value="' + cssEscape(originalChecks[i].value) + '"]'
|
||
);
|
||
|
||
if (!cloneCheck)
|
||
continue;
|
||
|
||
cloneCheck.checked = originalChecks[i].checked;
|
||
|
||
var originalRow = DropdownGrid.getRow(originalChecks[i]);
|
||
var cloneRow = DropdownGrid.getRow(cloneCheck);
|
||
|
||
if (originalRow && cloneRow) {
|
||
var order = originalRow.getAttribute('data-selected-order');
|
||
|
||
if (order)
|
||
cloneRow.setAttribute('data-selected-order', order);
|
||
else
|
||
cloneRow.removeAttribute('data-selected-order');
|
||
}
|
||
}
|
||
};
|
||
|
||
DropdownGrid.initializeSelectedOrder = function (container) {
|
||
if (!container)
|
||
return;
|
||
|
||
var checks = container.querySelectorAll('.dropdown-grid-check:checked');
|
||
|
||
for (var i = 0; i < checks.length; i++) {
|
||
var row = DropdownGrid.getRow(checks[i]);
|
||
|
||
if (row && !row.getAttribute('data-selected-order')) {
|
||
row.setAttribute('data-selected-order', selectionCounter++);
|
||
}
|
||
}
|
||
};
|
||
|
||
DropdownGrid.moveSelectedRowsTop = function (container) {
|
||
if (!container)
|
||
return;
|
||
|
||
var tbody = container.querySelector('tbody');
|
||
|
||
if (!tbody)
|
||
return;
|
||
|
||
var rows = Array.prototype.slice.call(tbody.querySelectorAll('tr'));
|
||
var selected = [];
|
||
var unselected = [];
|
||
|
||
for (var i = 0; i < rows.length; i++) {
|
||
var check = rows[i].querySelector('.dropdown-grid-check');
|
||
|
||
if (check && check.checked)
|
||
selected.push(rows[i]);
|
||
else
|
||
unselected.push(rows[i]);
|
||
}
|
||
|
||
selected.sort(function (a, b) {
|
||
var ao = parseInt(a.getAttribute('data-selected-order') || '0', 10);
|
||
var bo = parseInt(b.getAttribute('data-selected-order') || '0', 10);
|
||
|
||
return bo - ao;
|
||
});
|
||
|
||
for (var s = 0; s < selected.length; s++) {
|
||
tbody.appendChild(selected[s]);
|
||
}
|
||
|
||
for (var u = 0; u < unselected.length; u++) {
|
||
tbody.appendChild(unselected[u]);
|
||
}
|
||
};
|
||
|
||
DropdownGrid.filter = function (root, value) {
|
||
value = (value || '').toLowerCase();
|
||
|
||
var container = activeRoot === root && activeClone
|
||
? activeClone
|
||
: root.querySelector('.dropdown-grid-table-box');
|
||
|
||
if (!container)
|
||
return;
|
||
|
||
var rows = container.querySelectorAll('tbody tr');
|
||
|
||
for (var i = 0; i < rows.length; i++) {
|
||
var search = rows[i].getAttribute('data-search') || '';
|
||
rows[i].style.display = search.indexOf(value) >= 0 ? '' : 'none';
|
||
}
|
||
};
|
||
|
||
DropdownGrid.refreshHidden = function (root) {
|
||
var hidden = root.querySelector('input[type="hidden"]');
|
||
var checks = root.querySelectorAll('.dropdown-grid-table-box .dropdown-grid-check:checked');
|
||
var selected = [];
|
||
|
||
for (var i = 0; i < checks.length; i++) {
|
||
selected.push(checks[i].value);
|
||
}
|
||
|
||
if (hidden)
|
||
hidden.value = selected.join(',');
|
||
};
|
||
|
||
DropdownGrid.removeValue = function (root, value) {
|
||
DropdownGrid.applyValue(root, value, false);
|
||
};
|
||
|
||
DropdownGrid.updateDisplay = function (root) {
|
||
var hidden = root.querySelector('input[type="hidden"]');
|
||
var input = root.querySelector('[data-dropdown-search="true"]');
|
||
var chips = root.querySelector('.dropdown-grid-chips');
|
||
|
||
if (!hidden)
|
||
return;
|
||
|
||
var multiple = root.getAttribute('data-multiple') === 'true';
|
||
var values = hidden.value ? hidden.value.split(',') : [];
|
||
|
||
if (!multiple || values.length <= 1) {
|
||
if (chips) {
|
||
chips.innerHTML = '';
|
||
chips.style.display = 'none';
|
||
}
|
||
|
||
if (input && activeRoot !== root) {
|
||
if (values.length === 1) {
|
||
var row = root.querySelector(
|
||
'.dropdown-grid-table-box tr[data-key="' + cssEscape(values[0]) + '"]'
|
||
);
|
||
|
||
input.value = row ? row.getAttribute('data-text') || '' : '';
|
||
} else {
|
||
input.value = '';
|
||
}
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
if (input && activeRoot !== root)
|
||
input.value = '';
|
||
|
||
if (!chips)
|
||
return;
|
||
|
||
chips.innerHTML = '';
|
||
chips.style.display = '';
|
||
|
||
for (var i = 0; i < values.length; i++) {
|
||
var rowChip = root.querySelector(
|
||
'.dropdown-grid-table-box tr[data-key="' + cssEscape(values[i]) + '"]'
|
||
);
|
||
|
||
if (!rowChip)
|
||
continue;
|
||
|
||
var text = rowChip.getAttribute('data-text') || values[i];
|
||
|
||
var chip = document.createElement('span');
|
||
chip.className = 'dropdown-grid-chip';
|
||
|
||
var label = document.createElement('span');
|
||
label.innerHTML = text;
|
||
|
||
var remove = document.createElement('a');
|
||
remove.href = '#';
|
||
remove.className = 'dropdown-grid-chip-remove';
|
||
remove.setAttribute('data-value', values[i]);
|
||
remove.innerHTML = ' ×';
|
||
|
||
chip.appendChild(label);
|
||
chip.appendChild(remove);
|
||
|
||
chips.appendChild(chip);
|
||
}
|
||
};
|
||
|
||
DropdownGrid.restoreInputText = function (root) {
|
||
var hidden = root.querySelector('input[type="hidden"]');
|
||
var input = root.querySelector('[data-dropdown-search="true"]');
|
||
|
||
if (!hidden || !input)
|
||
return;
|
||
|
||
var values = hidden.value ? hidden.value.split(',') : [];
|
||
|
||
if (values.length === 1) {
|
||
var row = root.querySelector(
|
||
'.dropdown-grid-table-box tr[data-key="' + cssEscape(values[0]) + '"]'
|
||
);
|
||
|
||
input.value = row ? row.getAttribute('data-text') || '' : '';
|
||
} else {
|
||
input.value = '';
|
||
}
|
||
};
|
||
|
||
function cssEscape(value) {
|
||
if (window.CSS && CSS.escape)
|
||
return CSS.escape(value);
|
||
|
||
return String(value).replace(/["\\]/g, '\\$&');
|
||
}
|
||
|
||
document.addEventListener('mousedown', function (e) {
|
||
if (activeRoot && activeRoot.contains(e.target))
|
||
return;
|
||
|
||
if (activeClone && activeClone.contains(e.target))
|
||
return;
|
||
|
||
DropdownGrid.hideAll(true);
|
||
});
|
||
|
||
document.addEventListener('keydown', function (e) {
|
||
if (e.key === 'Escape') {
|
||
DropdownGrid.hideAll(true);
|
||
}
|
||
});
|
||
|
||
window.addEventListener('resize', function () {
|
||
if (activeRoot && activeClone)
|
||
DropdownGrid.positionClone(activeRoot);
|
||
});
|
||
|
||
window.addEventListener('scroll', function () {
|
||
if (activeRoot && activeClone)
|
||
DropdownGrid.positionClone(activeRoot);
|
||
}, true);
|
||
|
||
window.DropdownGrid = DropdownGrid;
|
||
|
||
})(window, document); |