Initial commit
This commit is contained in:
559
SIG.Web/Scripts/DropDownGrid.js
Normal file
559
SIG.Web/Scripts/DropDownGrid.js
Normal file
@@ -0,0 +1,559 @@
|
||||
(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);
|
||||
Reference in New Issue
Block a user