From ee059540f79f97abcecfcb04c14e28a24b6c9746 Mon Sep 17 00:00:00 2001 From: Raymond Hill Date: Tue, 20 Oct 2020 05:37:07 -0400 Subject: [PATCH] Cache element picker's optimized candidates for reuse Optimized candidates computed for each depth are now cached for reuse. This reduces the amount of work done when moving the depth slider. --- src/css/epicker-ui.css | 15 +++++--- src/js/epicker-ui.js | 36 ++++++++++++++------ src/js/scriptlets/epicker.js | 1 + src/web_accessible_resources/epicker-ui.html | 1 + 4 files changed, 37 insertions(+), 16 deletions(-) diff --git a/src/css/epicker-ui.css b/src/css/epicker-ui.css index 8cb75747c..53552d94a 100644 --- a/src/css/epicker-ui.css +++ b/src/css/epicker-ui.css @@ -32,10 +32,6 @@ html#ublock0-epicker, #ublock0-epicker #toolbar { cursor: grab; display: flex; - justify-content: space-between; -} -#ublock0-epicker aside.moving #toolbar { - cursor: grabbing; } #ublock0-epicker ul { margin: 0.25em 0 0 0; @@ -67,6 +63,13 @@ html#ublock0-epicker, background-color: var(--button-preferred-surface); color: var(--button-preferred-ink); } +#ublock0-epicker #move { + cursor: grab; + flex-grow: 1; + } +#ublock0-epicker aside.moving #move { + cursor: grabbing; +} #ublock0-epicker section { border: 0; box-sizing: border-box; @@ -117,12 +120,14 @@ html#ublock0-epicker, } .resultsetModifier > span { align-items: flex-end; - border-bottom: 2px solid white; display: flex; height: 100%; pointer-events: none; width: 100%; } +.resultsetModifier > span > span { + margin: 2px 0; + } .resultsetModifier > span > span:nth-of-type(1) { background-color: var(--checkbox-checked-ink); border-inline-end: 1px solid #aaa; diff --git a/src/js/epicker-ui.js b/src/js/epicker-ui.js index 2d1767a0b..a728349a6 100644 --- a/src/js/epicker-ui.js +++ b/src/js/epicker-ui.js @@ -63,7 +63,7 @@ let netFilterCandidates = []; let cosmeticFilterCandidates = []; let computedCandidateSlot = 0; let computedCandidate = ''; -let computedSpecificityCandidates = []; +const computedSpecificityCandidates = new Map(); let needBody = false; /******************************************************************************/ @@ -201,6 +201,16 @@ const candidateFromFilterChoice = function(filterChoice) { /******************************************************************************/ const cosmeticCandidatesFromFilterChoice = function(filterChoice) { + let { slot, filters } = filterChoice; + + renderRange('resultsetDepth', slot, true); + renderRange('resultsetSpecificity'); + + if ( computedSpecificityCandidates.has(slot) ) { + onCandidatesOptimized({ slot }); + return; + } + const specificities = [ 0b0000, // remove hierarchy; remove id, nth-of-type, attribute values 0b0010, // remove hierarchy; remove id, nth-of-type @@ -214,7 +224,6 @@ const cosmeticCandidatesFromFilterChoice = function(filterChoice) { const candidates = []; - let { slot, filters } = filterChoice; let filter = filters[slot]; for ( const specificity of specificities ) { @@ -288,12 +297,10 @@ const cosmeticCandidatesFromFilterChoice = function(filterChoice) { candidates.push(paths); } - renderRange('resultsetDepth', slot, true); - renderRange('resultsetSpecificity'); - vAPI.MessagingConnection.sendTo(epickerConnectionId, { what: 'optimizeCandidates', candidates, + slot, }); }; @@ -302,8 +309,11 @@ const cosmeticCandidatesFromFilterChoice = function(filterChoice) { const onCandidatesOptimized = function(details) { $id('resultsetModifiers').classList.remove('hide'); const i = parseInt($stor('#resultsetSpecificity input').value, 10); - computedSpecificityCandidates = details.candidates; - computedCandidate = computedSpecificityCandidates[i]; + if ( Array.isArray(details.candidates) ) { + computedSpecificityCandidates.set(details.slot, details.candidates); + } + const candidates = computedSpecificityCandidates.get(details.slot); + computedCandidate = candidates[i]; cmEditor.setValue(computedCandidate); cmEditor.clearHistory(); onCandidateChanged(); @@ -521,8 +531,11 @@ const onDepthChanged = function() { const onSpecificityChanged = function() { renderRange('resultsetSpecificity'); if ( rawFilterFromTextarea() !== computedCandidate ) { return; } + const depthInput = $stor('#resultsetDepth input'); + const slot = parseInt(depthInput.max, 10) - parseInt(depthInput.value, 10); const i = parseInt($stor('#resultsetSpecificity input').value, 10); - computedCandidate = computedSpecificityCandidates[i]; + const candidates = computedSpecificityCandidates.get(slot); + computedCandidate = candidates[i]; cmEditor.setValue(computedCandidate); cmEditor.clearHistory(); onCandidateChanged(); @@ -614,7 +627,7 @@ const onStartMoving = (( ) => { }; return function(ev) { - const target = dialog.querySelector('#toolbar'); + const target = dialog.querySelector('#move'); if ( ev.target !== target ) { return; } if ( dialog.classList.contains('moving') ) { return; } isTouch = ev.type.startsWith('touch'); @@ -735,6 +748,7 @@ const showDialog = function(details) { populateCandidates(netFilters, '#netFilters'); populateCandidates(cosmeticFilters, '#cosmeticFilters'); + computedSpecificityCandidates.clear(); const depthInput = $stor('#resultsetDepth input'); depthInput.max = cosmeticFilters.length - 1; @@ -805,8 +819,8 @@ const startPicker = function() { $id('create').addEventListener('click', onCreateClicked); $id('pick').addEventListener('click', onPickClicked); $id('quit').addEventListener('click', onQuitClicked); - $id('toolbar').addEventListener('mousedown', onStartMoving); - $id('toolbar').addEventListener('touchstart', onStartMoving); + $id('move').addEventListener('mousedown', onStartMoving); + $id('move').addEventListener('touchstart', onStartMoving); $id('candidateFilters').addEventListener('click', onCandidateClicked); $stor('#resultsetDepth input').addEventListener('input', onDepthChanged); $stor('#resultsetSpecificity input').addEventListener('input', onSpecificityChanged); diff --git a/src/js/scriptlets/epicker.js b/src/js/scriptlets/epicker.js index c048bf0c5..f0b37e3e6 100644 --- a/src/js/scriptlets/epicker.js +++ b/src/js/scriptlets/epicker.js @@ -847,6 +847,7 @@ const onOptmizeCandidates = function(details) { vAPI.MessagingConnection.sendTo(epickerConnectionId, { what: 'candidatesOptimized', candidates: results.map(a => a.selector), + slot: details.slot, }); }; diff --git a/src/web_accessible_resources/epicker-ui.html b/src/web_accessible_resources/epicker-ui.html index 24ee86595..8ab76e32b 100644 --- a/src/web_accessible_resources/epicker-ui.html +++ b/src/web_accessible_resources/epicker-ui.html @@ -35,6 +35,7 @@
+