aboutsummaryrefslogtreecommitdiffstats
path: root/js/contentscript.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/contentscript.js')
-rw-r--r--js/contentscript.js517
1 files changed, 279 insertions, 238 deletions
diff --git a/js/contentscript.js b/js/contentscript.js
index 650d1be..c304fdf 100644
--- a/js/contentscript.js
+++ b/js/contentscript.js
@@ -21,70 +21,58 @@
uMatrix Home: https://github.com/gorhill/uMatrix
*/
-/* global HTMLDocument, XMLDocument */
-
'use strict';
-/******************************************************************************/
-/******************************************************************************/
-
// Injected into content pages
-(function() {
-
- /******************************************************************************/
-
+(function () {
// https://github.com/chrisaljoudi/uBlock/issues/464
// https://github.com/gorhill/uMatrix/issues/621
- if (
- document instanceof HTMLDocument === false &&
- document instanceof XMLDocument === false
- ) {
+ if (document instanceof HTMLDocument === false
+ && document instanceof XMLDocument === false) {
return;
}
- // This can also happen (for example if script injected into a `data:` URI doc)
- if ( !window.location ) {
+ // This can also happen (for example if script injected into a
+ // `data:` URI doc)
+ if (!window.location) {
return;
}
// This can happen
- if ( typeof vAPI !== 'object' ) {
+ if (typeof vAPI !== 'object') {
//console.debug('contentscript.js > vAPI not found');
return;
}
// https://github.com/chrisaljoudi/uBlock/issues/456
// Already injected?
- if ( vAPI.contentscriptEndInjected ) {
+ if (vAPI.contentscriptEndInjected) {
//console.debug('contentscript.js > content script already injected');
return;
}
vAPI.contentscriptEndInjected = true;
- /******************************************************************************/
- /******************************************************************************/
-
// Executed only once.
-
- (function() {
- var localStorageHandler = function(mustRemove) {
- if ( mustRemove ) {
+ (function () {
+ let localStorageHandler = function (mustRemove) {
+ if (mustRemove) {
window.localStorage.clear();
window.sessionStorage.clear();
}
};
// Check with extension whether local storage must be emptied
- // rhill 2014-03-28: we need an exception handler in case 3rd-party access
- // to site data is disabled.
+ // rhill 2014-03-28: we need an exception handler in case
+ // 3rd-party access to site data is disabled.
// https://github.com/gorhill/httpswitchboard/issues/215
try {
- var hasLocalStorage =
+ let hasLocalStorage =
window.localStorage && window.localStorage.length !== 0;
- var hasSessionStorage =
+ let hasSessionStorage =
window.sessionStorage && window.sessionStorage.length !== 0;
- if ( hasLocalStorage || hasSessionStorage ) {
+
+ if (hasLocalStorage || hasSessionStorage) {
vAPI.messaging.send('contentscript.js', {
what: 'contentScriptHasLocalStorage',
originURL: window.location.origin
@@ -104,140 +92,154 @@
// "There is no way to enumerate or delete the databases available for an origin from this API."
// Ref.: http://www.w3.org/TR/webdatabase/#databases
// }
- }
- catch (e) {
+ } catch (e) {
}
})();
- /******************************************************************************/
- /******************************************************************************/
-
// https://github.com/gorhill/uMatrix/issues/45
-
- var collapser = (function() {
- var resquestIdGenerator = 1,
- processTimer,
- toProcess = [],
- toFilter = [],
- toCollapse = new Map(),
- cachedBlockedMap,
- cachedBlockedMapHash,
- cachedBlockedMapTimer,
- reURLPlaceholder = /\{\{url\}\}/g;
- var src1stProps = {
- 'embed': 'src',
- 'iframe': 'src',
- 'img': 'src',
- 'object': 'data'
+ let collapser = (function () {
+ let resquestIdGenerator = 1;
+ let processTimer;
+ let toProcess = [];
+ let toFilter = [];
+ let toCollapse = new Map();
+ let cachedBlockedMap;
+ let cachedBlockedMapHash;
+ let cachedBlockedMapTimer;
+ let reURLPlaceholder = /\{\{url\}\}/g;
+ let src1stProps = {
+ embed: 'src',
+ iframe: 'src',
+ img: 'src',
+ object: 'data',
};
- var src2ndProps = {
- 'img': 'srcset'
+ let src2ndProps = {
+ img: 'srcset',
};
- var tagToTypeMap = {
+ let tagToTypeMap = {
embed: 'media',
iframe: 'frame',
img: 'image',
- object: 'media'
+ object: 'media',
};
- var cachedBlockedSetClear = function() {
+ let cachedBlockedSetClear = function () {
cachedBlockedMap =
cachedBlockedMapHash =
cachedBlockedMapTimer = undefined;
};
// https://github.com/chrisaljoudi/uBlock/issues/174
- // Do not remove fragment from src URL
- var onProcessed = function(response) {
- if ( !response ) { // This happens if uBO is disabled or restarted.
+ // Do not remove fragment from src URL
+ let onProcessed = function (response) {
+ if (!response) { // This happens if uBO is disabled or restarted.
toCollapse.clear();
return;
}
- var targets = toCollapse.get(response.id);
- if ( targets === undefined ) { return; }
+ let targets = toCollapse.get(response.id);
+ if (targets === undefined) {
+ return;
+ }
+
toCollapse.delete(response.id);
- if ( cachedBlockedMapHash !== response.hash ) {
+
+ if (cachedBlockedMapHash !== response.hash) {
cachedBlockedMap = new Map(response.blockedResources);
cachedBlockedMapHash = response.hash;
- if ( cachedBlockedMapTimer !== undefined ) {
+ if (cachedBlockedMapTimer !== undefined) {
clearTimeout(cachedBlockedMapTimer);
}
- cachedBlockedMapTimer = vAPI.setTimeout(cachedBlockedSetClear, 30000);
+ cachedBlockedMapTimer =
+ vAPI.setTimeout(cachedBlockedSetClear, 30000);
}
- if ( cachedBlockedMap === undefined || cachedBlockedMap.size === 0 ) {
+
+ if (cachedBlockedMap === undefined || cachedBlockedMap.size === 0) {
return;
}
- var placeholders = response.placeholders,
- tag, prop, src, collapsed, docurl, replaced;
+ let placeholders = response.placeholders;
- for ( var target of targets ) {
- tag = target.localName;
- prop = src1stProps[tag];
- if ( prop === undefined ) { continue; }
- src = target[prop];
- if ( typeof src !== 'string' || src.length === 0 ) {
+ for (let target of targets) {
+ let tag = target.localName;
+
+ let prop = src1stProps[tag];
+ if (prop === undefined) {
+ continue;
+ }
+
+ let src = target[prop];
+ if (typeof src !== 'string' || src.length === 0) {
prop = src2ndProps[tag];
- if ( prop === undefined ) { continue; }
+ if (prop === undefined) {
+ continue;
+ }
src = target[prop];
- if ( typeof src !== 'string' || src.length === 0 ) { continue; }
+ if (typeof src !== 'string' || src.length === 0) {
+ continue;
+ }
}
- collapsed = cachedBlockedMap.get(tagToTypeMap[tag] + ' ' + src);
- if ( collapsed === undefined ) { continue; }
- if ( collapsed ) {
+
+ let collapsed = cachedBlockedMap.get(tagToTypeMap[tag]
+ + ' '
+ + src);
+ if (collapsed === undefined) {
+ continue;
+ }
+
+ if (collapsed) {
target.style.setProperty('display', 'none', 'important');
target.hidden = true;
continue;
}
- switch ( tag ) {
+
+ switch (tag) {
case 'iframe':
- if ( placeholders.frame !== true ) { break; }
- docurl =
- 'data:text/html,' +
- encodeURIComponent(
- placeholders.frameDocument.replace(
- reURLPlaceholder,
- src
- )
- );
+ if (placeholders.frame !== true) {
+ break;
+ }
+
+ docurl = 'data:text/html,'
+ + encodeURIComponent(placeholders
+ .frameDocument
+ .replace(reURLPlaceholder, src));
replaced = false;
+
// Using contentWindow.location prevent tainting browser
// history -- i.e. breaking back button (seen on Chromium).
- if ( target.contentWindow ) {
+ if (target.contentWindow) {
try {
target.contentWindow.location.replace(docurl);
replaced = true;
} catch(ex) {
}
}
- if ( !replaced ) {
+
+ if (!replaced) {
target.setAttribute('src', docurl);
}
break;
case 'img':
- if ( placeholders.image !== true ) { break; }
+ if (placeholders.image !== true) {
+ break;
+ }
+
target.style.setProperty('display', 'inline-block');
target.style.setProperty('min-width', '20px', 'important');
target.style.setProperty('min-height', '20px', 'important');
- target.style.setProperty(
- 'border',
- placeholders.imageBorder,
- 'important'
- );
- target.style.setProperty(
- 'background',
- placeholders.imageBackground,
- 'important'
- );
+ target.style.setProperty('border', placeholders.imageBorder,
+ 'important');
+ target.style.setProperty('background',
+ placeholders.imageBackground,
+ 'important');
break;
}
}
};
- var send = function() {
+ let send = function () {
processTimer = undefined;
toCollapse.set(resquestIdGenerator, toProcess);
- var msg = {
+ let msg = {
what: 'lookupBlockedCollapsibles',
id: resquestIdGenerator,
toFilter: toFilter,
@@ -249,95 +251,108 @@
resquestIdGenerator += 1;
};
- var process = function(delay) {
- if ( toProcess.length === 0 ) { return; }
- if ( delay === 0 ) {
- if ( processTimer !== undefined ) {
+ let process = function (delay) {
+ if (toProcess.length === 0) {
+ return;
+ }
+
+ if (delay === 0) {
+ if (processTimer !== undefined) {
clearTimeout(processTimer);
}
send();
- } else if ( processTimer === undefined ) {
+ } else if (processTimer === undefined) {
processTimer = vAPI.setTimeout(send, delay || 47);
}
};
- var add = function(target) {
+ let add = function (target) {
toProcess.push(target);
};
- var addMany = function(targets) {
- var i = targets.length;
- while ( i-- ) {
+ let addMany = function (targets) {
+ for (let i=targets.length-1; i>=0; --i) {
toProcess.push(targets[i]);
}
};
- var iframeSourceModified = function(mutations) {
- var i = mutations.length;
- while ( i-- ) {
+ let iframeSourceModified = function (mutations) {
+ for (let i=mutations.length-1; i>=0; --i) {
addIFrame(mutations[i].target, true);
}
process();
};
- var iframeSourceObserver;
- var iframeSourceObserverOptions = {
+
+ let iframeSourceObserver;
+ let iframeSourceObserverOptions = {
attributes: true,
attributeFilter: [ 'src' ]
};
- var addIFrame = function(iframe, dontObserve) {
+ let addIFrame = function (iframe, dontObserve) {
// https://github.com/gorhill/uBlock/issues/162
// Be prepared to deal with possible change of src attribute.
- if ( dontObserve !== true ) {
- if ( iframeSourceObserver === undefined ) {
- iframeSourceObserver = new MutationObserver(iframeSourceModified);
+ if (dontObserve !== true) {
+ if (iframeSourceObserver === undefined) {
+ iframeSourceObserver =
+ new MutationObserver(iframeSourceModified);
}
- iframeSourceObserver.observe(iframe, iframeSourceObserverOptions);
+ iframeSourceObserver.observe(iframe,
+ iframeSourceObserverOptions);
+ }
+
+ let src = iframe.src;
+ if (src === '' || typeof src !== 'string') {
+ return;
+ }
+ if (src.startsWith('http') === false) {
+ return;
}
- var src = iframe.src;
- if ( src === '' || typeof src !== 'string' ) { return; }
- if ( src.startsWith('http') === false ) { return; }
- toFilter.push({ type: 'frame', url: iframe.src });
+
+ toFilter.push({
+ type: 'frame',
+ url: iframe.src,
+ });
+
add(iframe);
};
- var addIFrames = function(iframes) {
- var i = iframes.length;
- while ( i-- ) {
+ let addIFrames = function (iframes) {
+ for (let i=iframes.length-1; i>=0; --i) {
addIFrame(iframes[i]);
}
};
- var addNodeList = function(nodeList) {
- var node,
- i = nodeList.length;
- while ( i-- ) {
- node = nodeList[i];
- if ( node.nodeType !== 1 ) { continue; }
- if ( node.localName === 'iframe' ) {
+ let addNodeList = function (nodeList) {
+ for (let i=nodeList.length-1; i>=0; --i) {
+ let node = nodeList[i];
+ if (node.nodeType !== 1) {
+ continue;
+ }
+ if (node.localName === 'iframe') {
addIFrame(node);
}
- if ( node.childElementCount !== 0 ) {
+ if (node.childElementCount !== 0) {
addIFrames(node.querySelectorAll('iframe'));
}
}
};
- var onResourceFailed = function(ev) {
- if ( tagToTypeMap[ev.target.localName] !== undefined ) {
+ let onResourceFailed = function (ev) {
+ if (tagToTypeMap[ev.target.localName] !== undefined) {
add(ev.target);
process();
}
};
document.addEventListener('error', onResourceFailed, true);
- vAPI.shutdown.add(function() {
+ vAPI.shutdown.add(function () {
document.removeEventListener('error', onResourceFailed, true);
- if ( iframeSourceObserver !== undefined ) {
+ if (iframeSourceObserver !== undefined) {
iframeSourceObserver.disconnect();
iframeSourceObserver = undefined;
}
- if ( processTimer !== undefined ) {
+ if (processTimer !== undefined) {
clearTimeout(processTimer);
processTimer = undefined;
}
@@ -351,24 +366,21 @@
};
})();
- /******************************************************************************/
- /******************************************************************************/
-
// Observe changes in the DOM
-
// Added node lists will be cumulated here before being processed
- (function() {
+ (function () {
// This fixes http://acid3.acidtests.org/
- if ( !document.body ) { return; }
+ if (!document.body) {
+ return;
+ }
- var addedNodeLists = [];
- var addedNodeListsTimer;
+ let addedNodeLists = [];
+ let addedNodeListsTimer;
- var treeMutationObservedHandler = function() {
+ let treeMutationObservedHandler = function () {
addedNodeListsTimer = undefined;
- var i = addedNodeLists.length;
- while ( i-- ) {
+ for (let i=addedNodeLists.length-1; i>=0; --i) {
collapser.addNodeList(addedNodeLists[i]);
}
collapser.process();
@@ -377,33 +389,33 @@
// https://github.com/gorhill/uBlock/issues/205
// Do not handle added node directly from within mutation observer.
- var treeMutationObservedHandlerAsync = function(mutations) {
- var iMutation = mutations.length,
- nodeList;
- while ( iMutation-- ) {
- nodeList = mutations[iMutation].addedNodes;
- if ( nodeList.length !== 0 ) {
+ let treeMutationObservedHandlerAsync = function (mutations) {
+ for (let i=mutations.length-1; i>=0; --i) {
+ let nodeList = mutations[i].addedNodes;
+ if (nodeList.length !== 0) {
addedNodeLists.push(nodeList);
}
}
- if ( addedNodeListsTimer === undefined ) {
- addedNodeListsTimer = vAPI.setTimeout(treeMutationObservedHandler, 47);
+ if (addedNodeListsTimer === undefined) {
+ addedNodeListsTimer =
+ vAPI.setTimeout(treeMutationObservedHandler, 47);
}
};
// https://github.com/gorhill/httpswitchboard/issues/176
- var treeObserver = new MutationObserver(treeMutationObservedHandlerAsync);
+ let treeObserver =
+ new MutationObserver(treeMutationObservedHandlerAsync);
treeObserver.observe(document.body, {
childList: true,
subtree: true
});
- vAPI.shutdown.add(function() {
- if ( addedNodeListsTimer !== undefined ) {
+ vAPI.shutdown.add(function () {
+ if (addedNodeListsTimer !== undefined) {
clearTimeout(addedNodeListsTimer);
addedNodeListsTimer = undefined;
}
- if ( treeObserver !== null ) {
+ if (treeObserver !== null) {
treeObserver.disconnect();
treeObserver = undefined;
}
@@ -411,9 +423,6 @@
});
})();
- /******************************************************************************/
- /******************************************************************************/
-
// Executed only once.
//
// https://github.com/gorhill/httpswitchboard/issues/25
@@ -427,12 +436,41 @@
// https://github.com/gorhill/uMatrix/issues/924
// Report inline styles.
- (function() {
- if (
- document.querySelector('script:not([src])') !== null ||
- document.querySelector('a[href^="javascript:"]') !== null ||
- document.querySelector('[onabort],[onblur],[oncancel],[oncanplay],[oncanplaythrough],[onchange],[onclick],[onclose],[oncontextmenu],[oncuechange],[ondblclick],[ondrag],[ondragend],[ondragenter],[ondragexit],[ondragleave],[ondragover],[ondragstart],[ondrop],[ondurationchange],[onemptied],[onended],[onerror],[onfocus],[oninput],[oninvalid],[onkeydown],[onkeypress],[onkeyup],[onload],[onloadeddata],[onloadedmetadata],[onloadstart],[onmousedown],[onmouseenter],[onmouseleave],[onmousemove],[onmouseout],[onmouseover],[onmouseup],[onwheel],[onpause],[onplay],[onplaying],[onprogress],[onratechange],[onreset],[onresize],[onscroll],[onseeked],[onseeking],[onselect],[onshow],[onstalled],[onsubmit],[onsuspend],[ontimeupdate],[ontoggle],[onvolumechange],[onwaiting],[onafterprint],[onbeforeprint],[onbeforeunload],[onhashchange],[onlanguagechange],[onmessage],[onoffline],[ononline],[onpagehide],[onpageshow],[onrejectionhandled],[onpopstate],[onstorage],[onunhandledrejection],[onunload],[oncopy],[oncut],[onpaste]') !== null
- ) {
+ (function () {
+ if (document.querySelector('script:not([src])') !== null
+ || document.querySelector('a[href^="javascript:"]') !== null
+ || document.querySelector('[onabort],[onblur],[oncancel],'
+ + '[oncanplay],[oncanplaythrough],'
+ + '[onchange],[onclick],[onclose],'
+ + '[oncontextmenu],[oncuechange],'
+ + '[ondblclick],[ondrag],[ondragend],'
+ + '[ondragenter],[ondragexit],'
+ + '[ondragleave],[ondragover],'
+ + '[ondragstart],[ondrop],'
+ + '[ondurationchange],[onemptied],'
+ + '[onended],[onerror],[onfocus],'
+ + '[oninput],[oninvalid],[onkeydown],'
+ + '[onkeypress],[onkeyup],[onload],'
+ + '[onloadeddata],[onloadedmetadata],'
+ + '[onloadstart],[onmousedown],'
+ + '[onmouseenter],[onmouseleave],'
+ + '[onmousemove],[onmouseout],'
+ + '[onmouseover],[onmouseup],[onwheel],'
+ + '[onpause],[onplay],[onplaying],'
+ + '[onprogress],[onratechange],[onreset],'
+ + '[onresize],[onscroll],[onseeked],'
+ + '[onseeking],[onselect],[onshow],'
+ + '[onstalled],[onsubmit],[onsuspend],'
+ + '[ontimeupdate],[ontoggle],'
+ + '[onvolumechange],[onwaiting],'
+ + '[onafterprint],[onbeforeprint],'
+ + '[onbeforeunload],[onhashchange],'
+ + '[onlanguagechange],[onmessage],'
+ + '[onoffline],[ononline],[onpagehide],'
+ + '[onpageshow],[onrejectionhandled],'
+ + '[onpopstate],[onstorage],'
+ + '[onunhandledrejection],[onunload],'
+ + '[oncopy],[oncut],[onpaste]') !== null) {
vAPI.messaging.send('contentscript.js', {
what: 'securityPolicyViolation',
directive: 'script-src',
@@ -440,7 +478,7 @@
});
}
- if ( document.querySelector('style,[style]') !== null ) {
+ if (document.querySelector('style,[style]') !== null) {
vAPI.messaging.send('contentscript.js', {
what: 'securityPolicyViolation',
directive: 'style-src',
@@ -453,90 +491,93 @@
collapser.process();
})();
- /******************************************************************************/
- /******************************************************************************/
-
// Executed only once.
-
// https://github.com/gorhill/uMatrix/issues/232
- // Force `display` property, Firefox is still affected by the issue.
-
- (function() {
- var noscripts = document.querySelectorAll('noscript');
- if ( noscripts.length === 0 ) { return; }
-
- var redirectTimer,
- reMetaContent = /^\s*(\d+)\s*;\s*url=(['"]?)([^'"]+)\2/i,
- reSafeURL = /^https?:\/\//;
-
- var autoRefresh = function(root) {
- var meta = root.querySelector('meta[http-equiv="refresh"][content]');
- if ( meta === null ) { return; }
- var match = reMetaContent.exec(meta.getAttribute('content'));
- if ( match === null || match[3].trim() === '' ) { return; }
- var url = new URL(match[3], document.baseURI);
- if ( reSafeURL.test(url.href) === false ) { return; }
- redirectTimer = setTimeout(
- function() {
- location.assign(url.href);
- },
- parseInt(match[1], 10) * 1000 + 1
- );
+ // Force `display` property, Firefox is still affected by the issue.
+
+ (function () {
+ let noscripts = document.querySelectorAll('noscript');
+ if (noscripts.length === 0) {
+ return;
+ }
+
+ let redirectTimer;
+ let reMetaContent = /^\s*(\d+)\s*;\s*url=(['"]?)([^'"]+)\2/i;
+ let reSafeURL = /^https?:\/\//;
+
+ let autoRefresh = function (root) {
+ let meta =
+ root.querySelector('meta[http-equiv="refresh"][content]');
+ if (meta === null) {
+ return;
+ }
+
+ let match = reMetaContent.exec(meta.getAttribute('content'));
+ if (match === null || match[3].trim() === '') {
+ return;
+ }
+
+ let url = new URL(match[3], document.baseURI);
+ if (reSafeURL.test(url.href) === false) {
+ return;
+ }
+
+ redirectTimer = setTimeout(function () {
+ location.assign(url.href);
+ }, parseInt(match[1], 10) * 1000 + 1);
+
meta.parentNode.removeChild(meta);
};
- var morphNoscript = function(from) {
- if ( /^application\/(?:xhtml\+)?xml/.test(document.contentType) ) {
- var to = document.createElement('span');
- while ( from.firstChild !== null ) {
+ let morphNoscript = function (from) {
+ if (/^application\/(?:xhtml\+)?xml/.test(document.contentType)) {
+ let to = document.createElement('span');
+ while (from.firstChild !== null) {
to.appendChild(from.firstChild);
}
return to;
}
- var parser = new DOMParser();
- var doc = parser.parseFromString(
- '<span>' + from.textContent + '</span>',
- 'text/html'
- );
+
+ let parser = new DOMParser();
+ let doc =
+ parser.parseFromString('<span>' + from.textContent + '</span>',
+ 'text/html');
+
return document.adoptNode(doc.querySelector('span'));
};
- var renderNoscriptTags = function(response) {
- if ( response !== true ) { return; }
- var parent, span;
- for ( var noscript of noscripts ) {
- parent = noscript.parentNode;
- if ( parent === null ) { continue; }
- span = morphNoscript(noscript);
+ let renderNoscriptTags = function (response) {
+ if (response !== true) {
+ return;
+ }
+
+ for (let noscript of noscripts) {
+ let parent = noscript.parentNode;
+ if (parent === null) {
+ continue;
+ }
+
+ let span = morphNoscript(noscript);
span.style.setProperty('display', 'inline', 'important');
- if ( redirectTimer === undefined ) {
+
+ if (redirectTimer === undefined) {
autoRefresh(span);
}
+
parent.replaceChild(span, noscript);
}
};
- vAPI.messaging.send(
- 'contentscript.js',
- { what: 'mustRenderNoscriptTags?' },
- renderNoscriptTags
- );
+ vAPI.messaging.send('contentscript.js', {
+ what: 'mustRenderNoscriptTags?'
+ }, renderNoscriptTags);
})();
- /******************************************************************************/
- /******************************************************************************/
-
- vAPI.messaging.send(
- 'contentscript.js',
- { what: 'shutdown?' },
- function(response) {
- if ( response === true ) {
- vAPI.shutdown.exec();
- }
+ vAPI.messaging.send('contentscript.js', {
+ what: 'shutdown?'
+ }, function (response) {
+ if (response === true) {
+ vAPI.shutdown.exec();
}
- );
-
- /******************************************************************************/
- /******************************************************************************/
-
+ });
})();