feat(hide-columns): refactor and auto-hide empty columns
This commit is contained in:
parent
d1232ce72d
commit
047c0a5787
@ -73,32 +73,18 @@ export class HideColumns {
|
||||
this._element.parentElement.insertBefore(this._tableHiderContainer, this._element);
|
||||
}
|
||||
|
||||
this._element.querySelectorAll('th').forEach(th => {
|
||||
const storageKey = this.getStorageKey(th);
|
||||
const previouslyHidden = this._storageManager.load(storageKey);
|
||||
this.setupHideButton(th, previouslyHidden);
|
||||
});
|
||||
this._element.querySelectorAll('th').forEach(th => this.setupHideButton(th));
|
||||
}
|
||||
|
||||
hideHiderBehindHeader(hider) {
|
||||
if (!this._tableHiderContainer.contains(hider)) {
|
||||
this._tableHiderContainer.appendChild(hider);
|
||||
}
|
||||
const thR = this.hiderToHeader.get(hider).getBoundingClientRect();
|
||||
const hR = hider.getBoundingClientRect();
|
||||
const pR = this._tableHiderContainer.getBoundingClientRect();
|
||||
hider.style.left = (thR.left + thR.width/2 - hR.width/2 - pR.left) + 'px';
|
||||
hider.style.top = (thR.top - pR.top + thR.height) + 'px';
|
||||
setupHideButton(th) {
|
||||
const preHidden = this.isHiddenColumn(th);
|
||||
|
||||
// remove visible class if necessary
|
||||
hider.classList.remove(TABLE_HIDER_VISIBLE_CLASS);
|
||||
}
|
||||
|
||||
setupHideButton(th, prevHidden) {
|
||||
const hider = document.createElement('span');
|
||||
|
||||
const hiderIcon = document.createElement('i');
|
||||
hiderIcon.classList.add('fas', 'fa-fw');
|
||||
hider.appendChild(hiderIcon);
|
||||
|
||||
const hiderContent = document.createElement('span');
|
||||
hiderContent.classList.add('table-hider__label');
|
||||
hiderContent.innerHTML = th.innerText;
|
||||
@ -106,14 +92,6 @@ export class HideColumns {
|
||||
|
||||
this.addHeaderHider(th, hider);
|
||||
|
||||
hider.addEventListener('click', (event) => {
|
||||
event.preventDefault();
|
||||
this.switchColumnDisplay(th, hider);
|
||||
|
||||
// recompute position for every table hider
|
||||
this._tableHiderContainer.getElementsByClassName(TABLE_HIDER_CLASS).forEach(hider => this.hideHiderBehindHeader(hider));
|
||||
});
|
||||
|
||||
th.addEventListener('mouseover', () => {
|
||||
hider.classList.add(TABLE_HIDER_VISIBLE_CLASS);
|
||||
});
|
||||
@ -123,45 +101,51 @@ export class HideColumns {
|
||||
}
|
||||
});
|
||||
|
||||
hider.addEventListener('click', (event) => {
|
||||
event.preventDefault();
|
||||
this.switchColumnDisplay(th, hider);
|
||||
this._tableHiderContainer.getElementsByClassName(TABLE_HIDER_CLASS).forEach(hider => this.hideHiderBehindHeader(hider));
|
||||
});
|
||||
|
||||
hider.addEventListener('mouseover', () => {
|
||||
hider.classList.add(TABLE_HIDER_VISIBLE_CLASS);
|
||||
const currentlyHidden = this._storageManager.load(this.getStorageKey(th));
|
||||
const currentlyHidden = this.isHiddenColumn(th);
|
||||
this.updateHiderIcon(hider, !currentlyHidden);
|
||||
});
|
||||
hider.addEventListener('mouseout', () => {
|
||||
if (hider.classList.contains(TABLE_HIDER_CLASS)) {
|
||||
hider.classList.remove(TABLE_HIDER_VISIBLE_CLASS);
|
||||
}
|
||||
const currentlyHidden = this._storageManager.load(this.getStorageKey(th));
|
||||
const currentlyHidden = this.isHiddenColumn(th);
|
||||
this.updateHiderIcon(hider, currentlyHidden);
|
||||
});
|
||||
|
||||
this.updateColumnDisplay(th.cellIndex, prevHidden);
|
||||
this.updateHider(hider, prevHidden);
|
||||
// reposition hider on each window resize event
|
||||
window.addEventListener('resize', () => this.repositionHider(hider));
|
||||
|
||||
if (prevHidden) {
|
||||
if (preHidden) {
|
||||
this._tableUtilContainer.appendChild(hider);
|
||||
} else {
|
||||
this.hideHiderBehindHeader(hider);
|
||||
}
|
||||
|
||||
this.updateColumnDisplay(th.cellIndex, preHidden);
|
||||
this.updateHider(hider, preHidden);
|
||||
|
||||
this._tableHiderContainer.children.forEach(hider => this.repositionHider(hider));
|
||||
}
|
||||
|
||||
switchColumnDisplay(th, hider) {
|
||||
const storageKey = this.getStorageKey(th);
|
||||
|
||||
const hidden = !this._storageManager.load(storageKey);
|
||||
const hidden = !this.isHiddenColumn(th);
|
||||
|
||||
this.updateColumnDisplay(th.cellIndex, hidden);
|
||||
this.updateHider(hider, hidden);
|
||||
|
||||
// persist new hidden setting for column
|
||||
this._storageManager.save(storageKey, hidden);
|
||||
this._storageManager.save(this.getStorageKey(th), hidden);
|
||||
}
|
||||
|
||||
updateColumnDisplay(columnIndex, hidden) {
|
||||
let isColumnWithContent = false;
|
||||
|
||||
this._element.getElementsByTagName('tr').forEach(row => {
|
||||
const cell = row.cells[columnIndex];
|
||||
if (cell) {
|
||||
@ -169,46 +153,49 @@ export class HideColumns {
|
||||
cell.classList.add(CELL_HIDDEN_CLASS);
|
||||
} else {
|
||||
cell.classList.remove(CELL_HIDDEN_CLASS);
|
||||
|
||||
// determine if this cell has content
|
||||
if (cell.nodeName === 'TD') {
|
||||
let cellHasContent = false;
|
||||
if (this._elementWrapper.hasAttribute(ASYNC_TABLE_IDENT)) {
|
||||
cell.children.forEach(child => {
|
||||
cellHasContent = cellHasContent || !isEmptyElement(child);
|
||||
});
|
||||
} else {
|
||||
cellHasContent = !isEmptyElement(cell);
|
||||
}
|
||||
isColumnWithContent = isColumnWithContent || cellHasContent;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (!hidden && !isColumnWithContent) {
|
||||
this.updateColumnDisplay(columnIndex, true);
|
||||
}
|
||||
}
|
||||
|
||||
updateHider(hider, hidden) {
|
||||
if (hidden) {
|
||||
this._tableUtilContainer.appendChild(hider);
|
||||
hider.classList.remove(TABLE_HIDER_CLASS);
|
||||
hider.classList.add(TABLE_PILL_CLASS);
|
||||
this._tableUtilContainer.appendChild(hider);
|
||||
} else {
|
||||
this.hideHiderBehindHeader(hider);
|
||||
this._tableHiderContainer.appendChild(hider);
|
||||
hider.classList.remove(TABLE_PILL_CLASS);
|
||||
hider.classList.add(TABLE_HIDER_CLASS);
|
||||
this.hideHiderBehindHeader(hider);
|
||||
}
|
||||
this.updateHiderIcon(hider, hidden);
|
||||
}
|
||||
|
||||
updateHiderIcon(hider, hidden) {
|
||||
const hiderIcon = hider.getElementsByClassName('fas')[0];
|
||||
hiderIcon.classList.remove(hidden ? 'fa-eye' : 'fa-eye-slash');
|
||||
hiderIcon.classList.add(hidden ? 'fa-eye-slash' : 'fa-eye');
|
||||
hider.getElementsByClassName('fas').forEach(hiderIcon => {
|
||||
hiderIcon.classList.remove(hidden ? 'fa-eye' : 'fa-eye-slash');
|
||||
hiderIcon.classList.add(hidden ? 'fa-eye-slash' : 'fa-eye');
|
||||
});
|
||||
}
|
||||
|
||||
hideHiderBehindHeader(hider) {
|
||||
if (!this._tableHiderContainer.contains(hider)) {
|
||||
this._tableHiderContainer.appendChild(hider);
|
||||
}
|
||||
|
||||
this.repositionHider(hider);
|
||||
|
||||
// remove visible class if necessary
|
||||
hider.classList.remove(TABLE_HIDER_VISIBLE_CLASS);
|
||||
}
|
||||
|
||||
repositionHider(hider) {
|
||||
const thR = this.hiderToHeader.get(hider).getBoundingClientRect(),
|
||||
hR = hider.getBoundingClientRect(),
|
||||
pR = this._tableHiderContainer.getBoundingClientRect();
|
||||
|
||||
hider.style.left = (thR.left + thR.width/2 - hR.width/2 - pR.left) + 'px';
|
||||
hider.style.top = (thR.top - pR.top + thR.height) + 'px';
|
||||
}
|
||||
|
||||
getStorageKey(th) {
|
||||
@ -236,6 +223,33 @@ export class HideColumns {
|
||||
return `${handlerIdent}__${tIdent}__${thIdent}`;
|
||||
}
|
||||
|
||||
isEmptyColumn(columnIndex) {
|
||||
for (let row of this._element.getElementsByTagName('TR')) {
|
||||
if (row.children.length <= columnIndex) {
|
||||
throw new Error('Invalid column index for table');
|
||||
}
|
||||
|
||||
const cell = row.children[columnIndex];
|
||||
if (cell.tagName === 'TH')
|
||||
continue;
|
||||
if (this._element.closest(`[${ASYNC_TABLE_IDENT}]`)) {
|
||||
for (let child of cell.children) {
|
||||
if (!isEmptyElement(child))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return isEmptyElement(cell);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
isHiddenColumn(th) {
|
||||
const hidden = this._storageManager.load(this.getStorageKey(th)),
|
||||
emptyColumn = this.isEmptyColumn(th.cellIndex);
|
||||
return hidden === true || hidden === undefined && emptyColumn;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function isEmptyElement(element) {
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
|
||||
transition: transform .2s ease 1s;
|
||||
/* transition: transform .2s ease; */
|
||||
transform: scaleY(0);
|
||||
transform-origin: top;
|
||||
|
||||
@ -24,7 +24,20 @@
|
||||
}
|
||||
|
||||
&.table-hider--visible {
|
||||
transform: scaleY(1);
|
||||
transform: scaleY(.4);
|
||||
transition: none; /* TODO find better way to prevent transition on icons */
|
||||
|
||||
.fas {
|
||||
transform: scaleY(2.5);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
transform: scaleY(1);
|
||||
|
||||
.fas {
|
||||
transform: scaleY(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -66,12 +79,3 @@
|
||||
.hide-columns--hidden-cell {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@keyframes fadeout {
|
||||
0% { opacity: 1; }
|
||||
100% { opacity: 0; }
|
||||
}
|
||||
@keyframes fadein {
|
||||
0% { opacity: 0; }
|
||||
100% { opacity: 1; }
|
||||
}
|
||||
|
||||
@ -138,12 +138,33 @@ packages:
|
||||
original:
|
||||
hackage: HaXml-1.25.5
|
||||
- completed:
|
||||
hackage: esqueleto-3.0.0@sha256:efd84fd11ceaf0ae4e1b0c6236122b1f213c2c6f2f4f58e30f03eddc2ec3f423,5248
|
||||
hackage: persistent-2.10.4@sha256:16c4c0823dd5e16bac4d607895ab0f4febd0626c020e5755ed1a52bf04068148,4738
|
||||
pantry-tree:
|
||||
size: 1127
|
||||
sha256: 74e43834d5cc468acc3cb6e8a81567ebfbb5350a3e07ae01dd7f30d6255274a1
|
||||
size: 2094
|
||||
sha256: b40d1783b539ddbbceaa827bf286d0b3bfcf76ca19e604c9d510b2a64008714e
|
||||
original:
|
||||
hackage: esqueleto-3.0.0
|
||||
hackage: persistent-2.10.4
|
||||
- completed:
|
||||
hackage: persistent-postgresql-2.10.1@sha256:ea53a0f1f4223b4884b5e19511325367879560d2432a02a976aa4da57c5fb760,2871
|
||||
pantry-tree:
|
||||
size: 740
|
||||
sha256: 3cdbc757b1cebb65542fb919369be238b3f120adc45f023084a8b64c214d9675
|
||||
original:
|
||||
hackage: persistent-postgresql-2.10.1
|
||||
- completed:
|
||||
hackage: persistent-template-2.7.3@sha256:ac3e5e8c48e968b927bbf4e97162c52e7e417d69b05efeb1c581d7c682e043d2,2703
|
||||
pantry-tree:
|
||||
size: 560
|
||||
sha256: fdfb2a721eb9c9831d7381d36bc52de0808a008ed3d553b6490080f337249684
|
||||
original:
|
||||
hackage: persistent-template-2.7.3
|
||||
- completed:
|
||||
hackage: esqueleto-3.2.3@sha256:5e1e0a8600e2744127ef4bb5956fa84ae6bc1fc337c7b8726fabb7ca53e2d9b3,5466
|
||||
pantry-tree:
|
||||
size: 1461
|
||||
sha256: f6215274a43addd339f8bc89f1ca0e8fdfb08180b13d779ae8f7e360acc4c473
|
||||
original:
|
||||
hackage: esqueleto-3.2.3
|
||||
- completed:
|
||||
hackage: HaskellNet-SSL-0.3.4.1@sha256:3ca14dd69460a380cf69aed40654fb10c4c03e344632b6a9986568c87feda157,1843
|
||||
pantry-tree:
|
||||
@ -242,6 +263,20 @@ packages:
|
||||
sha256: 9ed161eadfda5b1eb36cfcf077146f7b66db1da69f1041fc720aea287ec021b0
|
||||
original:
|
||||
hackage: generic-lens-1.2.0.0
|
||||
- completed:
|
||||
hackage: prometheus-metrics-ghc-1.0.0@sha256:0f4ecbefa810bd847e66c498ab3387bf21e426525a7c9a94841973c582719ba3,1231
|
||||
pantry-tree:
|
||||
size: 293
|
||||
sha256: 8a6d6ef3235ab980e867f64b712b5d38f1a84c3ac4920f5b4c3b3e63bcdf6ec9
|
||||
original:
|
||||
hackage: prometheus-metrics-ghc-1.0.0
|
||||
- completed:
|
||||
hackage: wai-middleware-prometheus-1.0.0@sha256:1625792914fb2139f005685be8ce519111451cfb854816e430fbf54af46238b4,1314
|
||||
pantry-tree:
|
||||
size: 307
|
||||
sha256: 6d64803c639ed4c7204ea6fab0536b97d3ee16cdecb9b4a883cd8e56d3c61402
|
||||
original:
|
||||
hackage: wai-middleware-prometheus-1.0.0
|
||||
snapshots:
|
||||
- completed:
|
||||
size: 498180
|
||||
|
||||
@ -329,8 +329,12 @@ input[type="button"].btn-info:hover,
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.table:only-child {
|
||||
margin: 0;
|
||||
.table:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.table:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.table--striped {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user