1
0
mirror of https://github.com/gorhill/uBlock.git synced 2024-10-06 09:37:12 +02:00

Simplify client messaging code

Little-used code from vapi-client.js has been moved
to vapi-client-extra.js. Given that vapi-client.js
is injected in all web pages, this means less dead
code being injected in all pages.

Swathes of code in vapi-client.js was used only in
a few very specific cases, such as when the logger's
DOM inspector is opened or when the "Filter lists"
pane in the dashboard is opened -- and thus to avoid
that little used code to be loaded in every web page
unconditionally, it has been moved to its own
separate file, vapi-client.extra.js.

vapi-client-extra.js is loaded declaratively or
programmatically only where needed.
This commit is contained in:
Raymond Hill 2019-09-19 08:31:38 -04:00
parent 149b5cf59c
commit 87d0e456f1
No known key found for this signature in database
GPG Key ID: 25E1490B761470C2
10 changed files with 517 additions and 421 deletions

View File

@ -939,10 +939,10 @@ vAPI.messaging = {
switch ( msg.what ) { switch ( msg.what ) {
case 'connectionAccepted': case 'connectionAccepted':
case 'connectionRefused': { case 'connectionRefused': {
const { port: toPort } = this.ports.get(msg.fromToken); const toPort = this.ports.get(msg.fromToken);
if ( toPort !== undefined ) { if ( toPort !== undefined ) {
msg.tabId = tabId; msg.tabId = tabId;
toPort.postMessage(request); toPort.port.postMessage(request);
} else { } else {
msg.what = 'connectionBroken'; msg.what = 'connectionBroken';
port.postMessage(request); port.postMessage(request);
@ -952,24 +952,32 @@ vAPI.messaging = {
case 'connectionRequested': case 'connectionRequested':
msg.tabId = tabId; msg.tabId = tabId;
for ( const { port: toPort } of this.ports.values() ) { for ( const { port: toPort } of this.ports.values() ) {
if ( toPort === port ) { continue; }
toPort.postMessage(request); toPort.postMessage(request);
} }
break; break;
case 'connectionBroken': case 'connectionBroken':
case 'connectionCheck': case 'connectionCheck':
case 'connectionMessage': { case 'connectionMessage': {
const { port: toPort } = this.ports.get( const toPort = this.ports.get(
port.name === msg.fromToken ? msg.toToken : msg.fromToken port.name === msg.fromToken ? msg.toToken : msg.fromToken
); );
if ( toPort !== undefined ) { if ( toPort !== undefined ) {
msg.tabId = tabId; msg.tabId = tabId;
toPort.postMessage(request); toPort.port.postMessage(request);
} else { } else {
msg.what = 'connectionBroken'; msg.what = 'connectionBroken';
port.postMessage(request); port.postMessage(request);
} }
break; break;
} }
case 'extendClient':
vAPI.tabs.executeScript(tabId, {
file: '/js/vapi-client-extra.js',
}).then(( ) => {
callback();
});
break;
case 'userCSS': case 'userCSS':
if ( tabId === undefined ) { break; } if ( tabId === undefined ) { break; }
const details = { const details = {
@ -1043,7 +1051,7 @@ vAPI.messaging = {
} }
// Content process to main process: framework handler. // Content process to main process: framework handler.
if ( request.channelName === 'vapi' ) { if ( request.channel === 'vapi' ) {
this.onFrameworkMessage(request, port, callback); this.onFrameworkMessage(request, port, callback);
return; return;
} }
@ -1052,7 +1060,7 @@ vAPI.messaging = {
const fromDetails = this.ports.get(port.name); const fromDetails = this.ports.get(port.name);
if ( fromDetails === undefined ) { return; } if ( fromDetails === undefined ) { return; }
const listenerDetails = this.listeners.get(request.channelName); const listenerDetails = this.listeners.get(request.channel);
let r = this.UNHANDLED; let r = this.UNHANDLED;
if ( if (
(listenerDetails !== undefined) && (listenerDetails !== undefined) &&

View File

@ -0,0 +1,308 @@
/*******************************************************************************
uBlock Origin - a browser extension to block requests.
Copyright (C) 2019-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
*/
// For non-background page
'use strict';
/******************************************************************************/
// Direct messaging connection ability
(( ) => {
// >>>>>>>> start of private namespace
if (
typeof vAPI !== 'object' ||
vAPI.messaging instanceof Object === false ||
vAPI.MessagingConnection instanceof Function
) {
return;
}
const listeners = new Set();
const connections = new Map();
vAPI.MessagingConnection = class {
constructor(handler, details) {
this.messaging = vAPI.messaging;
this.handler = handler;
this.id = details.id;
this.to = details.to;
this.toToken = details.toToken;
this.from = details.from;
this.fromToken = details.fromToken;
this.checkTimer = undefined;
// On Firefox it appears ports are not automatically disconnected
// when navigating to another page.
const ctor = vAPI.MessagingConnection;
if ( ctor.pagehide !== undefined ) { return; }
ctor.pagehide = ( ) => {
for ( const connection of connections.values() ) {
connection.disconnect();
connection.handler(
connection.toDetails('connectionBroken')
);
}
};
window.addEventListener('pagehide', ctor.pagehide);
}
toDetails(what, payload) {
return {
what: what,
id: this.id,
from: this.from,
fromToken: this.fromToken,
to: this.to,
toToken: this.toToken,
payload: payload
};
}
disconnect() {
if ( this.checkTimer !== undefined ) {
clearTimeout(this.checkTimer);
this.checkTimer = undefined;
}
connections.delete(this.id);
const port = this.messaging.getPort();
if ( port === null ) { return; }
port.postMessage({
channel: 'vapi',
msg: this.toDetails('connectionBroken'),
});
}
checkAsync() {
if ( this.checkTimer !== undefined ) {
clearTimeout(this.checkTimer);
}
this.checkTimer = vAPI.setTimeout(
( ) => { this.check(); },
499
);
}
check() {
this.checkTimer = undefined;
if ( connections.has(this.id) === false ) { return; }
const port = this.messaging.getPort();
if ( port === null ) { return; }
port.postMessage({
channel: 'vapi',
msg: this.toDetails('connectionCheck'),
});
this.checkAsync();
}
receive(details) {
switch ( details.what ) {
case 'connectionAccepted':
this.toToken = details.toToken;
this.handler(details);
this.checkAsync();
break;
case 'connectionBroken':
connections.delete(this.id);
this.handler(details);
break;
case 'connectionMessage':
this.handler(details);
this.checkAsync();
break;
case 'connectionCheck':
const port = this.messaging.getPort();
if ( port === null ) { return; }
if ( connections.has(this.id) ) {
this.checkAsync();
} else {
details.what = 'connectionBroken';
port.postMessage({ channel: 'vapi', msg: details });
}
break;
case 'connectionRefused':
connections.delete(this.id);
this.handler(details);
break;
}
}
send(payload) {
const port = this.messaging.getPort();
if ( port === null ) { return; }
port.postMessage({
channel: 'vapi',
msg: this.toDetails('connectionMessage', payload),
});
}
static addListener(listener) {
listeners.add(listener);
}
static async connectTo(from, to, handler) {
const port = vAPI.messaging.getPort();
if ( port === null ) { return; }
const connection = new vAPI.MessagingConnection(handler, {
id: `${from}-${to}-${vAPI.sessionId}`,
to: to,
from: from,
fromToken: port.name
});
connections.set(connection.id, connection);
port.postMessage({
channel: 'vapi',
msg: {
what: 'connectionRequested',
id: connection.id,
from: from,
fromToken: port.name,
to: to,
}
});
return connection.id;
}
static disconnectFrom(connectionId) {
const connection = connections.get(connectionId);
if ( connection === undefined ) { return; }
connection.disconnect();
}
static sendTo(connectionId, payload) {
const connection = connections.get(connectionId);
if ( connection === undefined ) { return; }
connection.send(payload);
}
static canDestroyPort() {
return listeners.length === 0 && connections.size === 0;
}
static mustDestroyPort() {
if ( connections.size === 0 ) { return; }
for ( const connection of connections.values() ) {
connection.receive({ what: 'connectionBroken' });
}
connections.clear();
}
static canProcessMessage(details) {
if ( details.channel !== 'vapi' ) { return; }
switch ( details.msg.what ) {
case 'connectionAccepted':
case 'connectionBroken':
case 'connectionCheck':
case 'connectionMessage':
case 'connectionRefused': {
const connection = connections.get(details.msg.id);
if ( connection === undefined ) { break; }
connection.receive(details.msg);
return true;
}
case 'connectionRequested':
if ( listeners.length === 0 ) { return; }
const port = vAPI.messaging.getPort();
if ( port === null ) { break; }
let listener, result;
for ( listener of listeners ) {
result = listener(details.msg);
if ( result !== undefined ) { break; }
}
if ( result === undefined ) { break; }
if ( result === true ) {
details.msg.what = 'connectionAccepted';
details.msg.toToken = port.name;
const connection = new vAPI.MessagingConnection(
listener,
details.msg
);
connections.set(connection.id, connection);
} else {
details.msg.what = 'connectionRefused';
}
port.postMessage(details);
return true;
default:
break;
}
}
};
vAPI.messaging.extensions.push(vAPI.MessagingConnection);
// <<<<<<<< end of private namespace
})();
/******************************************************************************/
// Broadcast listening ability
(( ) => {
// >>>>>>>> start of private namespace
if (
typeof vAPI !== 'object' ||
vAPI.messaging instanceof Object === false ||
vAPI.broadcastListener instanceof Object
) {
return;
}
const listeners = new Set();
vAPI.broadcastListener = {
add: function(listener) {
listeners.add(listener);
vAPI.messaging.getPort();
},
remove: function(listener) {
listeners.delete(listener);
},
canDestroyPort() {
return listeners.size === 0;
},
mustDestroyPort() {
listeners.clear();
},
canProcessMessage(details) {
if ( details.broadcast === false ) { return; }
for ( const listener of listeners ) {
listener(details.msg);
}
},
};
vAPI.messaging.extensions.push(vAPI.broadcastListener);
// <<<<<<<< end of private namespace
})();
/******************************************************************************/
/*******************************************************************************
DO NOT:
- Remove the following code
- Add code beyond the following code
Reason:
- https://github.com/gorhill/uBlock/pull/3721
- uBO never uses the return value from injected content scripts
**/
void 0;

View File

@ -30,16 +30,18 @@
// Skip if already injected. // Skip if already injected.
// >>>>>>>> start of HUGE-IF-BLOCK // >>>>>>>> start of HUGE-IF-BLOCK
if ( typeof vAPI === 'object' && !vAPI.clientScript ) { if (
typeof vAPI === 'object' &&
vAPI.randomToken instanceof Function === false
) {
/******************************************************************************/ /******************************************************************************/
/******************************************************************************/ /******************************************************************************/
vAPI.clientScript = true;
vAPI.randomToken = function() { vAPI.randomToken = function() {
return String.fromCharCode(Date.now() % 26 + 97) + const now = Date.now();
Math.floor(Math.random() * 982451653 + 982451653).toString(36); return String.fromCharCode(now % 26 + 97) +
Math.floor((1 + Math.random()) * now).toString(36);
}; };
vAPI.sessionId = vAPI.randomToken(); vAPI.sessionId = vAPI.randomToken();
@ -77,121 +79,11 @@ vAPI.messaging = {
port: null, port: null,
portTimer: null, portTimer: null,
portTimerDelay: 10000, portTimerDelay: 10000,
channels: new Map(), extensions: [],
connections: new Map(),
pending: new Map(),
msgIdGenerator: 1, msgIdGenerator: 1,
pending: new Map(),
shuttingDown: false, shuttingDown: false,
Connection: class {
constructor(handler, details) {
this.messaging = vAPI.messaging;
this.handler = handler;
this.id = details.id;
this.to = details.to;
this.toToken = details.toToken;
this.from = details.from;
this.fromToken = details.fromToken;
this.checkTimer = undefined;
// On Firefox it appears ports are not automatically disconnected
// when navigating to another page.
const ctor = this.messaging.Connection;
if ( ctor.pagehide !== undefined ) { return; }
ctor.pagehide = ( ) => {
for ( const connection of this.messaging.connections.values() ) {
connection.disconnect();
connection.handler(
connection.toDetails('connectionBroken')
);
}
};
window.addEventListener('pagehide', ctor.pagehide);
}
toDetails(what, payload) {
return {
what: what,
id: this.id,
from: this.from,
fromToken: this.fromToken,
to: this.to,
toToken: this.toToken,
payload: payload
};
}
disconnect() {
if ( this.checkTimer !== undefined ) {
clearTimeout(this.checkTimer);
this.checkTimer = undefined;
}
this.messaging.connections.delete(this.id);
const port = this.messaging.getPort();
if ( port === null ) { return; }
port.postMessage({
channelName: 'vapi',
msg: this.toDetails('connectionBroken')
});
}
checkAsync() {
if ( this.checkTimer !== undefined ) {
clearTimeout(this.checkTimer);
}
this.checkTimer = vAPI.setTimeout(
( ) => { this.check(); },
499
);
}
check() {
this.checkTimer = undefined;
if ( this.messaging.connections.has(this.id) === false ) { return; }
const port = this.messaging.getPort();
if ( port === null ) { return; }
port.postMessage({
channelName: 'vapi',
msg: this.toDetails('connectionCheck')
});
this.checkAsync();
}
receive(details) {
switch ( details.what ) {
case 'connectionAccepted':
this.toToken = details.toToken;
this.handler(details);
this.checkAsync();
break;
case 'connectionBroken':
this.messaging.connections.delete(this.id);
this.handler(details);
break;
case 'connectionMessage':
this.handler(details);
this.checkAsync();
break;
case 'connectionCheck':
const port = this.messaging.getPort();
if ( port === null ) { return; }
if ( this.messaging.connections.has(this.id) ) {
this.checkAsync();
} else {
details.what = 'connectionBroken';
port.postMessage({ channelName: 'vapi', msg: details });
}
break;
case 'connectionRefused':
this.messaging.connections.delete(this.id);
this.handler(details);
break;
}
}
send(payload) {
const port = this.messaging.getPort();
if ( port === null ) { return; }
port.postMessage({
channelName: 'vapi',
msg: this.toDetails('connectionMessage', payload)
});
}
},
shutdown: function() { shutdown: function() {
this.shuttingDown = true; this.shuttingDown = true;
this.destroyPort(); this.destroyPort();
@ -212,14 +104,6 @@ vAPI.messaging = {
messageListener: function(details) { messageListener: function(details) {
if ( details instanceof Object === false ) { return; } if ( details instanceof Object === false ) { return; }
// Sent to all channels
if ( details.broadcast ) {
for ( const channelName of this.channels.keys() ) {
this.sendToChannelListeners(channelName, details.msg);
}
return;
}
// Response to specific message previously sent // Response to specific message previously sent
if ( details.msgId !== undefined ) { if ( details.msgId !== undefined ) {
const resolver = this.pending.get(details.msgId); const resolver = this.pending.get(details.msgId);
@ -230,53 +114,28 @@ vAPI.messaging = {
} }
} }
if ( details.channelName !== 'vapi' ) { return; } // Unhandled messages
this.extensions.every(ext => ext.canProcessMessage(details) !== true);
// Internal handler
let connection;
switch ( details.msg.what ) {
case 'connectionAccepted':
case 'connectionBroken':
case 'connectionCheck':
case 'connectionMessage':
case 'connectionRefused':
connection = this.connections.get(details.msg.id);
if ( connection === undefined ) { return; }
connection.receive(details.msg);
break;
case 'connectionRequested':
const listeners = this.channels.get(details.msg.to);
if ( listeners === undefined ) { return; }
const port = this.getPort();
if ( port === null ) { return; }
for ( const listener of listeners ) {
if ( listener(details.msg) !== true ) { continue; }
details.msg.what = 'connectionAccepted';
details.msg.toToken = port.name;
connection = new this.Connection(listener, details.msg);
this.connections.set(connection.id, connection);
break;
}
if ( details.msg.what !== 'connectionAccepted' ) {
details.msg.what = 'connectionRefused';
}
port.postMessage(details);
break;
default:
break;
}
}, },
messageListenerCallback: null, messageListenerCallback: null,
canDestroyPort: function() {
return this.pending.size === 0 &&
(
this.extensions.length === 0 ||
this.extensions.every(e => e.canDestroyPort())
);
},
mustDestroyPort: function() {
if ( this.extensions.length === 0 ) { return; }
this.extensions.forEach(e => e.mustDestroyPort());
this.extensions.length = 0;
},
portPoller: function() { portPoller: function() {
this.portTimer = null; this.portTimer = null;
if ( if ( this.port !== null && this.canDestroyPort() ) {
this.port !== null &&
this.channels.size === 0 &&
this.connections.size === 0 &&
this.pending.size === 0
) {
return this.destroyPort(); return this.destroyPort();
} }
this.portTimer = vAPI.setTimeout(this.portPollerBound, this.portTimerDelay); this.portTimer = vAPI.setTimeout(this.portPollerBound, this.portTimerDelay);
@ -296,13 +155,7 @@ vAPI.messaging = {
port.onDisconnect.removeListener(this.disconnectListenerBound); port.onDisconnect.removeListener(this.disconnectListenerBound);
this.port = null; this.port = null;
} }
this.channels.clear(); this.mustDestroyPort();
if ( this.connections.size !== 0 ) {
for ( const connection of this.connections.values() ) {
connection.receive({ what: 'connectionBroken' });
}
this.connections.clear();
}
// service pending callbacks // service pending callbacks
if ( this.pending.size !== 0 ) { if ( this.pending.size !== 0 ) {
const pending = this.pending; const pending = this.pending;
@ -347,7 +200,7 @@ vAPI.messaging = {
return this.port !== null ? this.port : this.createPort(); return this.port !== null ? this.port : this.createPort();
}, },
send: function(channelName, msg) { send: function(channel, msg) {
// Too large a gap between the last request and the last response means // Too large a gap between the last request and the last response means
// the main process is no longer reachable: memory leaks and bad // the main process is no longer reachable: memory leaks and bad
// performance become a risk -- especially for long-lived, dynamic // performance become a risk -- especially for long-lived, dynamic
@ -363,86 +216,12 @@ vAPI.messaging = {
const promise = new Promise(resolve => { const promise = new Promise(resolve => {
this.pending.set(msgId, resolve); this.pending.set(msgId, resolve);
}); });
port.postMessage({ channelName, msgId, msg }); port.postMessage({ channel, msgId, msg });
return promise; return promise;
}, },
connectTo: function(from, to, handler) {
const port = this.getPort();
if ( port === null ) { return; }
const connection = new this.Connection(handler, {
id: `${from}-${to}-${vAPI.sessionId}`,
to: to,
from: from,
fromToken: port.name
});
this.connections.set(connection.id, connection);
port.postMessage({
channelName: 'vapi',
msg: {
what: 'connectionRequested',
id: connection.id,
from: from,
fromToken: port.name,
to: to
}
});
return connection.id;
},
disconnectFrom: function(connectionId) {
const connection = this.connections.get(connectionId);
if ( connection === undefined ) { return; }
connection.disconnect();
},
sendTo: function(connectionId, payload) {
const connection = this.connections.get(connectionId);
if ( connection === undefined ) { return; }
connection.send(payload);
},
addChannelListener: function(channelName, listener) {
const listeners = this.channels.get(channelName);
if ( listeners === undefined ) {
this.channels.set(channelName, [ listener ]);
} else if ( listeners.indexOf(listener) === -1 ) {
listeners.push(listener);
}
this.getPort();
},
removeChannelListener: function(channelName, listener) {
const listeners = this.channels.get(channelName);
if ( listeners === undefined ) { return; }
const pos = listeners.indexOf(listener);
if ( pos === -1 ) { return; }
listeners.splice(pos, 1);
if ( listeners.length === 0 ) {
this.channels.delete(channelName);
}
},
removeAllChannelListeners: function(channelName) {
this.channels.delete(channelName);
},
sendToChannelListeners: function(channelName, msg) {
let listeners = this.channels.get(channelName);
if ( listeners === undefined ) { return; }
listeners = listeners.slice(0);
let response;
for ( const listener of listeners ) {
response = listener(msg);
if ( response !== undefined ) { break; }
}
return response;
}
}; };
/******************************************************************************/ vAPI.shutdown.add(( ) => {
vAPI.shutdown.add(function() {
vAPI.messaging.shutdown(); vAPI.messaging.shutdown();
window.vAPI = undefined; window.vAPI = undefined;
}); });

View File

@ -59,6 +59,7 @@
<script src="js/vapi.js"></script> <script src="js/vapi.js"></script>
<script src="js/vapi-common.js"></script> <script src="js/vapi-common.js"></script>
<script src="js/vapi-client.js"></script> <script src="js/vapi-client.js"></script>
<script src="js/vapi-client-extra.js"></script>
<script src="js/udom.js"></script> <script src="js/udom.js"></script>
<script src="js/i18n.js"></script> <script src="js/i18n.js"></script>
<script src="js/dashboard-common.js"></script> <script src="js/dashboard-common.js"></script>

View File

@ -38,7 +38,9 @@ let hideUnusedSet = new Set();
/******************************************************************************/ /******************************************************************************/
const onMessage = function(msg) { const messaging = vAPI.messaging;
vAPI.broadcastListener.add(msg => {
switch ( msg.what ) { switch ( msg.what ) {
case 'assetUpdated': case 'assetUpdated':
updateAssetStatus(msg); updateAssetStatus(msg);
@ -53,10 +55,7 @@ const onMessage = function(msg) {
default: default:
break; break;
} }
}; });
const messaging = vAPI.messaging;
messaging.addChannelListener('dashboard', onMessage);
/******************************************************************************/ /******************************************************************************/

View File

@ -817,8 +817,9 @@ FilterContainer.prototype.pruneSelectorCacheAsync = function() {
/******************************************************************************/ /******************************************************************************/
FilterContainer.prototype.randomAlphaToken = function() { FilterContainer.prototype.randomAlphaToken = function() {
return String.fromCharCode(Date.now() % 26 + 97) + const now = Date.now();
Math.floor(Math.random() * 982451653 + 982451653).toString(36); return String.fromCharCode(now % 26 + 97) +
Math.floor((1 + Math.random()) * now).toString(36);
}; };
/******************************************************************************/ /******************************************************************************/

View File

@ -55,9 +55,10 @@ var filterToIdMap = new Map();
/******************************************************************************/ /******************************************************************************/
var messaging = vAPI.messaging; const messaging = vAPI.messaging;
messaging.addChannelListener('loggerUI', function(msg) { vAPI.MessagingConnection.addListener(function(msg) {
if ( msg.from !== 'domInspector' || msg.to !== 'loggerUI' ) { return; }
switch ( msg.what ) { switch ( msg.what ) {
case 'connectionBroken': case 'connectionBroken':
if ( inspectorConnectionId === msg.id ) { if ( inspectorConnectionId === msg.id ) {
@ -77,12 +78,8 @@ messaging.addChannelListener('loggerUI', function(msg) {
} }
break; break;
case 'connectionRequested': case 'connectionRequested':
if ( msg.from !== 'domInspector' ) { return false; } if ( msg.tabId === undefined || msg.tabId !== inspectedTabId ) {
if ( return;
msg.tabId === undefined ||
msg.tabId !== inspectedTabId
) {
return false;
} }
filterToIdMap.clear(); filterToIdMap.clear();
logger.removeAllChildren(domTree); logger.removeAllChildren(domTree);
@ -93,7 +90,7 @@ messaging.addChannelListener('loggerUI', function(msg) {
/******************************************************************************/ /******************************************************************************/
var nodeFromDomEntry = function(entry) { const nodeFromDomEntry = function(entry) {
var node, value; var node, value;
var li = document.createElement('li'); var li = document.createElement('li');
li.setAttribute('id', entry.nid); li.setAttribute('id', entry.nid);
@ -130,25 +127,21 @@ var nodeFromDomEntry = function(entry) {
/******************************************************************************/ /******************************************************************************/
var appendListItem = function(ul, li) { const appendListItem = function(ul, li) {
ul.appendChild(li); ul.appendChild(li);
// Ancestor nodes of a node which is affected by a cosmetic filter will // Ancestor nodes of a node which is affected by a cosmetic filter will
// be marked as "containing cosmetic filters", for user convenience. // be marked as "containing cosmetic filters", for user convenience.
if ( li.classList.contains('isCosmeticHide') === false ) { if ( li.classList.contains('isCosmeticHide') === false ) { return; }
return;
}
for (;;) { for (;;) {
li = li.parentElement.parentElement; li = li.parentElement.parentElement;
if ( li === null ) { if ( li === null ) { break; }
break;
}
li.classList.add('hasCosmeticHide'); li.classList.add('hasCosmeticHide');
} }
}; };
/******************************************************************************/ /******************************************************************************/
var renderDOMFull = function(response) { const renderDOMFull = function(response) {
var domTreeParent = domTree.parentElement; var domTreeParent = domTree.parentElement;
var ul = domTreeParent.removeChild(domTree); var ul = domTreeParent.removeChild(domTree);
logger.removeAllChildren(domTree); logger.removeAllChildren(domTree);
@ -197,7 +190,7 @@ var renderDOMFull = function(response) {
/******************************************************************************/ /******************************************************************************/
var patchIncremental = function(from, delta) { const patchIncremental = function(from, delta) {
var span, cnt; var span, cnt;
var li = from.parentElement.parentElement; var li = from.parentElement.parentElement;
var patchCosmeticHide = delta >= 0 && var patchCosmeticHide = delta >= 0 &&
@ -222,7 +215,7 @@ var patchIncremental = function(from, delta) {
/******************************************************************************/ /******************************************************************************/
var renderDOMIncremental = function(response) { const renderDOMIncremental = function(response) {
// Process each journal entry: // Process each journal entry:
// 1 = node added // 1 = node added
// -1 = node removed // -1 = node removed
@ -284,7 +277,7 @@ var renderDOMIncremental = function(response) {
/******************************************************************************/ /******************************************************************************/
var countFromNode = function(li) { const countFromNode = function(li) {
var span = li.children[2]; var span = li.children[2];
var cnt = parseInt(span.getAttribute('data-cnt'), 10); var cnt = parseInt(span.getAttribute('data-cnt'), 10);
return isNaN(cnt) ? 0 : cnt; return isNaN(cnt) ? 0 : cnt;
@ -292,7 +285,7 @@ var countFromNode = function(li) {
/******************************************************************************/ /******************************************************************************/
var selectorFromNode = function(node) { const selectorFromNode = function(node) {
var selector = ''; var selector = '';
var code; var code;
while ( node !== null ) { while ( node !== null ) {
@ -312,7 +305,7 @@ var selectorFromNode = function(node) {
/******************************************************************************/ /******************************************************************************/
var selectorFromFilter = function(node) { const selectorFromFilter = function(node) {
while ( node !== null ) { while ( node !== null ) {
if ( node.localName === 'li' ) { if ( node.localName === 'li' ) {
var code = node.querySelector('code:nth-of-type(2)'); var code = node.querySelector('code:nth-of-type(2)');
@ -327,7 +320,7 @@ var selectorFromFilter = function(node) {
/******************************************************************************/ /******************************************************************************/
var nidFromNode = function(node) { const nidFromNode = function(node) {
var li = node; var li = node;
while ( li !== null ) { while ( li !== null ) {
if ( li.localName === 'li' ) { if ( li.localName === 'li' ) {
@ -399,7 +392,7 @@ const startDialog = (function() {
}; };
const showCommitted = function() { const showCommitted = function() {
messaging.sendTo(inspectorConnectionId, { vAPI.MessagingConnection.sendTo(inspectorConnectionId, {
what: 'showCommitted', what: 'showCommitted',
hide: hideSelectors.join(',\n'), hide: hideSelectors.join(',\n'),
unhide: unhideSelectors.join(',\n') unhide: unhideSelectors.join(',\n')
@ -407,7 +400,7 @@ const startDialog = (function() {
}; };
const showInteractive = function() { const showInteractive = function() {
messaging.sendTo(inspectorConnectionId, { vAPI.MessagingConnection.sendTo(inspectorConnectionId, {
what: 'showInteractive', what: 'showInteractive',
hide: hideSelectors.join(',\n'), hide: hideSelectors.join(',\n'),
unhide: unhideSelectors.join(',\n') unhide: unhideSelectors.join(',\n')
@ -460,7 +453,7 @@ const startDialog = (function() {
/******************************************************************************/ /******************************************************************************/
var onClicked = function(ev) { const onClicked = function(ev) {
ev.stopPropagation(); ev.stopPropagation();
if ( inspectedTabId === 0 ) { return; } if ( inspectedTabId === 0 ) { return; }
@ -489,7 +482,7 @@ var onClicked = function(ev) {
// Toggle cosmetic filter // Toggle cosmetic filter
if ( target.classList.contains('filter') ) { if ( target.classList.contains('filter') ) {
messaging.sendTo(inspectorConnectionId, { vAPI.MessagingConnection.sendTo(inspectorConnectionId, {
what: 'toggleFilter', what: 'toggleFilter',
original: false, original: false,
target: target.classList.toggle('off'), target: target.classList.toggle('off'),
@ -504,7 +497,7 @@ var onClicked = function(ev) {
} }
// Toggle node // Toggle node
else { else {
messaging.sendTo(inspectorConnectionId, { vAPI.MessagingConnection.sendTo(inspectorConnectionId, {
what: 'toggleNodes', what: 'toggleNodes',
original: true, original: true,
target: target.classList.toggle('off') === false, target: target.classList.toggle('off') === false,
@ -520,13 +513,13 @@ var onClicked = function(ev) {
/******************************************************************************/ /******************************************************************************/
var onMouseOver = (function() { const onMouseOver = (function() {
var mouseoverTarget = null; var mouseoverTarget = null;
var mouseoverTimer = null; var mouseoverTimer = null;
var timerHandler = function() { var timerHandler = function() {
mouseoverTimer = null; mouseoverTimer = null;
messaging.sendTo(inspectorConnectionId, { vAPI.MessagingConnection.sendTo(inspectorConnectionId, {
what: 'highlightOne', what: 'highlightOne',
selector: selectorFromNode(mouseoverTarget), selector: selectorFromNode(mouseoverTarget),
nid: nidFromNode(mouseoverTarget), nid: nidFromNode(mouseoverTarget),
@ -574,9 +567,9 @@ const injectInspector = function() {
/******************************************************************************/ /******************************************************************************/
var shutdownInspector = function() { const shutdownInspector = function() {
if ( inspectorConnectionId !== undefined ) { if ( inspectorConnectionId !== undefined ) {
messaging.disconnectFrom(inspectorConnectionId); vAPI.MessagingConnection.disconnectFrom(inspectorConnectionId);
inspectorConnectionId = undefined; inspectorConnectionId = undefined;
} }
logger.removeAllChildren(domTree); logger.removeAllChildren(domTree);
@ -586,7 +579,7 @@ var shutdownInspector = function() {
/******************************************************************************/ /******************************************************************************/
var onTabIdChanged = function() { const onTabIdChanged = function() {
const tabId = currentTabId(); const tabId = currentTabId();
if ( tabId <= 0 ) { if ( tabId <= 0 ) {
return toggleOff(); return toggleOff();
@ -599,7 +592,7 @@ var onTabIdChanged = function() {
/******************************************************************************/ /******************************************************************************/
var toggleVCompactView = function() { const toggleVCompactView = function() {
var state = inspector.classList.toggle('vExpanded'); var state = inspector.classList.toggle('vExpanded');
var branches = document.querySelectorAll('#domInspector li.branch'); var branches = document.querySelectorAll('#domInspector li.branch');
for ( var branch of branches ) { for ( var branch of branches ) {
@ -607,14 +600,14 @@ var toggleVCompactView = function() {
} }
}; };
var toggleHCompactView = function() { const toggleHCompactView = function() {
inspector.classList.toggle('hCompact'); inspector.classList.toggle('hCompact');
}; };
/******************************************************************************/ /******************************************************************************/
/* /*
var toggleHighlightMode = function() { var toggleHighlightMode = function() {
messaging.sendTo(inspectorConnectionId, { vAPI.MessagingConnection.sendTo(inspectorConnectionId, {
what: 'highlightMode', what: 'highlightMode',
invert: uDom.nodeFromSelector('#domInspector .permatoolbar .highlightMode').classList.toggle('invert') invert: uDom.nodeFromSelector('#domInspector .permatoolbar .highlightMode').classList.toggle('invert')
}); });
@ -622,9 +615,12 @@ var toggleHighlightMode = function() {
*/ */
/******************************************************************************/ /******************************************************************************/
var revert = function() { const revert = function() {
uDom('#domTree .off').removeClass('off'); uDom('#domTree .off').removeClass('off');
messaging.sendTo(inspectorConnectionId, { what: 'resetToggledNodes' }); vAPI.MessagingConnection.sendTo(
inspectorConnectionId,
{ what: 'resetToggledNodes' }
);
inspector.querySelector('.permatoolbar .revert').classList.add('disabled'); inspector.querySelector('.permatoolbar .revert').classList.add('disabled');
inspector.querySelector('.permatoolbar .commit').classList.add('disabled'); inspector.querySelector('.permatoolbar .commit').classList.add('disabled');
}; };

View File

@ -24,6 +24,7 @@
/******************************************************************************/ /******************************************************************************/
(( ) => { (( ) => {
// >>>>>>>> start of private namespace
/******************************************************************************/ /******************************************************************************/
@ -295,21 +296,28 @@ const handlers = {
/******************************************************************************/ /******************************************************************************/
const onMessage = function(msg) { (async ( ) => {
if ( msg.what === 'loggerDisabled' ) { // Dynamically add broadcast listening abilities.
processTimer.clear(); if ( vAPI.broadcastListener instanceof Object === false ) {
attributeObserver.disconnect(); await vAPI.messaging.send('vapi', { what: 'extendClient' });
vAPI.domFilterer.removeListener(handlers);
vAPI.domWatcher.removeListener(handlers);
vAPI.messaging.removeChannelListener('domLogger', onMessage);
} }
}; const broadcastListener = msg => {
vAPI.messaging.addChannelListener('domLogger', onMessage); if ( msg.what === 'loggerDisabled' ) {
processTimer.clear();
attributeObserver.disconnect();
vAPI.domFilterer.removeListener(handlers);
vAPI.domWatcher.removeListener(handlers);
vAPI.broadcastListener.remove(broadcastListener);
}
};
vAPI.broadcastListener.add(broadcastListener);
})();
vAPI.domWatcher.addListener(handlers); vAPI.domWatcher.addListener(handlers);
/******************************************************************************/ /******************************************************************************/
// <<<<<<<< end of private namespace
})(); })();

View File

@ -19,18 +19,16 @@
Home: https://github.com/gorhill/uBlock Home: https://github.com/gorhill/uBlock
*/ */
/******************************************************************************/
/******************************************************************************/
(function() {
'use strict'; 'use strict';
/******************************************************************************/
/******************************************************************************/ /******************************************************************************/
if ( typeof vAPI !== 'object' || !vAPI.domFilterer ) { (( ) => {
return;
} /******************************************************************************/
if ( typeof vAPI !== 'object' || !vAPI.domFilterer ) { return; }
/******************************************************************************/ /******************************************************************************/
@ -49,7 +47,7 @@ if ( document.querySelector('iframe.dom-inspector.' + sessionId) !== null ) {
// Added serializeAsString parameter. // Added serializeAsString parameter.
/*! http://mths.be/cssescape v0.2.1 by @mathias | MIT license */ /*! http://mths.be/cssescape v0.2.1 by @mathias | MIT license */
var cssEscape = (function(/*root*/) { const cssEscape = (function(/*root*/) {
var InvalidCharacterError = function(message) { var InvalidCharacterError = function(message) {
this.message = message; this.message = message;
@ -137,29 +135,29 @@ var cssEscape = (function(/*root*/) {
/******************************************************************************/ /******************************************************************************/
/******************************************************************************/ /******************************************************************************/
var loggerConnectionId; let loggerConnectionId;
// Highlighter-related // Highlighter-related
var svgRoot = null; let svgRoot = null;
var pickerRoot = null; let pickerRoot = null;
var nodeToIdMap = new WeakMap(); // No need to iterate let nodeToIdMap = new WeakMap(); // No need to iterate
var blueNodes = []; let blueNodes = [];
var roRedNodes = new Map(); // node => current cosmetic filter const roRedNodes = new Map(); // node => current cosmetic filter
var rwRedNodes = new Set(); // node => new cosmetic filter (toggle node) const rwRedNodes = new Set(); // node => new cosmetic filter (toggle node)
//var roGreenNodes = new Map(); // node => current exception cosmetic filter (can't toggle) //var roGreenNodes = new Map(); // node => current exception cosmetic filter (can't toggle)
var rwGreenNodes = new Set(); // node => new exception cosmetic filter (toggle filter) const rwGreenNodes = new Set(); // node => new exception cosmetic filter (toggle filter)
var reHasCSSCombinators = /[ >+~]/; const reHasCSSCombinators = /[ >+~]/;
/******************************************************************************/ /******************************************************************************/
var domLayout = (function() { const domLayout = (function() {
var skipTagNames = new Set([ const skipTagNames = new Set([
'br', 'head', 'link', 'meta', 'script', 'style', 'title' 'br', 'head', 'link', 'meta', 'script', 'style', 'title'
]); ]);
var resourceAttrNames = new Map([ const resourceAttrNames = new Map([
[ 'a', 'href' ], [ 'a', 'href' ],
[ 'iframe', 'src' ], [ 'iframe', 'src' ],
[ 'img', 'src' ], [ 'img', 'src' ],
@ -170,13 +168,13 @@ var domLayout = (function() {
// This will be used to uniquely identify nodes across process. // This will be used to uniquely identify nodes across process.
var newNodeId = function(node) { const newNodeId = function(node) {
var nid = 'n' + (idGenerator++).toString(36); var nid = 'n' + (idGenerator++).toString(36);
nodeToIdMap.set(node, nid); nodeToIdMap.set(node, nid);
return nid; return nid;
}; };
var selectorFromNode = function(node) { const selectorFromNode = function(node) {
var str, attr, pos, sw, i; var str, attr, pos, sw, i;
var tag = node.localName; var tag = node.localName;
var selector = cssEscape(tag); var selector = cssEscape(tag);
@ -217,7 +215,7 @@ var domLayout = (function() {
return selector; return selector;
}; };
var DomRoot = function() { const DomRoot = function() {
this.nid = newNodeId(document.body); this.nid = newNodeId(document.body);
this.lvl = 0; this.lvl = 0;
this.sel = 'body'; this.sel = 'body';
@ -225,7 +223,7 @@ var domLayout = (function() {
this.filter = roRedNodes.get(document.body); this.filter = roRedNodes.get(document.body);
}; };
var DomNode = function(node, level) { const DomNode = function(node, level) {
this.nid = newNodeId(node); this.nid = newNodeId(node);
this.lvl = level; this.lvl = level;
this.sel = selectorFromNode(node); this.sel = selectorFromNode(node);
@ -233,7 +231,7 @@ var domLayout = (function() {
this.filter = roRedNodes.get(node); this.filter = roRedNodes.get(node);
}; };
var domNodeFactory = function(level, node) { const domNodeFactory = function(level, node) {
var localName = node.localName; var localName = node.localName;
if ( skipTagNames.has(localName) ) { return null; } if ( skipTagNames.has(localName) ) { return null; }
// skip uBlock's own nodes // skip uBlock's own nodes
@ -246,7 +244,7 @@ var domLayout = (function() {
// Collect layout data. // Collect layout data.
var getLayoutData = function() { const getLayoutData = function() {
var layout = []; var layout = [];
var stack = []; var stack = [];
var node = document.documentElement; var node = document.documentElement;
@ -282,7 +280,7 @@ var domLayout = (function() {
// Descendant count for each node. // Descendant count for each node.
var patchLayoutData = function(layout) { const patchLayoutData = function(layout) {
var stack = [], ptr; var stack = [], ptr;
var lvl = 0; var lvl = 0;
var domNode, cnt; var domNode, cnt;
@ -320,7 +318,7 @@ var domLayout = (function() {
var addedNodelists = []; var addedNodelists = [];
var removedNodelist = []; var removedNodelist = [];
var previousElementSiblingId = function(node) { const previousElementSiblingId = function(node) {
var sibling = node; var sibling = node;
for (;;) { for (;;) {
sibling = sibling.previousElementSibling; sibling = sibling.previousElementSibling;
@ -330,7 +328,7 @@ var domLayout = (function() {
} }
}; };
var journalFromBranch = function(root, newNodes, newNodeToIdMap) { const journalFromBranch = function(root, newNodes, newNodeToIdMap) {
var domNode; var domNode;
var node = root.firstElementChild; var node = root.firstElementChild;
while ( node !== null ) { while ( node !== null ) {
@ -361,7 +359,7 @@ var domLayout = (function() {
} }
}; };
var journalFromMutations = function() { const journalFromMutations = function() {
var nodelist, node, domNode, nid; var nodelist, node, domNode, nid;
mutationTimer = undefined; mutationTimer = undefined;
@ -408,7 +406,7 @@ var domLayout = (function() {
if ( journalEntries.length === 0 ) { return; } if ( journalEntries.length === 0 ) { return; }
vAPI.messaging.sendTo(loggerConnectionId, { vAPI.MessagingConnection.sendTo(loggerConnectionId, {
what: 'domLayoutIncremental', what: 'domLayoutIncremental',
url: window.location.href, url: window.location.href,
hostname: window.location.hostname, hostname: window.location.hostname,
@ -417,7 +415,7 @@ var domLayout = (function() {
}); });
}; };
var onMutationObserved = function(mutationRecords) { const onMutationObserved = function(mutationRecords) {
for ( var record of mutationRecords ) { for ( var record of mutationRecords ) {
if ( record.addedNodes.length !== 0 ) { if ( record.addedNodes.length !== 0 ) {
addedNodelists.push(record.addedNodes); addedNodelists.push(record.addedNodes);
@ -433,7 +431,7 @@ var domLayout = (function() {
// API // API
var getLayout = function() { const getLayout = function() {
cosmeticFilterMapper.reset(); cosmeticFilterMapper.reset();
mutationObserver = new MutationObserver(onMutationObserved); mutationObserver = new MutationObserver(onMutationObserved);
mutationObserver.observe(document.body, { mutationObserver.observe(document.body, {
@ -449,11 +447,11 @@ var domLayout = (function() {
}; };
}; };
var reset = function() { const reset = function() {
shutdown(); shutdown();
}; };
var shutdown = function() { const shutdown = function() {
if ( mutationTimer !== undefined ) { if ( mutationTimer !== undefined ) {
clearTimeout(mutationTimer); clearTimeout(mutationTimer);
mutationTimer = undefined; mutationTimer = undefined;
@ -482,7 +480,7 @@ var domLayout = (function() {
// For browsers not supporting `:scope`, it's not the end of the world: the // For browsers not supporting `:scope`, it's not the end of the world: the
// suggested CSS selectors may just end up being more verbose. // suggested CSS selectors may just end up being more verbose.
var cssScope = ':scope > '; let cssScope = ':scope > ';
try { try {
document.querySelector(':scope *'); document.querySelector(':scope *');
} catch (e) { } catch (e) {
@ -491,7 +489,7 @@ try {
/******************************************************************************/ /******************************************************************************/
var cosmeticFilterMapper = (function() { const cosmeticFilterMapper = (function() {
// https://github.com/gorhill/uBlock/issues/546 // https://github.com/gorhill/uBlock/issues/546
var matchesFnName; var matchesFnName;
if ( typeof document.body.matches === 'function' ) { if ( typeof document.body.matches === 'function' ) {
@ -502,7 +500,7 @@ var cosmeticFilterMapper = (function() {
matchesFnName = 'webkitMatchesSelector'; matchesFnName = 'webkitMatchesSelector';
} }
var nodesFromStyleTag = function(rootNode) { const nodesFromStyleTag = function(rootNode) {
var filterMap = roRedNodes, var filterMap = roRedNodes,
entry, selector, canonical, nodes, node; entry, selector, canonical, nodes, node;
@ -544,16 +542,16 @@ var cosmeticFilterMapper = (function() {
} }
}; };
var incremental = function(rootNode) { const incremental = function(rootNode) {
nodesFromStyleTag(rootNode); nodesFromStyleTag(rootNode);
}; };
var reset = function() { const reset = function() {
roRedNodes = new Map(); roRedNodes.clear();
incremental(document.documentElement); incremental(document.documentElement);
}; };
var shutdown = function() { const shutdown = function() {
vAPI.domFilterer.toggle(true); vAPI.domFilterer.toggle(true);
}; };
@ -566,26 +564,23 @@ var cosmeticFilterMapper = (function() {
/******************************************************************************/ /******************************************************************************/
var elementsFromSelector = function(selector, context) { const elementsFromSelector = function(selector, context) {
if ( !context ) { if ( !context ) {
context = document; context = document;
} }
var out;
if ( selector.indexOf(':') !== -1 ) { if ( selector.indexOf(':') !== -1 ) {
out = elementsFromSpecialSelector(selector); const out = elementsFromSpecialSelector(selector);
if ( out !== undefined ) { if ( out !== undefined ) { return out; }
return out;
}
} }
// plain CSS selector // plain CSS selector
try { try {
out = context.querySelectorAll(selector); return context.querySelectorAll(selector);
} catch (ex) { } catch (ex) {
} }
return out || []; return [];
}; };
var elementsFromSpecialSelector = function(selector) { const elementsFromSpecialSelector = function(selector) {
var out = [], i; var out = [], i;
var matches = /^(.+?):has\((.+?)\)$/.exec(selector); var matches = /^(.+?):has\((.+?)\)$/.exec(selector);
if ( matches !== null ) { if ( matches !== null ) {
@ -606,36 +601,35 @@ var elementsFromSpecialSelector = function(selector) {
} }
matches = /^:xpath\((.+?)\)$/.exec(selector); matches = /^:xpath\((.+?)\)$/.exec(selector);
if ( matches !== null ) { if ( matches === null ) { return; }
var xpr = document.evaluate( const xpr = document.evaluate(
matches[1], matches[1],
document, document,
null, null,
XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
null null
); );
i = xpr.snapshotLength; i = xpr.snapshotLength;
while ( i-- ) { while ( i-- ) {
out.push(xpr.snapshotItem(i)); out.push(xpr.snapshotItem(i));
}
return out;
} }
return out;
}; };
/******************************************************************************/ /******************************************************************************/
var getSvgRootChildren = function() { const getSvgRootChildren = function() {
if ( svgRoot.children ) { if ( svgRoot.children ) {
return svgRoot.children; return svgRoot.children;
} else { } else {
var childNodes = Array.prototype.slice.apply(svgRoot.childNodes); const childNodes = Array.prototype.slice.apply(svgRoot.childNodes);
return childNodes.filter(function(node) { return childNodes.filter(function(node) {
return node.nodeType === Node.ELEMENT_NODE; return node.nodeType === Node.ELEMENT_NODE;
}); });
} }
}; };
var highlightElements = function() { const highlightElements = function() {
var islands; var islands;
var elem, rect, poly; var elem, rect, poly;
var xl, xr, yt, yb, w, h, ws; var xl, xr, yt, yb, w, h, ws;
@ -729,9 +723,9 @@ var highlightElements = function() {
/******************************************************************************/ /******************************************************************************/
var onScrolled = (function() { const onScrolled = (function() {
var buffered = false; let buffered = false;
var timerHandler = function() { const timerHandler = function() {
buffered = false; buffered = false;
highlightElements(); highlightElements();
}; };
@ -745,10 +739,10 @@ var onScrolled = (function() {
/******************************************************************************/ /******************************************************************************/
var selectNodes = function(selector, nid) { const selectNodes = function(selector, nid) {
var nodes = elementsFromSelector(selector); const nodes = elementsFromSelector(selector);
if ( nid === '' ) { return nodes; } if ( nid === '' ) { return nodes; }
for ( var node of nodes ) { for ( const node of nodes ) {
if ( nodeToIdMap.get(node) === nid ) { if ( nodeToIdMap.get(node) === nid ) {
return [ node ]; return [ node ];
} }
@ -758,9 +752,9 @@ var selectNodes = function(selector, nid) {
/******************************************************************************/ /******************************************************************************/
var nodesFromFilter = function(selector) { const nodesFromFilter = function(selector) {
var out = []; const out = [];
for ( var entry of roRedNodes ) { for ( const entry of roRedNodes ) {
if ( entry[1] === selector ) { if ( entry[1] === selector ) {
out.push(entry[0]); out.push(entry[0]);
} }
@ -770,8 +764,8 @@ var nodesFromFilter = function(selector) {
/******************************************************************************/ /******************************************************************************/
var toggleExceptions = function(nodes, targetState) { const toggleExceptions = function(nodes, targetState) {
for ( var node of nodes ) { for ( const node of nodes ) {
if ( targetState ) { if ( targetState ) {
rwGreenNodes.add(node); rwGreenNodes.add(node);
} else { } else {
@ -780,8 +774,8 @@ var toggleExceptions = function(nodes, targetState) {
} }
}; };
var toggleFilter = function(nodes, targetState) { const toggleFilter = function(nodes, targetState) {
for ( var node of nodes ) { for ( const node of nodes ) {
if ( targetState ) { if ( targetState ) {
rwRedNodes.delete(node); rwRedNodes.delete(node);
} else { } else {
@ -790,21 +784,19 @@ var toggleFilter = function(nodes, targetState) {
} }
}; };
var resetToggledNodes = function() { const resetToggledNodes = function() {
rwGreenNodes.clear(); rwGreenNodes.clear();
rwRedNodes.clear(); rwRedNodes.clear();
}; };
// https://www.youtube.com/watch?v=L5jRewnxSBY
/******************************************************************************/ /******************************************************************************/
var start = function() { const start = function() {
var onReady = function(ev) { const onReady = function(ev) {
if ( ev ) { if ( ev ) {
document.removeEventListener(ev.type, onReady); document.removeEventListener(ev.type, onReady);
} }
vAPI.messaging.sendTo(loggerConnectionId, domLayout.get()); vAPI.MessagingConnection.sendTo(loggerConnectionId, domLayout.get());
vAPI.domFilterer.toggle(false, highlightElements); vAPI.domFilterer.toggle(false, highlightElements);
}; };
if ( document.readyState === 'loading' ) { if ( document.readyState === 'loading' ) {
@ -816,10 +808,10 @@ var start = function() {
/******************************************************************************/ /******************************************************************************/
var shutdown = function() { const shutdown = function() {
cosmeticFilterMapper.shutdown(); cosmeticFilterMapper.shutdown();
domLayout.shutdown(); domLayout.shutdown();
vAPI.messaging.disconnectFrom(loggerConnectionId); vAPI.MessagingConnection.disconnectFrom(loggerConnectionId);
window.removeEventListener('scroll', onScrolled, true); window.removeEventListener('scroll', onScrolled, true);
document.documentElement.removeChild(pickerRoot); document.documentElement.removeChild(pickerRoot);
pickerRoot = svgRoot = null; pickerRoot = svgRoot = null;
@ -828,7 +820,7 @@ var shutdown = function() {
/******************************************************************************/ /******************************************************************************/
/******************************************************************************/ /******************************************************************************/
var onMessage = function(request) { const onMessage = function(request) {
var response, var response,
nodes; nodes;
@ -888,32 +880,17 @@ var onMessage = function(request) {
return response; return response;
}; };
var messagingHandler = function(msg) {
switch ( msg.what ) {
case 'connectionAccepted':
loggerConnectionId = msg.id;
start();
break;
case 'connectionBroken':
shutdown();
break;
case 'connectionMessage':
onMessage(msg.payload);
break;
}
};
/******************************************************************************/ /******************************************************************************/
// Install DOM inspector widget // Install DOM inspector widget
var bootstrap = function(ev) { const bootstrap = async function(ev) {
if ( ev ) { if ( ev ) {
pickerRoot.removeEventListener(ev.type, bootstrap); pickerRoot.removeEventListener(ev.type, bootstrap);
} }
var pickerDoc = this.contentDocument; const pickerDoc = ev.target.contentDocument;
var style = pickerDoc.createElement('style'); const style = pickerDoc.createElement('style');
style.textContent = [ style.textContent = [
'body {', 'body {',
'background-color: transparent;', 'background-color: transparent;',
@ -955,7 +932,25 @@ var bootstrap = function(ev) {
window.addEventListener('scroll', onScrolled, true); window.addEventListener('scroll', onScrolled, true);
vAPI.messaging.connectTo('domInspector', 'loggerUI', messagingHandler); // Dynamically add direct connection abilities so that we can establish
// a direct, fast messaging connection to the logger.
if ( vAPI.MessagingConnection instanceof Function === false ) {
await vAPI.messaging.send('vapi', { what: 'extendClient' });
}
vAPI.MessagingConnection.connectTo('domInspector', 'loggerUI', msg => {
switch ( msg.what ) {
case 'connectionAccepted':
loggerConnectionId = msg.id;
start();
break;
case 'connectionBroken':
shutdown();
break;
case 'connectionMessage':
onMessage(msg.payload);
break;
}
});
}; };
pickerRoot = document.createElement('iframe'); pickerRoot = document.createElement('iframe');
@ -982,7 +977,7 @@ pickerRoot.style.cssText = [
'' ''
].join(' !important;\n'); ].join(' !important;\n');
pickerRoot.addEventListener('load', bootstrap); pickerRoot.addEventListener('load', ev => { bootstrap(ev); });
document.documentElement.appendChild(pickerRoot); document.documentElement.appendChild(pickerRoot);
/******************************************************************************/ /******************************************************************************/

View File

@ -205,6 +205,7 @@
<script src="js/vapi.js"></script> <script src="js/vapi.js"></script>
<script src="js/vapi-common.js"></script> <script src="js/vapi-common.js"></script>
<script src="js/vapi-client.js"></script> <script src="js/vapi-client.js"></script>
<script src="js/vapi-client-extra.js"></script>
<script src="js/udom.js"></script> <script src="js/udom.js"></script>
<script src="js/i18n.js"></script> <script src="js/i18n.js"></script>
<script src="js/logger-ui.js"></script> <script src="js/logger-ui.js"></script>