mirror of
https://github.com/gorhill/uBlock.git
synced 2024-11-10 09:07:54 +01:00
Count hidden elements on-demand only in popup panel
Related issue: - https://github.com/uBlockOrigin/uBlock-issues/issues/756 The badge value for the no-cosmetic-filtering switch will be evaluated on-demand only, when the user hover over the switch with the mouse cursor. For touch screen displays, a tap on the switch will cause the badge to be rendered if not already done, otherwise this will toggle the switch as usual.
This commit is contained in:
parent
7c0294bd5f
commit
c090d2fde4
4 changed files with 171 additions and 91 deletions
|
@ -366,39 +366,34 @@ const popupDataFromRequest = async function(request) {
|
|||
return popupDataFromTabId(tabId, tabTitle);
|
||||
};
|
||||
|
||||
const getDOMStats = async function(tabId) {
|
||||
const getElementCount = async function(tabId, what) {
|
||||
const results = await vAPI.tabs.executeScript(tabId, {
|
||||
allFrames: true,
|
||||
file: '/js/scriptlets/dom-survey.js',
|
||||
file: `/js/scriptlets/dom-survey-${what}.js`,
|
||||
runAt: 'document_end',
|
||||
});
|
||||
|
||||
let elementCount = 0;
|
||||
let scriptCount = 0;
|
||||
results.forEach(result => {
|
||||
if ( result instanceof Object === false ) { return; }
|
||||
if ( result.hiddenElementCount > 0 ) {
|
||||
elementCount += result.hiddenElementCount;
|
||||
}
|
||||
if ( result.externalScriptCount > 0 ) {
|
||||
scriptCount += result.externalScriptCount;
|
||||
}
|
||||
if ( result.inlineScriptCount > 0 ) {
|
||||
scriptCount += 1;
|
||||
}
|
||||
let total = 0;
|
||||
results.forEach(count => {
|
||||
if ( typeof count !== 'number' ) { return; }
|
||||
total += count;
|
||||
});
|
||||
|
||||
return { elementCount, scriptCount };
|
||||
return total;
|
||||
};
|
||||
|
||||
const onMessage = function(request, sender, callback) {
|
||||
let pageStore;
|
||||
|
||||
// Async
|
||||
switch ( request.what ) {
|
||||
case 'getPopupLazyData':
|
||||
getDOMStats(request.tabId).then(results => {
|
||||
callback(results);
|
||||
case 'getHiddenElementCount':
|
||||
getElementCount(request.tabId, 'elements').then(count => {
|
||||
callback(count);
|
||||
});
|
||||
return;
|
||||
|
||||
case 'getScriptCount':
|
||||
getElementCount(request.tabId, 'scripts').then(count => {
|
||||
callback(count);
|
||||
});
|
||||
return;
|
||||
|
||||
|
@ -414,6 +409,7 @@ const onMessage = function(request, sender, callback) {
|
|||
|
||||
// Sync
|
||||
let response;
|
||||
let pageStore;
|
||||
|
||||
switch ( request.what ) {
|
||||
case 'hasPopupContentChanged':
|
||||
|
|
|
@ -668,24 +668,48 @@ let renderOnce = function() {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
const renderPopupLazy = async function() {
|
||||
const result = await messaging.send('popupPanel', {
|
||||
what: 'getPopupLazyData',
|
||||
tabId: popupData.tabId,
|
||||
});
|
||||
if ( result instanceof Object === false ) { return; }
|
||||
const renderPopupLazy = (( ) => {
|
||||
let mustRenderCosmeticFilteringBadge = true;
|
||||
|
||||
let count = result.elementCount || 0;
|
||||
uDom.nodeFromSelector('#no-cosmetic-filtering > span.fa-icon-badge')
|
||||
.textContent = count !== 0
|
||||
? Math.min(count, 99).toLocaleString()
|
||||
: '';
|
||||
count = result.scriptCount || 0;
|
||||
uDom.nodeFromSelector('#no-scripting > span.fa-icon-badge')
|
||||
.textContent = count !== 0
|
||||
? Math.min(count, 99).toLocaleString()
|
||||
: '';
|
||||
};
|
||||
// https://github.com/uBlockOrigin/uBlock-issues/issues/756
|
||||
// Launch potentially expensive hidden elements-counting scriptlet on
|
||||
// demand only.
|
||||
{
|
||||
const sw = uDom.nodeFromId('no-cosmetic-filtering');
|
||||
const badge = sw.querySelector(':scope > span.fa-icon-badge');
|
||||
badge.textContent = '\u22EF';
|
||||
|
||||
const render = ( ) => {
|
||||
if ( mustRenderCosmeticFilteringBadge === false ) { return; }
|
||||
mustRenderCosmeticFilteringBadge = false;
|
||||
if ( sw.classList.contains('hnSwitchBusy') ) { return; }
|
||||
sw.classList.add('hnSwitchBusy');
|
||||
messaging.send('popupPanel', {
|
||||
what: 'getHiddenElementCount',
|
||||
tabId: popupData.tabId,
|
||||
}).then(count => {
|
||||
badge.textContent = (count || 0) !== 0
|
||||
? Math.min(count, 99).toLocaleString()
|
||||
: '';
|
||||
sw.classList.remove('hnSwitchBusy');
|
||||
});
|
||||
};
|
||||
|
||||
sw.addEventListener('mouseenter', render, { passive: true });
|
||||
}
|
||||
|
||||
return async function() {
|
||||
const count = await messaging.send('popupPanel', {
|
||||
what: 'getScriptCount',
|
||||
tabId: popupData.tabId,
|
||||
});
|
||||
uDom.nodeFromSelector('#no-scripting > span.fa-icon-badge')
|
||||
.textContent = (count || 0) !== 0
|
||||
? Math.min(count, 99).toLocaleString()
|
||||
: '';
|
||||
mustRenderCosmeticFilteringBadge = true;
|
||||
};
|
||||
})();
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
|
@ -954,6 +978,13 @@ const toggleHostnameSwitch = async function(ev) {
|
|||
const target = ev.currentTarget;
|
||||
const switchName = target.getAttribute('id');
|
||||
if ( !switchName ) { return; }
|
||||
// For touch displays, process click only if the switch is not "busy".
|
||||
if (
|
||||
vAPI.webextFlavor.soup.has('mobile') &&
|
||||
target.classList.contains('hnSwitchBusy')
|
||||
) {
|
||||
return;
|
||||
}
|
||||
target.classList.toggle('on');
|
||||
renderTooltips('#' + switchName);
|
||||
|
||||
|
|
96
src/js/scriptlets/dom-survey-elements.js
Normal file
96
src/js/scriptlets/dom-survey-elements.js
Normal file
|
@ -0,0 +1,96 @@
|
|||
/*******************************************************************************
|
||||
|
||||
uBlock Origin - a browser extension to block requests.
|
||||
Copyright (C) 2015-present Raymond Hill
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
|
||||
Home: https://github.com/gorhill/uBlock
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// https://github.com/uBlockOrigin/uBlock-issues/issues/756
|
||||
// Keep in mind CPU usage with large DOM and/or filterset.
|
||||
|
||||
(( ) => {
|
||||
if ( typeof vAPI !== 'object' ) { return; }
|
||||
|
||||
const t0 = Date.now();
|
||||
|
||||
if ( vAPI.domSurveyElements instanceof Object === false ) {
|
||||
vAPI.domSurveyElements = {
|
||||
busy: false,
|
||||
hiddenElementCount: -1,
|
||||
surveyTime: t0,
|
||||
};
|
||||
}
|
||||
const surveyResults = vAPI.domSurveyElements;
|
||||
|
||||
if ( surveyResults.busy ) { return; }
|
||||
surveyResults.busy = true;
|
||||
|
||||
if ( surveyResults.surveyTime < vAPI.domMutationTime ) {
|
||||
surveyResults.hiddenElementCount = -1;
|
||||
}
|
||||
surveyResults.surveyTime = t0;
|
||||
|
||||
if ( surveyResults.hiddenElementCount === -1 ) {
|
||||
surveyResults.hiddenElementCount = (( ) => {
|
||||
if ( vAPI.domFilterer instanceof Object === false ) { return 0; }
|
||||
const details = vAPI.domFilterer.getAllSelectors_(true);
|
||||
if ( Array.isArray(details.declarative) === false ) { return 0; }
|
||||
const selectors = details.declarative.map(entry => entry[0]);
|
||||
const simple = [], complex = [];
|
||||
for ( const selectorStr of selectors ) {
|
||||
for ( const selector of selectorStr.split(',\n') ) {
|
||||
if ( /[ +>~]/.test(selector) ) {
|
||||
complex.push(selector);
|
||||
} else {
|
||||
simple.push(selector);
|
||||
}
|
||||
}
|
||||
}
|
||||
const simpleStr = simple.join(',\n');
|
||||
const complexStr = complex.join(',\n');
|
||||
const nodeIter = document.createNodeIterator(
|
||||
document.body,
|
||||
NodeFilter.SHOW_ELEMENT
|
||||
);
|
||||
const matched = new Set();
|
||||
for (;;) {
|
||||
const node = nodeIter.nextNode();
|
||||
if ( node === null ) { break; }
|
||||
if ( node.offsetParent !== null ) { continue; }
|
||||
if (
|
||||
node.matches(simpleStr) === false &&
|
||||
node.closest(complexStr) !== node
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
matched.add(node);
|
||||
if ( matched.size === 99 ) { break; }
|
||||
}
|
||||
return matched.size;
|
||||
})();
|
||||
}
|
||||
|
||||
surveyResults.busy = false;
|
||||
|
||||
// IMPORTANT: This is returned to the injector, so this MUST be
|
||||
// the last statement.
|
||||
return surveyResults.hiddenElementCount;
|
||||
})();
|
|
@ -23,31 +23,28 @@
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
// https://github.com/uBlockOrigin/uBlock-issues/issues/756
|
||||
// Keep in mind CPU usage witj large DOM and/or filterset.
|
||||
// Scriptlets to count the number of script tags in a document.
|
||||
|
||||
(( ) => {
|
||||
if ( typeof vAPI !== 'object' ) { return; }
|
||||
|
||||
const t0 = Date.now();
|
||||
const tMax = t0 + 60;
|
||||
const tMax = t0 + 50;
|
||||
|
||||
if ( vAPI.domSurveyResults instanceof Object === false ) {
|
||||
vAPI.domSurveyResults = {
|
||||
if ( vAPI.domSurveyScripts instanceof Object === false ) {
|
||||
vAPI.domSurveyScripts = {
|
||||
busy: false,
|
||||
hiddenElementCount: -1,
|
||||
inlineScriptCount: -1,
|
||||
externalScriptCount: -1,
|
||||
surveyTime: t0,
|
||||
};
|
||||
}
|
||||
const surveyResults = vAPI.domSurveyResults;
|
||||
const surveyResults = vAPI.domSurveyScripts;
|
||||
|
||||
if ( surveyResults.busy ) { return; }
|
||||
surveyResults.busy = true;
|
||||
|
||||
if ( surveyResults.surveyTime < vAPI.domMutationTime ) {
|
||||
surveyResults.hiddenElementCount = -1;
|
||||
surveyResults.inlineScriptCount = -1;
|
||||
surveyResults.externalScriptCount = -1;
|
||||
}
|
||||
|
@ -71,46 +68,6 @@
|
|||
surveyResults.externalScriptCount = externalScriptCount;
|
||||
}
|
||||
|
||||
if ( surveyResults.hiddenElementCount === -1 ) {
|
||||
surveyResults.hiddenElementCount = (( ) => {
|
||||
if ( vAPI.domFilterer instanceof Object === false ) { return 0; }
|
||||
const details = vAPI.domFilterer.getAllSelectors_(true);
|
||||
if ( Array.isArray(details.declarative) === false ) { return 0; }
|
||||
const selectors = details.declarative.map(entry => entry[0]);
|
||||
const simple = [], complex = [];
|
||||
for ( const selectorStr of selectors ) {
|
||||
for ( const selector of selectorStr.split(',\n') ) {
|
||||
if ( /[ +>~]/.test(selector) ) {
|
||||
complex.push(selector);
|
||||
} else {
|
||||
simple.push(selector);
|
||||
}
|
||||
}
|
||||
}
|
||||
const simpleStr = simple.join(',\n');
|
||||
const complexStr = complex.join(',\n');
|
||||
const nodeIter = document.createNodeIterator(
|
||||
document.body,
|
||||
NodeFilter.SHOW_ELEMENT
|
||||
);
|
||||
const matched = new Set();
|
||||
for (;;) {
|
||||
const node = nodeIter.nextNode();
|
||||
if ( node === null ) { break; }
|
||||
if ( node.offsetParent !== null ) { continue; }
|
||||
if (
|
||||
node.matches(simpleStr) === false &&
|
||||
node.closest(complexStr) !== node
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
matched.add(node);
|
||||
if ( matched.size === 99 ) { break; }
|
||||
}
|
||||
return matched.size;
|
||||
})();
|
||||
}
|
||||
|
||||
// https://github.com/uBlockOrigin/uBlock-issues/issues/756
|
||||
// Keep trying to find inline script-like instances but only if we
|
||||
// have the time-budget to do so.
|
||||
|
@ -164,9 +121,9 @@
|
|||
|
||||
// IMPORTANT: This is returned to the injector, so this MUST be
|
||||
// the last statement.
|
||||
return {
|
||||
hiddenElementCount: surveyResults.hiddenElementCount,
|
||||
inlineScriptCount: surveyResults.inlineScriptCount,
|
||||
externalScriptCount: surveyResults.externalScriptCount,
|
||||
};
|
||||
let total = surveyResults.externalScriptCount;
|
||||
if ( surveyResults.inlineScriptCount !== -1 ) {
|
||||
total += surveyResults.inlineScriptCount;
|
||||
}
|
||||
return total;
|
||||
})();
|
Loading…
Reference in a new issue