From eea4b654303074dd37cc7d64e48cc8d8700ba715 Mon Sep 17 00:00:00 2001 From: Adam Argyle Date: Sun, 1 Sep 2019 21:59:50 -0700 Subject: [PATCH 01/10] non thrashing, async mutate elements with clientRect --- app/utilities/styles.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/app/utilities/styles.js b/app/utilities/styles.js index fba4dc29..b6b60bb0 100644 --- a/app/utilities/styles.js +++ b/app/utilities/styles.js @@ -58,6 +58,24 @@ export const getStyles = el => { }) } +export const setVisbox = els => { + return new Promise(resolve => { + const observer = new IntersectionObserver(entries => { + observer.disconnect() + + for (const entry of entries) { + const el = els.find(el => el === entry.target) + el['vis-box'] = entry.boundingClientRect + } + + resolve(els) + }) + + for (const el of els) + observer.observe(el) + }) +} + export const getComputedBackgroundColor = el => { let background = getStyle(el, 'background-color') From 822aab24d66b1c934761935aff4ca5a21370721e Mon Sep 17 00:00:00 2001 From: Adam Argyle Date: Sun, 1 Sep 2019 22:00:01 -0700 Subject: [PATCH 02/10] guides use new pattern --- app/features/guides.js | 9 +++++---- app/features/selectable.js | 9 ++++++--- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/app/features/guides.js b/app/features/guides.js index 4431d9cf..8c1a8e03 100644 --- a/app/features/guides.js +++ b/app/features/guides.js @@ -1,5 +1,5 @@ import $ from 'blingblingjs' -import { isOffBounds, deepElementFromPoint } from '../utilities/' +import { isOffBounds, deepElementFromPoint, setVisbox } from '../utilities/' import { clearMeasurements, takeMeasurementOwnership } from './measurements' const state = { @@ -30,9 +30,10 @@ export function Guides(visbug) { } } -const on_hover = e => { +const on_hover = async e => { const target = deepElementFromPoint(e.clientX, e.clientY) if (isOffBounds(target)) return + await setVisbox([target]) showGridlines(target) } @@ -91,11 +92,11 @@ const on_hoverout = () => const showGridlines = node => { if (state.gridlines) { state.gridlines.style.display = null - state.gridlines.update = node.getBoundingClientRect() + state.gridlines.update = node['vis-box'] } else { state.gridlines = document.createElement('visbug-gridlines') - state.gridlines.position = node.getBoundingClientRect() + state.gridlines.position = node['vis-box'] document.body.appendChild(state.gridlines) } diff --git a/app/features/selectable.js b/app/features/selectable.js index b005ec67..b88dedac 100644 --- a/app/features/selectable.js +++ b/app/features/selectable.js @@ -16,7 +16,7 @@ import { metaKey, htmlStringToDom, createClassname, camelToDash, isOffBounds, getStyles, deepElementFromPoint, getShadowValues, isSelectorValid, findNearestChildElement, findNearestParentElement, - getTextShadowValues + getTextShadowValues, setVisbox } from '../utilities/' export function Selectable(visbug) { @@ -376,7 +376,7 @@ export function Selectable(visbug) { }) } - const on_hover = e => { + const on_hover = async e => { const $target = deepElementFromPoint(e.clientX, e.clientY) const tool = visbug.activeTool @@ -385,6 +385,8 @@ export function Selectable(visbug) { return clearHover() } + await setVisbox([$target]) + overlayHoverUI({ el: $target, // no_hover: tool === 'guides', @@ -409,7 +411,7 @@ export function Selectable(visbug) { } } - const select = el => { + const select = async el => { const id = handles.length const tool = visbug.activeTool @@ -419,6 +421,7 @@ export function Selectable(visbug) { clearHover() selected.unshift(el) + await setVisbox(selected) tellWatchers() overlayMetaUI({ From 352635621a3b1e6ee28f383ec26fa57dc7845b47 Mon Sep 17 00:00:00 2001 From: Adam Argyle Date: Sun, 1 Sep 2019 22:40:54 -0700 Subject: [PATCH 03/10] convert everything --- app/components/selection/handles.element.js | 2 +- app/components/selection/label.element.js | 2 +- app/features/imageswap.js | 2 +- app/features/margin.js | 2 +- app/features/measurements.js | 4 ++-- app/features/metatip.js | 2 +- app/features/padding.js | 2 +- app/features/selectable.js | 8 ++++---- 8 files changed, 12 insertions(+), 12 deletions(-) diff --git a/app/components/selection/handles.element.js b/app/components/selection/handles.element.js index eefa74f1..212ea4de 100644 --- a/app/components/selection/handles.element.js +++ b/app/components/selection/handles.element.js @@ -33,7 +33,7 @@ export class Handles extends HTMLElement { } set position({el, node_label_id}) { - this.$shadow.innerHTML = this.render(el.getBoundingClientRect(), node_label_id) + this.$shadow.innerHTML = this.render(el['vis-box'], node_label_id) if (this._backdrop) { this.backdrop = { diff --git a/app/components/selection/label.element.js b/app/components/selection/label.element.js index 31fdc6ed..51e80c74 100644 --- a/app/components/selection/label.element.js +++ b/app/components/selection/label.element.js @@ -28,7 +28,7 @@ export class Label extends HTMLElement { this.position = { node_label_id, - boundingRect: source_el.getBoundingClientRect(), + boundingRect: source_el['vis-box'], } }) } diff --git a/app/features/imageswap.js b/app/features/imageswap.js index 5fd1e099..ce171c01 100644 --- a/app/features/imageswap.js +++ b/app/features/imageswap.js @@ -178,7 +178,7 @@ const getPictureSourcesToUpdate = img => const showOverlay = (node, i) => { if (!state.watching) return - const rect = node.getBoundingClientRect() + const rect = node['vis-box'] const overlay = overlays[i] if (overlay) { diff --git a/app/features/margin.js b/app/features/margin.js index d52b5e2d..1f4ca44a 100644 --- a/app/features/margin.js +++ b/app/features/margin.js @@ -89,7 +89,7 @@ function removeBackgrounds(els) { } export function createMarginVisual(el, hover = false) { - const bounds = el.getBoundingClientRect() + const bounds = el['vis-box'] const styleOM = el.computedStyleMap() const calculatedStyle = getStyle(el, 'margin') const boxdisplay = document.createElement('visbug-boxmodel') diff --git a/app/features/measurements.js b/app/features/measurements.js index 1c39e4c8..1845d7eb 100644 --- a/app/features/measurements.js +++ b/app/features/measurements.js @@ -11,8 +11,8 @@ export function createMeasurements({$anchor, $target}) { if (state.distances.length) clearMeasurements() - const anchorBounds = $anchor.getBoundingClientRect() - const targetBounds = $target.getBoundingClientRect() + const anchorBounds = $anchor['vis-box'] + const targetBounds = $target['vis-box'] const measurements = [] diff --git a/app/features/metatip.js b/app/features/metatip.js index 758f75b6..be753dad 100644 --- a/app/features/metatip.js +++ b/app/features/metatip.js @@ -130,7 +130,7 @@ export function removeAll() { } const render = (el, tip = document.createElement('visbug-metatip')) => { - const { width, height } = el.getBoundingClientRect() + const { width, height } = el['vis-box'] const colormode = $('vis-bug')[0].colorMode const styles = getStyles(el) diff --git a/app/features/padding.js b/app/features/padding.js index 2c5900b6..ab6d9b53 100644 --- a/app/features/padding.js +++ b/app/features/padding.js @@ -89,7 +89,7 @@ function removeBackgrounds(els) { } export function createPaddingVisual(el, hover = false) { - const bounds = el.getBoundingClientRect() + const bounds = el['vis-box'] const styleOM = el.computedStyleMap() const calculatedStyle = getStyle(el, 'padding') const boxdisplay = document.createElement('visbug-boxmodel') diff --git a/app/features/selectable.js b/app/features/selectable.js index b4b71f58..a07860a2 100644 --- a/app/features/selectable.js +++ b/app/features/selectable.js @@ -419,6 +419,7 @@ export function Selectable(visbug) { el.setAttribute('data-label-id', id) clearHover() + await setVisbox([el]) overlayMetaUI({ el, @@ -426,7 +427,6 @@ export function Selectable(visbug) { no_label: tool !== 'inspector' && tool !== 'accessibility', }) - await setVisbox([el]) selected.unshift(el) tellWatchers() } @@ -578,7 +578,7 @@ export function Selectable(visbug) { } const setLabel = (el, label) => - label.update = el.getBoundingClientRect() + label.update = el['vis-box'] const createLabel = ({el, id, template}) => { if (!labels[id]) { @@ -586,7 +586,7 @@ export function Selectable(visbug) { label.text = template label.position = { - boundingRect: el.getBoundingClientRect(), + boundingRect: el['vis-box'], node_label_id: id, } @@ -654,7 +654,7 @@ export function Selectable(visbug) { hover_state.label.text = text hover_state.label.position = { - boundingRect: el.getBoundingClientRect(), + boundingRect: el['vis-box'], node_label_id: 'hover', } From c6b9a2f0b0dc6b7cc8c9451ac1cbd65700c71415 Mon Sep 17 00:00:00 2001 From: Adam Argyle Date: Wed, 4 Sep 2019 21:06:12 -0700 Subject: [PATCH 04/10] select can take an array now and perform bulk operations on a target set --- app/features/selectable.js | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/app/features/selectable.js b/app/features/selectable.js index a07860a2..b5bbf024 100644 --- a/app/features/selectable.js +++ b/app/features/selectable.js @@ -411,23 +411,29 @@ export function Selectable(visbug) { } } - const select = async el => { - const id = handles.length - const tool = visbug.activeTool - - el.setAttribute('data-selected', true) - el.setAttribute('data-label-id', id) + const select = async els => { + els = typeof els === 'object' + ? [els] + : els clearHover() - await setVisbox([el]) + await setVisbox(els) - overlayMetaUI({ - el, - id, - no_label: tool !== 'inspector' && tool !== 'accessibility', + els.forEach(el => { + const id = handles.length + const tool = visbug.activeTool + + el.setAttribute('data-selected', true) + el.setAttribute('data-label-id', id) + + overlayMetaUI({ + el, + id, + no_label: tool !== 'inspector' && tool !== 'accessibility', + }) }) - selected.unshift(el) + selected = [...selected, ...els] tellWatchers() } From 503825a29d461b03f17b7a66bf7791ca4eb6503f Mon Sep 17 00:00:00 2001 From: Adam Argyle Date: Wed, 4 Sep 2019 21:53:31 -0700 Subject: [PATCH 05/10] send select the matches collection --- app/features/search.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/app/features/search.js b/app/features/search.js index c60b964a..674d08db 100644 --- a/app/features/search.js +++ b/app/features/search.js @@ -92,10 +92,8 @@ export function queryPage(query, fn) { let matches = querySelectorAllDeep(query + notList) if (!matches.length) matches = querySelectorAllDeep(query) if (matches.length) { - matches.forEach(el => - fn - ? fn(el) - : SelectorEngine.select(el)) + SelectorEngine.select(matches) + if (fn) matches.forEach(el => fn(el)) } } catch (err) {} From 9536eabcd6cad5f290c1dceff9b369c82b5db575 Mon Sep 17 00:00:00 2001 From: Adam Argyle Date: Wed, 4 Sep 2019 21:55:06 -0700 Subject: [PATCH 06/10] select now performs single incision for appending gui --- app/features/selectable.js | 39 ++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/app/features/selectable.js b/app/features/selectable.js index b5bbf024..016b11e6 100644 --- a/app/features/selectable.js +++ b/app/features/selectable.js @@ -412,26 +412,34 @@ export function Selectable(visbug) { } const select = async els => { - els = typeof els === 'object' - ? [els] - : els + if (!els.length) + els = [els] clearHover() await setVisbox(els) - els.forEach(el => { + // for each item to be selected + // set visbug attributes and create gui overlay nodes + // reduce those nodes into 1 root fragment for one DOM append / incision + const gui = els.reduce((gui, el) => { const id = handles.length const tool = visbug.activeTool el.setAttribute('data-selected', true) el.setAttribute('data-label-id', id) - overlayMetaUI({ + const nodes = overlayMetaUI({ el, id, no_label: tool !== 'inspector' && tool !== 'accessibility', }) - }) + + nodes.forEach(node => gui.append(node)) + + return gui + }, document.createDocumentFragment()) + + document.body.append(gui) selected = [...selected, ...els] tellWatchers() @@ -552,8 +560,8 @@ export function Selectable(visbug) { } const overlayMetaUI = ({el, id, no_label = true}) => { - let handle = createHandle({el, id}) - let label = no_label + const handle = createHandle({el, id}) + const label = no_label ? null : createLabel({ el, @@ -571,8 +579,8 @@ export function Selectable(visbug) { ` }) - let observer = createObserver(el, {handle,label}) - let parentObserver = createObserver(el, {handle,label}) + const observer = createObserver(el, {handle,label}) + const parentObserver = createObserver(el, {handle,label}) observer.observe(el, { attributes: true }) parentObserver.observe(el.parentNode, { childList:true, subtree:true }) @@ -581,6 +589,8 @@ export function Selectable(visbug) { observer.disconnect() parentObserver.disconnect() }) + + return [handle, label] } const setLabel = (el, label) => @@ -596,8 +606,6 @@ export function Selectable(visbug) { node_label_id: id, } - document.body.appendChild(label) - $(label).on('query', ({detail}) => { if (!detail.text) return this.query_text = detail.text @@ -629,10 +637,8 @@ export function Selectable(visbug) { const handle = document.createElement('visbug-handles') handle.position = { el, node_label_id: id } - - document.body.appendChild(handle) - handles[handles.length] = handle + return handle } } @@ -643,7 +649,6 @@ export function Selectable(visbug) { hover_state.element.remove() hover_state.element = document.createElement('visbug-hover') - document.body.appendChild(hover_state.element) hover_state.element.position = {el} return hover_state.element @@ -656,7 +661,6 @@ export function Selectable(visbug) { hover_state.label.remove() hover_state.label = document.createElement('visbug-label') - document.body.appendChild(hover_state.label) hover_state.label.text = text hover_state.label.position = { @@ -666,7 +670,6 @@ export function Selectable(visbug) { hover_state.label.style.setProperty(`--label-bg`, `hsl(267, 100%, 58%)`) - return hover_state.label } } From d4d04d5374b8e8bc941b9b5e4e147a9b8d2c99e6 Mon Sep 17 00:00:00 2001 From: Adam Argyle Date: Wed, 4 Sep 2019 22:06:18 -0700 Subject: [PATCH 07/10] fixes hover to single body incision --- app/features/selectable.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/features/selectable.js b/app/features/selectable.js index 016b11e6..106b15e3 100644 --- a/app/features/selectable.js +++ b/app/features/selectable.js @@ -387,11 +387,17 @@ export function Selectable(visbug) { await setVisbox([$target]) + const gui = document.createDocumentFragment() overlayHoverUI({ el: $target, // no_hover: tool === 'guides', no_label: tool !== 'guides', }) + + gui.append(hover_state.element) + gui.append(hover_state.label) + + document.body.append(gui) if (tool === 'guides' && selected.length >= 1 && !selected.includes($target)) { $target.setAttribute('data-measuring', true) From 06124c40fe6c1f77b90e5f77adf78303a2d77f6f Mon Sep 17 00:00:00 2001 From: Adam Argyle Date: Wed, 4 Sep 2019 22:06:37 -0700 Subject: [PATCH 08/10] meta uses async setVisbox --- app/features/metatip.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/features/metatip.js b/app/features/metatip.js index be753dad..156998b6 100644 --- a/app/features/metatip.js +++ b/app/features/metatip.js @@ -4,7 +4,7 @@ import { TinyColor } from '@ctrl/tinycolor' import { queryPage } from './search' import { getStyles, camelToDash, isOffBounds, deepElementFromPoint, getShadowValues, - getTextShadowValues + getTextShadowValues, setVisbox } from '../utilities/' const state = { @@ -35,7 +35,7 @@ export function MetaTip({select}) { } } -const mouseMove = e => { +const mouseMove = async e => { const target = deepElementFromPoint(e.clientX, e.clientY) if (isOffBounds(target) || target.nodeName === 'VISBUG-METATIP' || target.hasAttribute('data-metatip')) { // aka: mouse out @@ -50,7 +50,7 @@ const mouseMove = e => { } toggleTargetCursor(e.altKey, target) - + await setVisbox([target]) showTip(target, e) } From e1432505f920a5c3a012da9a748b224b06052bb6 Mon Sep 17 00:00:00 2001 From: Adam Argyle Date: Wed, 4 Sep 2019 22:19:47 -0700 Subject: [PATCH 09/10] fixes label query regression --- app/features/search.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/app/features/search.js b/app/features/search.js index 674d08db..1c4bcce5 100644 --- a/app/features/search.js +++ b/app/features/search.js @@ -91,9 +91,12 @@ export function queryPage(query, fn) { try { let matches = querySelectorAllDeep(query + notList) if (!matches.length) matches = querySelectorAllDeep(query) - if (matches.length) { - SelectorEngine.select(matches) - if (fn) matches.forEach(el => fn(el)) + else if (matches.length) { + if (fn) + matches.forEach(el => + fn(el)) + else + SelectorEngine.select(matches) } } catch (err) {} From 466c6f6854d8d6a8a7b5df4e4dd9fc404b809782 Mon Sep 17 00:00:00 2001 From: Adam Argyle Date: Wed, 4 Sep 2019 22:42:13 -0700 Subject: [PATCH 10/10] fixes label psuedo query and unquery --- app/features/metatip.js | 20 +++++++++----------- app/features/search.js | 8 +++----- app/features/selectable.js | 14 +++++++------- 3 files changed, 19 insertions(+), 23 deletions(-) diff --git a/app/features/metatip.js b/app/features/metatip.js index 156998b6..380b5ef9 100644 --- a/app/features/metatip.js +++ b/app/features/metatip.js @@ -238,19 +238,17 @@ const togglePinned = e => { const linkQueryClicked = ({detail:{ text, activator }}) => { if (!text) return - queryPage('[data-pseudo-select]', el => - el.removeAttribute('data-pseudo-select')) + unPseudoQuery() - queryPage(text + ':not([data-selected])', el => + queryPage(text + ':not([data-selected])', els => activator === 'mouseenter' - ? el.setAttribute('data-pseudo-select', true) - : services.selectors.select(el)) + ? $(els).attr('data-pseudo-select', true) + : services.selectors.select(els)) } -const linkQueryHoverOut = e => { - queryPage('[data-pseudo-select]', el => - el.removeAttribute('data-pseudo-select')) -} +const unPseudoQuery = _ => + queryPage('[data-pseudo-select]', els => + $(els).attr('data-pseudo-select', null)) const toggleTargetCursor = (key, target) => key @@ -259,13 +257,13 @@ const toggleTargetCursor = (key, target) => const observe = ({tip, target}) => { $(tip).on('query', linkQueryClicked) - $(tip).on('unquery', linkQueryHoverOut) + $(tip).on('unquery', unPseudoQuery) $(target).on('DOMNodeRemoved', handleBlur) } const unobserve = ({tip, target}) => { $(tip).off('query', linkQueryClicked) - $(tip).off('unquery', linkQueryHoverOut) + $(tip).off('unquery', unPseudoQuery) $(target).off('DOMNodeRemoved', handleBlur) } diff --git a/app/features/search.js b/app/features/search.js index 1c4bcce5..96633b0a 100644 --- a/app/features/search.js +++ b/app/features/search.js @@ -91,12 +91,10 @@ export function queryPage(query, fn) { try { let matches = querySelectorAllDeep(query + notList) if (!matches.length) matches = querySelectorAllDeep(query) + else if (matches.length) { - if (fn) - matches.forEach(el => - fn(el)) - else - SelectorEngine.select(matches) + if (fn) fn(matches) + else SelectorEngine.select(matches) } } catch (err) {} diff --git a/app/features/selectable.js b/app/features/selectable.js index 106b15e3..48681400 100644 --- a/app/features/selectable.js +++ b/app/features/selectable.js @@ -616,20 +616,20 @@ export function Selectable(visbug) { if (!detail.text) return this.query_text = detail.text - queryPage('[data-pseudo-select]', el => - el.removeAttribute('data-pseudo-select')) + queryPage('[data-pseudo-select]', els => + $(els).attr('data-pseudo-select', null)) - queryPage(this.query_text + ':not([data-selected])', el => + queryPage(this.query_text + ':not([data-selected])', els => detail.activator === 'mouseenter' - ? el.setAttribute('data-pseudo-select', true) - : select(el)) + ? $(els).attr('data-pseudo-select', true) + : select(els)) }) $(label).on('mouseleave', e => { e.preventDefault() e.stopPropagation() - queryPage('[data-pseudo-select]', el => - el.removeAttribute('data-pseudo-select')) + queryPage('[data-pseudo-select]', els => + $(els).attr('data-pseudo-select', null)) }) labels[labels.length] = label