mirror of
https://github.com/gorhill/uBlock.git
synced 2024-11-10 09:07:54 +01: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:
parent
149b5cf59c
commit
87d0e456f1
10 changed files with 517 additions and 421 deletions
|
@ -939,10 +939,10 @@ vAPI.messaging = {
|
|||
switch ( msg.what ) {
|
||||
case 'connectionAccepted':
|
||||
case 'connectionRefused': {
|
||||
const { port: toPort } = this.ports.get(msg.fromToken);
|
||||
const toPort = this.ports.get(msg.fromToken);
|
||||
if ( toPort !== undefined ) {
|
||||
msg.tabId = tabId;
|
||||
toPort.postMessage(request);
|
||||
toPort.port.postMessage(request);
|
||||
} else {
|
||||
msg.what = 'connectionBroken';
|
||||
port.postMessage(request);
|
||||
|
@ -952,24 +952,32 @@ vAPI.messaging = {
|
|||
case 'connectionRequested':
|
||||
msg.tabId = tabId;
|
||||
for ( const { port: toPort } of this.ports.values() ) {
|
||||
if ( toPort === port ) { continue; }
|
||||
toPort.postMessage(request);
|
||||
}
|
||||
break;
|
||||
case 'connectionBroken':
|
||||
case 'connectionCheck':
|
||||
case 'connectionMessage': {
|
||||
const { port: toPort } = this.ports.get(
|
||||
const toPort = this.ports.get(
|
||||
port.name === msg.fromToken ? msg.toToken : msg.fromToken
|
||||
);
|
||||
if ( toPort !== undefined ) {
|
||||
msg.tabId = tabId;
|
||||
toPort.postMessage(request);
|
||||
toPort.port.postMessage(request);
|
||||
} else {
|
||||
msg.what = 'connectionBroken';
|
||||
port.postMessage(request);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'extendClient':
|
||||
vAPI.tabs.executeScript(tabId, {
|
||||
file: '/js/vapi-client-extra.js',
|
||||
}).then(( ) => {
|
||||
callback();
|
||||
});
|
||||
break;
|
||||
case 'userCSS':
|
||||
if ( tabId === undefined ) { break; }
|
||||
const details = {
|
||||
|
@ -1043,7 +1051,7 @@ vAPI.messaging = {
|
|||
}
|
||||
|
||||
// Content process to main process: framework handler.
|
||||
if ( request.channelName === 'vapi' ) {
|
||||
if ( request.channel === 'vapi' ) {
|
||||
this.onFrameworkMessage(request, port, callback);
|
||||
return;
|
||||
}
|
||||
|
@ -1052,7 +1060,7 @@ vAPI.messaging = {
|
|||
const fromDetails = this.ports.get(port.name);
|
||||
if ( fromDetails === undefined ) { return; }
|
||||
|
||||
const listenerDetails = this.listeners.get(request.channelName);
|
||||
const listenerDetails = this.listeners.get(request.channel);
|
||||
let r = this.UNHANDLED;
|
||||
if (
|
||||
(listenerDetails !== undefined) &&
|
||||
|
|
308
platform/chromium/vapi-client-extra.js
Normal file
308
platform/chromium/vapi-client-extra.js
Normal 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;
|
|
@ -30,16 +30,18 @@
|
|||
// Skip if already injected.
|
||||
|
||||
// >>>>>>>> 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() {
|
||||
return String.fromCharCode(Date.now() % 26 + 97) +
|
||||
Math.floor(Math.random() * 982451653 + 982451653).toString(36);
|
||||
const now = Date.now();
|
||||
return String.fromCharCode(now % 26 + 97) +
|
||||
Math.floor((1 + Math.random()) * now).toString(36);
|
||||
};
|
||||
|
||||
vAPI.sessionId = vAPI.randomToken();
|
||||
|
@ -77,121 +79,11 @@ vAPI.messaging = {
|
|||
port: null,
|
||||
portTimer: null,
|
||||
portTimerDelay: 10000,
|
||||
channels: new Map(),
|
||||
connections: new Map(),
|
||||
pending: new Map(),
|
||||
extensions: [],
|
||||
msgIdGenerator: 1,
|
||||
pending: new Map(),
|
||||
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() {
|
||||
this.shuttingDown = true;
|
||||
this.destroyPort();
|
||||
|
@ -212,14 +104,6 @@ vAPI.messaging = {
|
|||
messageListener: function(details) {
|
||||
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
|
||||
if ( details.msgId !== undefined ) {
|
||||
const resolver = this.pending.get(details.msgId);
|
||||
|
@ -230,53 +114,28 @@ vAPI.messaging = {
|
|||
}
|
||||
}
|
||||
|
||||
if ( details.channelName !== 'vapi' ) { return; }
|
||||
|
||||
// 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;
|
||||
}
|
||||
// Unhandled messages
|
||||
this.extensions.every(ext => ext.canProcessMessage(details) !== true);
|
||||
},
|
||||
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() {
|
||||
this.portTimer = null;
|
||||
if (
|
||||
this.port !== null &&
|
||||
this.channels.size === 0 &&
|
||||
this.connections.size === 0 &&
|
||||
this.pending.size === 0
|
||||
) {
|
||||
if ( this.port !== null && this.canDestroyPort() ) {
|
||||
return this.destroyPort();
|
||||
}
|
||||
this.portTimer = vAPI.setTimeout(this.portPollerBound, this.portTimerDelay);
|
||||
|
@ -296,13 +155,7 @@ vAPI.messaging = {
|
|||
port.onDisconnect.removeListener(this.disconnectListenerBound);
|
||||
this.port = null;
|
||||
}
|
||||
this.channels.clear();
|
||||
if ( this.connections.size !== 0 ) {
|
||||
for ( const connection of this.connections.values() ) {
|
||||
connection.receive({ what: 'connectionBroken' });
|
||||
}
|
||||
this.connections.clear();
|
||||
}
|
||||
this.mustDestroyPort();
|
||||
// service pending callbacks
|
||||
if ( this.pending.size !== 0 ) {
|
||||
const pending = this.pending;
|
||||
|
@ -347,7 +200,7 @@ vAPI.messaging = {
|
|||
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
|
||||
// the main process is no longer reachable: memory leaks and bad
|
||||
// performance become a risk -- especially for long-lived, dynamic
|
||||
|
@ -363,86 +216,12 @@ vAPI.messaging = {
|
|||
const promise = new Promise(resolve => {
|
||||
this.pending.set(msgId, resolve);
|
||||
});
|
||||
port.postMessage({ channelName, msgId, msg });
|
||||
port.postMessage({ channel, msgId, msg });
|
||||
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(function() {
|
||||
vAPI.shutdown.add(( ) => {
|
||||
vAPI.messaging.shutdown();
|
||||
window.vAPI = undefined;
|
||||
});
|
||||
|
|
|
@ -59,6 +59,7 @@
|
|||
<script src="js/vapi.js"></script>
|
||||
<script src="js/vapi-common.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/i18n.js"></script>
|
||||
<script src="js/dashboard-common.js"></script>
|
||||
|
|
|
@ -38,7 +38,9 @@ let hideUnusedSet = new Set();
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
const onMessage = function(msg) {
|
||||
const messaging = vAPI.messaging;
|
||||
|
||||
vAPI.broadcastListener.add(msg => {
|
||||
switch ( msg.what ) {
|
||||
case 'assetUpdated':
|
||||
updateAssetStatus(msg);
|
||||
|
@ -53,10 +55,7 @@ const onMessage = function(msg) {
|
|||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
const messaging = vAPI.messaging;
|
||||
messaging.addChannelListener('dashboard', onMessage);
|
||||
});
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
|
|
|
@ -817,8 +817,9 @@ FilterContainer.prototype.pruneSelectorCacheAsync = function() {
|
|||
/******************************************************************************/
|
||||
|
||||
FilterContainer.prototype.randomAlphaToken = function() {
|
||||
return String.fromCharCode(Date.now() % 26 + 97) +
|
||||
Math.floor(Math.random() * 982451653 + 982451653).toString(36);
|
||||
const now = Date.now();
|
||||
return String.fromCharCode(now % 26 + 97) +
|
||||
Math.floor((1 + Math.random()) * now).toString(36);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
|
|
@ -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 ) {
|
||||
case 'connectionBroken':
|
||||
if ( inspectorConnectionId === msg.id ) {
|
||||
|
@ -77,12 +78,8 @@ messaging.addChannelListener('loggerUI', function(msg) {
|
|||
}
|
||||
break;
|
||||
case 'connectionRequested':
|
||||
if ( msg.from !== 'domInspector' ) { return false; }
|
||||
if (
|
||||
msg.tabId === undefined ||
|
||||
msg.tabId !== inspectedTabId
|
||||
) {
|
||||
return false;
|
||||
if ( msg.tabId === undefined || msg.tabId !== inspectedTabId ) {
|
||||
return;
|
||||
}
|
||||
filterToIdMap.clear();
|
||||
logger.removeAllChildren(domTree);
|
||||
|
@ -93,7 +90,7 @@ messaging.addChannelListener('loggerUI', function(msg) {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
var nodeFromDomEntry = function(entry) {
|
||||
const nodeFromDomEntry = function(entry) {
|
||||
var node, value;
|
||||
var li = document.createElement('li');
|
||||
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);
|
||||
// Ancestor nodes of a node which is affected by a cosmetic filter will
|
||||
// be marked as "containing cosmetic filters", for user convenience.
|
||||
if ( li.classList.contains('isCosmeticHide') === false ) {
|
||||
return;
|
||||
}
|
||||
if ( li.classList.contains('isCosmeticHide') === false ) { return; }
|
||||
for (;;) {
|
||||
li = li.parentElement.parentElement;
|
||||
if ( li === null ) {
|
||||
break;
|
||||
}
|
||||
if ( li === null ) { break; }
|
||||
li.classList.add('hasCosmeticHide');
|
||||
}
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var renderDOMFull = function(response) {
|
||||
const renderDOMFull = function(response) {
|
||||
var domTreeParent = domTree.parentElement;
|
||||
var ul = domTreeParent.removeChild(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 li = from.parentElement.parentElement;
|
||||
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:
|
||||
// 1 = node added
|
||||
// -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 cnt = parseInt(span.getAttribute('data-cnt'), 10);
|
||||
return isNaN(cnt) ? 0 : cnt;
|
||||
|
@ -292,7 +285,7 @@ var countFromNode = function(li) {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
var selectorFromNode = function(node) {
|
||||
const selectorFromNode = function(node) {
|
||||
var selector = '';
|
||||
var code;
|
||||
while ( node !== null ) {
|
||||
|
@ -312,7 +305,7 @@ var selectorFromNode = function(node) {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
var selectorFromFilter = function(node) {
|
||||
const selectorFromFilter = function(node) {
|
||||
while ( node !== null ) {
|
||||
if ( node.localName === 'li' ) {
|
||||
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;
|
||||
while ( li !== null ) {
|
||||
if ( li.localName === 'li' ) {
|
||||
|
@ -399,7 +392,7 @@ const startDialog = (function() {
|
|||
};
|
||||
|
||||
const showCommitted = function() {
|
||||
messaging.sendTo(inspectorConnectionId, {
|
||||
vAPI.MessagingConnection.sendTo(inspectorConnectionId, {
|
||||
what: 'showCommitted',
|
||||
hide: hideSelectors.join(',\n'),
|
||||
unhide: unhideSelectors.join(',\n')
|
||||
|
@ -407,7 +400,7 @@ const startDialog = (function() {
|
|||
};
|
||||
|
||||
const showInteractive = function() {
|
||||
messaging.sendTo(inspectorConnectionId, {
|
||||
vAPI.MessagingConnection.sendTo(inspectorConnectionId, {
|
||||
what: 'showInteractive',
|
||||
hide: hideSelectors.join(',\n'),
|
||||
unhide: unhideSelectors.join(',\n')
|
||||
|
@ -460,7 +453,7 @@ const startDialog = (function() {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
var onClicked = function(ev) {
|
||||
const onClicked = function(ev) {
|
||||
ev.stopPropagation();
|
||||
|
||||
if ( inspectedTabId === 0 ) { return; }
|
||||
|
@ -489,7 +482,7 @@ var onClicked = function(ev) {
|
|||
|
||||
// Toggle cosmetic filter
|
||||
if ( target.classList.contains('filter') ) {
|
||||
messaging.sendTo(inspectorConnectionId, {
|
||||
vAPI.MessagingConnection.sendTo(inspectorConnectionId, {
|
||||
what: 'toggleFilter',
|
||||
original: false,
|
||||
target: target.classList.toggle('off'),
|
||||
|
@ -504,7 +497,7 @@ var onClicked = function(ev) {
|
|||
}
|
||||
// Toggle node
|
||||
else {
|
||||
messaging.sendTo(inspectorConnectionId, {
|
||||
vAPI.MessagingConnection.sendTo(inspectorConnectionId, {
|
||||
what: 'toggleNodes',
|
||||
original: true,
|
||||
target: target.classList.toggle('off') === false,
|
||||
|
@ -520,13 +513,13 @@ var onClicked = function(ev) {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
var onMouseOver = (function() {
|
||||
const onMouseOver = (function() {
|
||||
var mouseoverTarget = null;
|
||||
var mouseoverTimer = null;
|
||||
|
||||
var timerHandler = function() {
|
||||
mouseoverTimer = null;
|
||||
messaging.sendTo(inspectorConnectionId, {
|
||||
vAPI.MessagingConnection.sendTo(inspectorConnectionId, {
|
||||
what: 'highlightOne',
|
||||
selector: selectorFromNode(mouseoverTarget),
|
||||
nid: nidFromNode(mouseoverTarget),
|
||||
|
@ -574,9 +567,9 @@ const injectInspector = function() {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
var shutdownInspector = function() {
|
||||
const shutdownInspector = function() {
|
||||
if ( inspectorConnectionId !== undefined ) {
|
||||
messaging.disconnectFrom(inspectorConnectionId);
|
||||
vAPI.MessagingConnection.disconnectFrom(inspectorConnectionId);
|
||||
inspectorConnectionId = undefined;
|
||||
}
|
||||
logger.removeAllChildren(domTree);
|
||||
|
@ -586,7 +579,7 @@ var shutdownInspector = function() {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
var onTabIdChanged = function() {
|
||||
const onTabIdChanged = function() {
|
||||
const tabId = currentTabId();
|
||||
if ( tabId <= 0 ) {
|
||||
return toggleOff();
|
||||
|
@ -599,7 +592,7 @@ var onTabIdChanged = function() {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
var toggleVCompactView = function() {
|
||||
const toggleVCompactView = function() {
|
||||
var state = inspector.classList.toggle('vExpanded');
|
||||
var branches = document.querySelectorAll('#domInspector li.branch');
|
||||
for ( var branch of branches ) {
|
||||
|
@ -607,14 +600,14 @@ var toggleVCompactView = function() {
|
|||
}
|
||||
};
|
||||
|
||||
var toggleHCompactView = function() {
|
||||
const toggleHCompactView = function() {
|
||||
inspector.classList.toggle('hCompact');
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
var toggleHighlightMode = function() {
|
||||
messaging.sendTo(inspectorConnectionId, {
|
||||
vAPI.MessagingConnection.sendTo(inspectorConnectionId, {
|
||||
what: 'highlightMode',
|
||||
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');
|
||||
messaging.sendTo(inspectorConnectionId, { what: 'resetToggledNodes' });
|
||||
vAPI.MessagingConnection.sendTo(
|
||||
inspectorConnectionId,
|
||||
{ what: 'resetToggledNodes' }
|
||||
);
|
||||
inspector.querySelector('.permatoolbar .revert').classList.add('disabled');
|
||||
inspector.querySelector('.permatoolbar .commit').classList.add('disabled');
|
||||
};
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
/******************************************************************************/
|
||||
|
||||
(( ) => {
|
||||
// >>>>>>>> start of private namespace
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
|
@ -295,21 +296,28 @@ const handlers = {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
const onMessage = function(msg) {
|
||||
if ( msg.what === 'loggerDisabled' ) {
|
||||
processTimer.clear();
|
||||
attributeObserver.disconnect();
|
||||
vAPI.domFilterer.removeListener(handlers);
|
||||
vAPI.domWatcher.removeListener(handlers);
|
||||
vAPI.messaging.removeChannelListener('domLogger', onMessage);
|
||||
(async ( ) => {
|
||||
// Dynamically add broadcast listening abilities.
|
||||
if ( vAPI.broadcastListener instanceof Object === false ) {
|
||||
await vAPI.messaging.send('vapi', { what: 'extendClient' });
|
||||
}
|
||||
};
|
||||
vAPI.messaging.addChannelListener('domLogger', onMessage);
|
||||
const broadcastListener = msg => {
|
||||
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);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// <<<<<<<< end of private namespace
|
||||
})();
|
||||
|
||||
|
||||
|
|
|
@ -19,18 +19,16 @@
|
|||
Home: https://github.com/gorhill/uBlock
|
||||
*/
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
(function() {
|
||||
|
||||
'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.
|
||||
|
||||
/*! http://mths.be/cssescape v0.2.1 by @mathias | MIT license */
|
||||
var cssEscape = (function(/*root*/) {
|
||||
const cssEscape = (function(/*root*/) {
|
||||
|
||||
var InvalidCharacterError = function(message) {
|
||||
this.message = message;
|
||||
|
@ -137,29 +135,29 @@ var cssEscape = (function(/*root*/) {
|
|||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
var loggerConnectionId;
|
||||
let loggerConnectionId;
|
||||
|
||||
// Highlighter-related
|
||||
var svgRoot = null;
|
||||
var pickerRoot = null;
|
||||
let svgRoot = null;
|
||||
let pickerRoot = null;
|
||||
|
||||
var nodeToIdMap = new WeakMap(); // No need to iterate
|
||||
let nodeToIdMap = new WeakMap(); // No need to iterate
|
||||
|
||||
var blueNodes = [];
|
||||
var roRedNodes = new Map(); // node => current cosmetic filter
|
||||
var rwRedNodes = new Set(); // node => new cosmetic filter (toggle node)
|
||||
let blueNodes = [];
|
||||
const roRedNodes = new Map(); // node => current cosmetic filter
|
||||
const rwRedNodes = new Set(); // node => new cosmetic filter (toggle node)
|
||||
//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() {
|
||||
var skipTagNames = new Set([
|
||||
const domLayout = (function() {
|
||||
const skipTagNames = new Set([
|
||||
'br', 'head', 'link', 'meta', 'script', 'style', 'title'
|
||||
]);
|
||||
var resourceAttrNames = new Map([
|
||||
const resourceAttrNames = new Map([
|
||||
[ 'a', 'href' ],
|
||||
[ 'iframe', 'src' ],
|
||||
[ 'img', 'src' ],
|
||||
|
@ -170,13 +168,13 @@ var domLayout = (function() {
|
|||
|
||||
// This will be used to uniquely identify nodes across process.
|
||||
|
||||
var newNodeId = function(node) {
|
||||
const newNodeId = function(node) {
|
||||
var nid = 'n' + (idGenerator++).toString(36);
|
||||
nodeToIdMap.set(node, nid);
|
||||
return nid;
|
||||
};
|
||||
|
||||
var selectorFromNode = function(node) {
|
||||
const selectorFromNode = function(node) {
|
||||
var str, attr, pos, sw, i;
|
||||
var tag = node.localName;
|
||||
var selector = cssEscape(tag);
|
||||
|
@ -217,7 +215,7 @@ var domLayout = (function() {
|
|||
return selector;
|
||||
};
|
||||
|
||||
var DomRoot = function() {
|
||||
const DomRoot = function() {
|
||||
this.nid = newNodeId(document.body);
|
||||
this.lvl = 0;
|
||||
this.sel = 'body';
|
||||
|
@ -225,7 +223,7 @@ var domLayout = (function() {
|
|||
this.filter = roRedNodes.get(document.body);
|
||||
};
|
||||
|
||||
var DomNode = function(node, level) {
|
||||
const DomNode = function(node, level) {
|
||||
this.nid = newNodeId(node);
|
||||
this.lvl = level;
|
||||
this.sel = selectorFromNode(node);
|
||||
|
@ -233,7 +231,7 @@ var domLayout = (function() {
|
|||
this.filter = roRedNodes.get(node);
|
||||
};
|
||||
|
||||
var domNodeFactory = function(level, node) {
|
||||
const domNodeFactory = function(level, node) {
|
||||
var localName = node.localName;
|
||||
if ( skipTagNames.has(localName) ) { return null; }
|
||||
// skip uBlock's own nodes
|
||||
|
@ -246,7 +244,7 @@ var domLayout = (function() {
|
|||
|
||||
// Collect layout data.
|
||||
|
||||
var getLayoutData = function() {
|
||||
const getLayoutData = function() {
|
||||
var layout = [];
|
||||
var stack = [];
|
||||
var node = document.documentElement;
|
||||
|
@ -282,7 +280,7 @@ var domLayout = (function() {
|
|||
|
||||
// Descendant count for each node.
|
||||
|
||||
var patchLayoutData = function(layout) {
|
||||
const patchLayoutData = function(layout) {
|
||||
var stack = [], ptr;
|
||||
var lvl = 0;
|
||||
var domNode, cnt;
|
||||
|
@ -320,7 +318,7 @@ var domLayout = (function() {
|
|||
var addedNodelists = [];
|
||||
var removedNodelist = [];
|
||||
|
||||
var previousElementSiblingId = function(node) {
|
||||
const previousElementSiblingId = function(node) {
|
||||
var sibling = node;
|
||||
for (;;) {
|
||||
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 node = root.firstElementChild;
|
||||
while ( node !== null ) {
|
||||
|
@ -361,7 +359,7 @@ var domLayout = (function() {
|
|||
}
|
||||
};
|
||||
|
||||
var journalFromMutations = function() {
|
||||
const journalFromMutations = function() {
|
||||
var nodelist, node, domNode, nid;
|
||||
mutationTimer = undefined;
|
||||
|
||||
|
@ -408,7 +406,7 @@ var domLayout = (function() {
|
|||
|
||||
if ( journalEntries.length === 0 ) { return; }
|
||||
|
||||
vAPI.messaging.sendTo(loggerConnectionId, {
|
||||
vAPI.MessagingConnection.sendTo(loggerConnectionId, {
|
||||
what: 'domLayoutIncremental',
|
||||
url: window.location.href,
|
||||
hostname: window.location.hostname,
|
||||
|
@ -417,7 +415,7 @@ var domLayout = (function() {
|
|||
});
|
||||
};
|
||||
|
||||
var onMutationObserved = function(mutationRecords) {
|
||||
const onMutationObserved = function(mutationRecords) {
|
||||
for ( var record of mutationRecords ) {
|
||||
if ( record.addedNodes.length !== 0 ) {
|
||||
addedNodelists.push(record.addedNodes);
|
||||
|
@ -433,7 +431,7 @@ var domLayout = (function() {
|
|||
|
||||
// API
|
||||
|
||||
var getLayout = function() {
|
||||
const getLayout = function() {
|
||||
cosmeticFilterMapper.reset();
|
||||
mutationObserver = new MutationObserver(onMutationObserved);
|
||||
mutationObserver.observe(document.body, {
|
||||
|
@ -449,11 +447,11 @@ var domLayout = (function() {
|
|||
};
|
||||
};
|
||||
|
||||
var reset = function() {
|
||||
const reset = function() {
|
||||
shutdown();
|
||||
};
|
||||
|
||||
var shutdown = function() {
|
||||
const shutdown = function() {
|
||||
if ( mutationTimer !== undefined ) {
|
||||
clearTimeout(mutationTimer);
|
||||
mutationTimer = undefined;
|
||||
|
@ -482,7 +480,7 @@ var domLayout = (function() {
|
|||
// For browsers not supporting `:scope`, it's not the end of the world: the
|
||||
// suggested CSS selectors may just end up being more verbose.
|
||||
|
||||
var cssScope = ':scope > ';
|
||||
let cssScope = ':scope > ';
|
||||
try {
|
||||
document.querySelector(':scope *');
|
||||
} catch (e) {
|
||||
|
@ -491,7 +489,7 @@ try {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
var cosmeticFilterMapper = (function() {
|
||||
const cosmeticFilterMapper = (function() {
|
||||
// https://github.com/gorhill/uBlock/issues/546
|
||||
var matchesFnName;
|
||||
if ( typeof document.body.matches === 'function' ) {
|
||||
|
@ -502,7 +500,7 @@ var cosmeticFilterMapper = (function() {
|
|||
matchesFnName = 'webkitMatchesSelector';
|
||||
}
|
||||
|
||||
var nodesFromStyleTag = function(rootNode) {
|
||||
const nodesFromStyleTag = function(rootNode) {
|
||||
var filterMap = roRedNodes,
|
||||
entry, selector, canonical, nodes, node;
|
||||
|
||||
|
@ -544,16 +542,16 @@ var cosmeticFilterMapper = (function() {
|
|||
}
|
||||
};
|
||||
|
||||
var incremental = function(rootNode) {
|
||||
const incremental = function(rootNode) {
|
||||
nodesFromStyleTag(rootNode);
|
||||
};
|
||||
|
||||
var reset = function() {
|
||||
roRedNodes = new Map();
|
||||
const reset = function() {
|
||||
roRedNodes.clear();
|
||||
incremental(document.documentElement);
|
||||
};
|
||||
|
||||
var shutdown = function() {
|
||||
const shutdown = function() {
|
||||
vAPI.domFilterer.toggle(true);
|
||||
};
|
||||
|
||||
|
@ -566,26 +564,23 @@ var cosmeticFilterMapper = (function() {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
var elementsFromSelector = function(selector, context) {
|
||||
const elementsFromSelector = function(selector, context) {
|
||||
if ( !context ) {
|
||||
context = document;
|
||||
}
|
||||
var out;
|
||||
if ( selector.indexOf(':') !== -1 ) {
|
||||
out = elementsFromSpecialSelector(selector);
|
||||
if ( out !== undefined ) {
|
||||
return out;
|
||||
}
|
||||
const out = elementsFromSpecialSelector(selector);
|
||||
if ( out !== undefined ) { return out; }
|
||||
}
|
||||
// plain CSS selector
|
||||
try {
|
||||
out = context.querySelectorAll(selector);
|
||||
return context.querySelectorAll(selector);
|
||||
} catch (ex) {
|
||||
}
|
||||
return out || [];
|
||||
return [];
|
||||
};
|
||||
|
||||
var elementsFromSpecialSelector = function(selector) {
|
||||
const elementsFromSpecialSelector = function(selector) {
|
||||
var out = [], i;
|
||||
var matches = /^(.+?):has\((.+?)\)$/.exec(selector);
|
||||
if ( matches !== null ) {
|
||||
|
@ -606,36 +601,35 @@ var elementsFromSpecialSelector = function(selector) {
|
|||
}
|
||||
|
||||
matches = /^:xpath\((.+?)\)$/.exec(selector);
|
||||
if ( matches !== null ) {
|
||||
var xpr = document.evaluate(
|
||||
matches[1],
|
||||
document,
|
||||
null,
|
||||
XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
|
||||
null
|
||||
);
|
||||
i = xpr.snapshotLength;
|
||||
while ( i-- ) {
|
||||
out.push(xpr.snapshotItem(i));
|
||||
}
|
||||
return out;
|
||||
if ( matches === null ) { return; }
|
||||
const xpr = document.evaluate(
|
||||
matches[1],
|
||||
document,
|
||||
null,
|
||||
XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
|
||||
null
|
||||
);
|
||||
i = xpr.snapshotLength;
|
||||
while ( i-- ) {
|
||||
out.push(xpr.snapshotItem(i));
|
||||
}
|
||||
return out;
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var getSvgRootChildren = function() {
|
||||
const getSvgRootChildren = function() {
|
||||
if ( svgRoot.children ) {
|
||||
return svgRoot.children;
|
||||
} else {
|
||||
var childNodes = Array.prototype.slice.apply(svgRoot.childNodes);
|
||||
const childNodes = Array.prototype.slice.apply(svgRoot.childNodes);
|
||||
return childNodes.filter(function(node) {
|
||||
return node.nodeType === Node.ELEMENT_NODE;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
var highlightElements = function() {
|
||||
const highlightElements = function() {
|
||||
var islands;
|
||||
var elem, rect, poly;
|
||||
var xl, xr, yt, yb, w, h, ws;
|
||||
|
@ -729,9 +723,9 @@ var highlightElements = function() {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
var onScrolled = (function() {
|
||||
var buffered = false;
|
||||
var timerHandler = function() {
|
||||
const onScrolled = (function() {
|
||||
let buffered = false;
|
||||
const timerHandler = function() {
|
||||
buffered = false;
|
||||
highlightElements();
|
||||
};
|
||||
|
@ -745,10 +739,10 @@ var onScrolled = (function() {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
var selectNodes = function(selector, nid) {
|
||||
var nodes = elementsFromSelector(selector);
|
||||
const selectNodes = function(selector, nid) {
|
||||
const nodes = elementsFromSelector(selector);
|
||||
if ( nid === '' ) { return nodes; }
|
||||
for ( var node of nodes ) {
|
||||
for ( const node of nodes ) {
|
||||
if ( nodeToIdMap.get(node) === nid ) {
|
||||
return [ node ];
|
||||
}
|
||||
|
@ -758,9 +752,9 @@ var selectNodes = function(selector, nid) {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
var nodesFromFilter = function(selector) {
|
||||
var out = [];
|
||||
for ( var entry of roRedNodes ) {
|
||||
const nodesFromFilter = function(selector) {
|
||||
const out = [];
|
||||
for ( const entry of roRedNodes ) {
|
||||
if ( entry[1] === selector ) {
|
||||
out.push(entry[0]);
|
||||
}
|
||||
|
@ -770,8 +764,8 @@ var nodesFromFilter = function(selector) {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
var toggleExceptions = function(nodes, targetState) {
|
||||
for ( var node of nodes ) {
|
||||
const toggleExceptions = function(nodes, targetState) {
|
||||
for ( const node of nodes ) {
|
||||
if ( targetState ) {
|
||||
rwGreenNodes.add(node);
|
||||
} else {
|
||||
|
@ -780,8 +774,8 @@ var toggleExceptions = function(nodes, targetState) {
|
|||
}
|
||||
};
|
||||
|
||||
var toggleFilter = function(nodes, targetState) {
|
||||
for ( var node of nodes ) {
|
||||
const toggleFilter = function(nodes, targetState) {
|
||||
for ( const node of nodes ) {
|
||||
if ( targetState ) {
|
||||
rwRedNodes.delete(node);
|
||||
} else {
|
||||
|
@ -790,21 +784,19 @@ var toggleFilter = function(nodes, targetState) {
|
|||
}
|
||||
};
|
||||
|
||||
var resetToggledNodes = function() {
|
||||
const resetToggledNodes = function() {
|
||||
rwGreenNodes.clear();
|
||||
rwRedNodes.clear();
|
||||
};
|
||||
|
||||
// https://www.youtube.com/watch?v=L5jRewnxSBY
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var start = function() {
|
||||
var onReady = function(ev) {
|
||||
const start = function() {
|
||||
const onReady = function(ev) {
|
||||
if ( ev ) {
|
||||
document.removeEventListener(ev.type, onReady);
|
||||
}
|
||||
vAPI.messaging.sendTo(loggerConnectionId, domLayout.get());
|
||||
vAPI.MessagingConnection.sendTo(loggerConnectionId, domLayout.get());
|
||||
vAPI.domFilterer.toggle(false, highlightElements);
|
||||
};
|
||||
if ( document.readyState === 'loading' ) {
|
||||
|
@ -816,10 +808,10 @@ var start = function() {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
var shutdown = function() {
|
||||
const shutdown = function() {
|
||||
cosmeticFilterMapper.shutdown();
|
||||
domLayout.shutdown();
|
||||
vAPI.messaging.disconnectFrom(loggerConnectionId);
|
||||
vAPI.MessagingConnection.disconnectFrom(loggerConnectionId);
|
||||
window.removeEventListener('scroll', onScrolled, true);
|
||||
document.documentElement.removeChild(pickerRoot);
|
||||
pickerRoot = svgRoot = null;
|
||||
|
@ -828,7 +820,7 @@ var shutdown = function() {
|
|||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
var onMessage = function(request) {
|
||||
const onMessage = function(request) {
|
||||
var response,
|
||||
nodes;
|
||||
|
||||
|
@ -888,32 +880,17 @@ var onMessage = function(request) {
|
|||
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
|
||||
|
||||
var bootstrap = function(ev) {
|
||||
const bootstrap = async function(ev) {
|
||||
if ( ev ) {
|
||||
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 = [
|
||||
'body {',
|
||||
'background-color: transparent;',
|
||||
|
@ -955,7 +932,25 @@ var bootstrap = function(ev) {
|
|||
|
||||
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');
|
||||
|
@ -982,7 +977,7 @@ pickerRoot.style.cssText = [
|
|||
''
|
||||
].join(' !important;\n');
|
||||
|
||||
pickerRoot.addEventListener('load', bootstrap);
|
||||
pickerRoot.addEventListener('load', ev => { bootstrap(ev); });
|
||||
document.documentElement.appendChild(pickerRoot);
|
||||
|
||||
/******************************************************************************/
|
||||
|
|
|
@ -205,6 +205,7 @@
|
|||
<script src="js/vapi.js"></script>
|
||||
<script src="js/vapi-common.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/i18n.js"></script>
|
||||
<script src="js/logger-ui.js"></script>
|
||||
|
|
Loading…
Reference in a new issue