diff --git a/frontend/src/utils/hide-columns/hide-columns.js b/frontend/src/utils/hide-columns/hide-columns.js index f8d2cd755..c8599e17e 100644 --- a/frontend/src/utils/hide-columns/hide-columns.js +++ b/frontend/src/utils/hide-columns/hide-columns.js @@ -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) { diff --git a/frontend/src/utils/hide-columns/hide-columns.scss b/frontend/src/utils/hide-columns/hide-columns.scss index 394078c1c..d3df5addc 100644 --- a/frontend/src/utils/hide-columns/hide-columns.scss +++ b/frontend/src/utils/hide-columns/hide-columns.scss @@ -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; } -} diff --git a/stack.yaml.lock b/stack.yaml.lock index 3758cb266..3a7017a21 100644 --- a/stack.yaml.lock +++ b/stack.yaml.lock @@ -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 diff --git a/templates/default-layout.lucius b/templates/default-layout.lucius index 11355082b..0f09cb225 100644 --- a/templates/default-layout.lucius +++ b/templates/default-layout.lucius @@ -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 {