From bf690145c493acd86e578d7a860da238f0af72d4 Mon Sep 17 00:00:00 2001 From: Raymond Hill Date: Sat, 24 Sep 2022 20:49:00 -0400 Subject: [PATCH] Add new scriptlet: xml-prune Related issue: - https://github.com/uBlockOrigin/uAssets/issues/14849 Arguments: 1. Required. The selector of elements which are to be removed. Example: Period[id*="-roll-"][id*="-ad-"] 2. An optional selector that must have a match in the document for the pruning to occur. No selector means the pruning can be performed regardless. 3. An optional URL which must be a match for the pruning to occur. If left blank, the pruning can be performed regardless. --- assets/resources/scriptlets.js | 60 ++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/assets/resources/scriptlets.js b/assets/resources/scriptlets.js index 84ba5de84..053a86868 100644 --- a/assets/resources/scriptlets.js +++ b/assets/resources/scriptlets.js @@ -1669,6 +1669,66 @@ +/// xml-prune.js +(function() { + let selector = '{{1}}'; + if ( selector === '{{1}}' ) { + selector = ''; + } + let selectorCheck = '{{2}}'; + if ( selectorCheck === '{{2}}' ) { + selectorCheck = ''; + } + let urlPattern = '{{3}}'; + if ( urlPattern === '{{3}}' ) { + urlPattern = ''; + } + let reUrl; + if ( urlPattern === '' ) { + reUrl = /^/; + } else if ( /^\/.*\/$/.test(urlPattern) ) { + reUrl = new RegExp(urlPattern.slice(1, -1)); + } else { + reUrl = new RegExp(urlPattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')); + } + const pruner = text => { + if ( selector === '' ) { return text; } + if ( (/^\s*\s*$/.test(text)) === false ) { + return text; + } + try { + const xmlParser = new DOMParser(); + const xmlDoc = xmlParser.parseFromString(text, 'text/xml'); + if ( selectorCheck !== '' && xmlDoc.querySelector(selectorCheck) === null ) { + return text; + } + const elems = xmlDoc.querySelectorAll(selector); + if ( elems.length !== 0 ) { + for ( const elem of elems ) { + elem.remove(); + } + const serializer = new XMLSerializer(); + text = serializer.serializeToString(xmlDoc); + } + } catch(ex) { + } + return text; + }; + const realFetch = self.fetch; + self.fetch = new Proxy(self.fetch, { + apply: function(target, thisArg, args) { + if ( reUrl.test(String(args[0])) === false ) { + return Reflect.apply(target, thisArg, args); + } + return realFetch(...args).then(response => + response.text() + ).then(text => + new Response(pruner(text)) + ); + } + }); +})(); + // These lines below are skipped by the resource parser.