feat(hide-columns): refactor and auto-hide empty columns

This commit is contained in:
Sarah Vaupel 2019-12-02 18:19:50 +01:00 committed by Gregor Kleen
parent d1232ce72d
commit 047c0a5787
4 changed files with 135 additions and 78 deletions

View File

@ -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) {

View File

@ -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; }
}

View File

@ -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

View File

@ -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 {