From 3d1b10064692b0441cd54c0205ca385b1bdc8203 Mon Sep 17 00:00:00 2001 From: Raymond Hill Date: Wed, 17 Jan 2024 10:36:23 -0500 Subject: [PATCH] Remember presentation state of "My rules" pane Related feedback: https://old.reddit.com/r/uBlockOrigin/comments/198ohgi/ --- src/js/dyna-rules.js | 135 ++++++++++++++++++++++++++----------------- 1 file changed, 83 insertions(+), 52 deletions(-) diff --git a/src/js/dyna-rules.js b/src/js/dyna-rules.js index ea797427b9293..397b159770379 100644 --- a/src/js/dyna-rules.js +++ b/src/js/dyna-rules.js @@ -69,7 +69,6 @@ const thePanes = { let cleanEditToken = 0; let cleanEditText = ''; -let isCollapsed = false; /******************************************************************************/ @@ -104,7 +103,6 @@ let isCollapsed = false; qs$('.CodeMirror-merge-copybuttons-left'), { attributes: true, attributeFilter: [ 'title' ], subtree: true } ); - } /******************************************************************************/ @@ -142,14 +140,34 @@ const updateOverlay = (( ) => { stream.skipToEnd(); } }; - return function(filter) { - reFilter = typeof filter === 'string' && filter !== '' ? - new RegExp(filter.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'gi') : - undefined; + return function() { + const f = presentationState.filter; + reFilter = typeof f === 'string' && f !== '' + ? new RegExp(f.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'gi') + : undefined; return mode; }; })(); +const toggleOverlay = (( ) => { + let overlay = null; + + return function() { + if ( overlay !== null ) { + mergeView.leftOriginal().removeOverlay(overlay); + mergeView.editor().removeOverlay(overlay); + overlay = null; + } + if ( presentationState.filter !== '' ) { + overlay = updateOverlay(); + mergeView.leftOriginal().addOverlay(overlay); + mergeView.editor().addOverlay(overlay); + } + rulesToDoc(true); + savePresentationState(); + }; +})(); + /******************************************************************************/ // Incrementally update text in a CodeMirror editor for best user experience: @@ -210,7 +228,7 @@ const rulesToDoc = function(clearHistory) { if ( mark.uboEllipsis !== true ) { continue; } mark.clear(); } - if ( isCollapsed ) { + if ( presentationState.isCollapsed ) { for ( let iline = 0, n = edit.lineCount(); iline < n; iline++ ) { if ( edit.getLine(iline) !== '...' ) { continue; } const mark = edit.markText( @@ -353,41 +371,25 @@ function exportUserRulesToFile() { /******************************************************************************/ -const onFilterChanged = (( ) => { +{ let timer; - let overlay = null; - let last = ''; - const process = function() { - timer = undefined; - if ( mergeView.editor().isClean(cleanEditToken) === false ) { return; } - const filter = qs$('#ruleFilter input').value; - if ( filter === last ) { return; } - last = filter; - if ( overlay !== null ) { - mergeView.leftOriginal().removeOverlay(overlay); - mergeView.editor().removeOverlay(overlay); - overlay = null; - } - if ( filter !== '' ) { - overlay = updateOverlay(filter); - mergeView.leftOriginal().addOverlay(overlay); - mergeView.editor().addOverlay(overlay); - } - rulesToDoc(true); - }; - - return function() { + dom.on('#ruleFilter input', 'input', ( ) => { if ( timer !== undefined ) { self.cancelIdleCallback(timer); } - timer = self.requestIdleCallback(process, { timeout: 773 }); - }; -})(); + timer = self.requestIdleCallback(( ) => { + timer = undefined; + if ( mergeView.editor().isClean(cleanEditToken) === false ) { return; } + const filter = qs$('#ruleFilter input').value; + if ( filter === presentationState.filter ) { return; } + presentationState.filter = filter; + toggleOverlay(); + }, { timeout: 773 }); + }); +} /******************************************************************************/ const onPresentationChanged = (( ) => { - let sortType = 1; - const reSwRule = /^([^/]+): ([^/ ]+) ([^ ]+)/; const reRule = /^([^ ]+) ([^/ ]+) ([^ ]+ [^ ]+)/; const reUrlRule = /^([^ ]+) ([^ ]+) ([^ ]+ [^ ]+)/; @@ -431,10 +433,10 @@ const onPresentationChanged = (( ) => { desHn = sortNormalizeHn(hostnameFromURI(match[2])); extra = match[3]; } - if ( sortType === 0 ) { + if ( presentationState.sortType === 0 ) { return { rule, token: `${type} ${srcHn} ${desHn} ${extra}` }; } - if ( sortType === 1 ) { + if ( presentationState.sortType === 1 ) { return { rule, token: `${srcHn} ${type} ${desHn} ${extra}` }; } return { rule, token: `${desHn} ${type} ${srcHn} ${extra}` }; @@ -452,7 +454,7 @@ const onPresentationChanged = (( ) => { }; const collapse = ( ) => { - if ( isCollapsed !== true ) { return; } + if ( presentationState.isCollapsed !== true ) { return; } const diffs = getDiffer().diff_main( thePanes.orig.modified.join('\n'), thePanes.edit.modified.join('\n') @@ -491,23 +493,31 @@ const onPresentationChanged = (( ) => { thePanes.edit.modified = rr; }; - return function(clearHistory) { + dom.on('#ruleFilter select', 'input', ev => { + presentationState.sortType = parseInt(ev.target.value, 10) || 0; + savePresentationState(); + onPresentationChanged(true); + }); + dom.on('#ruleFilter #diffCollapse', 'click', ev => { + presentationState.isCollapsed = dom.cl.toggle(ev.target, 'active'); + savePresentationState(); + onPresentationChanged(true); + }); + + return function onPresentationChanged(clearHistory) { const origPane = thePanes.orig; const editPane = thePanes.edit; origPane.modified = origPane.original.slice(); editPane.modified = editPane.original.slice(); - const select = qs$('#ruleFilter select'); - sortType = parseInt(select.value, 10); - if ( isNaN(sortType) ) { sortType = 1; } { const mode = origPane.doc.getMode(); - mode.sortType = sortType; + mode.sortType = presentationState.sortType; mode.setHostnameToDomainMap(hostnameToDomainMap); mode.setPSL(publicSuffixList); } { const mode = editPane.doc.getMode(); - mode.sortType = sortType; + mode.sortType = presentationState.sortType; mode.setHostnameToDomainMap(hostnameToDomainMap); mode.setPSL(publicSuffixList); } @@ -644,6 +654,35 @@ self.hasUnsavedData = function() { /******************************************************************************/ +const presentationState = { + sortType: 0, + isCollapsed: false, + filter: '', +}; + +const savePresentationState = ( ) => { + vAPI.localStorage.setItem('dynaRulesPresentationState', presentationState); +}; + +vAPI.localStorage.getItemAsync('dynaRulesPresentationState').then(details => { + if ( details instanceof Object === false ) { return; } + if ( typeof details.sortType === 'number' ) { + presentationState.sortType = details.sortType; + qs$('#ruleFilter select').value = `${details.sortType}`; + } + if ( typeof details.isCollapsed === 'boolean' ) { + presentationState.isCollapsed = details.isCollapsed; + dom.cl.toggle('#ruleFilter #diffCollapse', 'active', details.isCollapsed); + } + if ( typeof details.filter === 'string' ) { + presentationState.filter = details.filter; + qs$('#ruleFilter input').value = details.filter; + toggleOverlay(); + } +}); + +/******************************************************************************/ + vAPI.messaging.send('dashboard', { what: 'getRules', }).then(details => { @@ -660,14 +699,6 @@ dom.on('#exportButton', 'click', exportUserRulesToFile); dom.on('#revertButton', 'click', revertAllHandler); dom.on('#commitButton', 'click', commitAllHandler); dom.on('#editSaveButton', 'click', editSaveHandler); -dom.on('#ruleFilter input', 'input', onFilterChanged); -dom.on('#ruleFilter select', 'input', ( ) => { - onPresentationChanged(true); -}); -dom.on('#ruleFilter #diffCollapse', 'click', ev => { - isCollapsed = dom.cl.toggle(ev.target, 'active'); - onPresentationChanged(true); -}); // https://groups.google.com/forum/#!topic/codemirror/UQkTrt078Vs mergeView.editor().on('updateDiff', ( ) => {