mirror of
https://github.com/gorhill/uBlock.git
synced 2024-10-06 09:37:12 +02:00
some refactoring: move to-aux-process-messaging timeout into vAPI
This commit is contained in:
parent
957dea5289
commit
aeba71790f
@ -519,97 +519,159 @@ vAPI.messaging = {
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// This allows to avoid creating a closure for every single message which
|
||||
// expects an answer. Having a closure created each time a message is processed
|
||||
// has been always bothering me. Another benefit of the implementation here
|
||||
// is to reuse the callback proxy object, so less memory churning.
|
||||
//
|
||||
// https://developers.google.com/speed/articles/optimizing-javascript
|
||||
// "Creating a closure is significantly slower then creating an inner
|
||||
// function without a closure, and much slower than reusing a static
|
||||
// function"
|
||||
//
|
||||
// http://hacksoflife.blogspot.ca/2015/01/the-four-horsemen-of-performance.html
|
||||
// "the dreaded 'uniformly slow code' case where every function takes 1%
|
||||
// of CPU and you have to make one hundred separate performance optimizations
|
||||
// to improve performance at all"
|
||||
//
|
||||
// http://jsperf.com/closure-no-closure/2
|
||||
|
||||
var CallbackWrapper = function(port, request) {
|
||||
// No need to bind every single time
|
||||
this.callback = this.proxy.bind(this);
|
||||
this.messaging = vAPI.messaging;
|
||||
this.init(port, request);
|
||||
};
|
||||
|
||||
CallbackWrapper.junkyard = [];
|
||||
|
||||
CallbackWrapper.factory = function(port, request) {
|
||||
var wrapper = CallbackWrapper.junkyard.pop();
|
||||
if ( wrapper ) {
|
||||
wrapper.init(port, request);
|
||||
return wrapper;
|
||||
}
|
||||
return new CallbackWrapper(port, request);
|
||||
};
|
||||
|
||||
CallbackWrapper.prototype.init = function(port, request) {
|
||||
this.port = port;
|
||||
this.request = request;
|
||||
};
|
||||
|
||||
CallbackWrapper.prototype.proxy = function(response) {
|
||||
// https://github.com/chrisaljoudi/uBlock/issues/383
|
||||
if ( this.messaging.ports.hasOwnProperty(this.port.name) ) {
|
||||
this.port.postMessage({
|
||||
requestId: this.request.requestId,
|
||||
channelName: this.request.channelName,
|
||||
msg: response !== undefined ? response : null
|
||||
});
|
||||
}
|
||||
// Mark for reuse
|
||||
this.port = this.request = null;
|
||||
CallbackWrapper.junkyard.push(this);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
vAPI.messaging.listen = function(listenerName, callback) {
|
||||
this.listeners[listenerName] = callback;
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
vAPI.messaging.onPortMessage = function(request, port) {
|
||||
var callback = vAPI.messaging.NOOPFUNC;
|
||||
if ( request.requestId !== undefined ) {
|
||||
callback = CallbackWrapper.factory(port, request).callback;
|
||||
vAPI.messaging.onPortMessage = (function() {
|
||||
var messaging = vAPI.messaging;
|
||||
var toAuxPending = {};
|
||||
|
||||
// Use a wrapper to avoid closure and to allow reuse.
|
||||
var CallbackWrapper = function(port, request, timeout) {
|
||||
this.callback = this.proxy.bind(this); // bind once
|
||||
this.init(port, request, timeout);
|
||||
};
|
||||
|
||||
CallbackWrapper.prototype.init = function(port, request, timeout) {
|
||||
this.port = port;
|
||||
this.request = request;
|
||||
this.timerId = timeout !== undefined ?
|
||||
vAPI.setTimeout(this.callback, timeout) :
|
||||
null;
|
||||
return this;
|
||||
};
|
||||
|
||||
CallbackWrapper.prototype.proxy = function(response) {
|
||||
if ( this.timerId !== null ) {
|
||||
clearTimeout(this.timerId);
|
||||
delete toAuxPending[this.timerId];
|
||||
this.timerId = null;
|
||||
}
|
||||
// https://github.com/chrisaljoudi/uBlock/issues/383
|
||||
if ( messaging.ports.hasOwnProperty(this.port.name) ) {
|
||||
this.port.postMessage({
|
||||
auxProcessId: this.request.auxProcessId,
|
||||
channelName: this.request.channelName,
|
||||
msg: response !== undefined ? response : null
|
||||
});
|
||||
}
|
||||
// Mark for reuse
|
||||
this.port = this.request = null;
|
||||
callbackWrapperJunkyard.push(this);
|
||||
};
|
||||
|
||||
var callbackWrapperJunkyard = [];
|
||||
|
||||
var callbackWrapperFactory = function(port, request, timeout) {
|
||||
var wrapper = callbackWrapperJunkyard.pop();
|
||||
if ( wrapper ) {
|
||||
return wrapper.init(port, request, timeout);
|
||||
}
|
||||
return new CallbackWrapper(port, request, timeout);
|
||||
};
|
||||
|
||||
var toAux = function(details, portFrom) {
|
||||
var portTo;
|
||||
var chromiumTabId = toChromiumTabId(details.toTabId);
|
||||
|
||||
// TODO: This could be an issue with a lot of tabs: easy to address
|
||||
// with a port name to tab id map.
|
||||
for ( var portName in messaging.ports ) {
|
||||
if ( messaging.ports.hasOwnProperty(portName) === false ) {
|
||||
continue;
|
||||
}
|
||||
if ( messaging.ports[portName].sender.tab.id === chromiumTabId ) {
|
||||
portTo = messaging.ports[portName];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Specific handler
|
||||
var r = vAPI.messaging.UNHANDLED;
|
||||
var listener = vAPI.messaging.listeners[request.channelName];
|
||||
var wrapper;
|
||||
if ( details.auxProcessId !== undefined ) {
|
||||
wrapper = callbackWrapperFactory(portFrom, details, 1023);
|
||||
}
|
||||
|
||||
// Destination not found:
|
||||
if ( portTo === undefined ) {
|
||||
if ( wrapper !== undefined ) {
|
||||
wrapper.callback();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// As per HTML5, timer id is always an integer, thus suitable to be
|
||||
// used as a key, and which value is safe to use across process
|
||||
// boundaries.
|
||||
if ( wrapper !== undefined ) {
|
||||
toAuxPending[wrapper.timerId] = wrapper;
|
||||
}
|
||||
|
||||
portTo.postMessage({
|
||||
mainProcessId: wrapper && wrapper.timerId,
|
||||
channelName: details.toChannel,
|
||||
msg: details.msg
|
||||
});
|
||||
};
|
||||
|
||||
var toAuxResponse = function(details) {
|
||||
var mainProcessId = details.mainProcessId;
|
||||
if ( mainProcessId === undefined ) {
|
||||
return;
|
||||
}
|
||||
if ( toAuxPending.hasOwnProperty(mainProcessId) === false ) {
|
||||
return;
|
||||
}
|
||||
var wrapper = toAuxPending[mainProcessId];
|
||||
delete toAuxPending[mainProcessId];
|
||||
wrapper.callback(details.msg);
|
||||
};
|
||||
|
||||
return function(request, port) {
|
||||
// Auxiliary process to auxiliary process
|
||||
if ( request.toTabId !== undefined ) {
|
||||
toAux(request, port);
|
||||
return;
|
||||
}
|
||||
|
||||
// Auxiliary process to auxiliary process: response
|
||||
if ( request.mainProcessId !== undefined ) {
|
||||
toAuxResponse(request);
|
||||
return;
|
||||
}
|
||||
|
||||
// Auxiliary process to main process: prepare response
|
||||
var callback = messaging.NOOPFUNC;
|
||||
if ( request.auxProcessId !== undefined ) {
|
||||
callback = callbackWrapperFactory(port, request).callback;
|
||||
}
|
||||
|
||||
// Auxiliary process to main process: specific handler
|
||||
var r = messaging.UNHANDLED;
|
||||
var listener = messaging.listeners[request.channelName];
|
||||
if ( typeof listener === 'function' ) {
|
||||
r = listener(request.msg, port.sender, callback);
|
||||
}
|
||||
if ( r !== vAPI.messaging.UNHANDLED ) {
|
||||
if ( r !== messaging.UNHANDLED ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Default handler
|
||||
r = vAPI.messaging.defaultHandler(request.msg, port.sender, callback);
|
||||
if ( r !== vAPI.messaging.UNHANDLED ) {
|
||||
// Auxiliary process to main process: default handler
|
||||
r = messaging.defaultHandler(request.msg, port.sender, callback);
|
||||
if ( r !== messaging.UNHANDLED ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Auxiliary process to main process: no handler
|
||||
console.error('uBlock> messaging > unknown request: %o', request);
|
||||
|
||||
// Unhandled:
|
||||
// Need to callback anyways in case caller expected an answer, or
|
||||
// else there is a memory leak on caller's side
|
||||
callback();
|
||||
};
|
||||
})();
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
@ -661,46 +723,6 @@ vAPI.messaging.broadcast = function(message) {
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// "Auxiliary process": any process other than main process.
|
||||
//
|
||||
// Main process to auxiliary processes messaging. The approach is that of
|
||||
// smoke-signal messaging, so emitters have to be ready to deal with no
|
||||
// response at all (i.e. use timeout where needed).
|
||||
//
|
||||
// Mandatory:
|
||||
// - receiverTabId: Which tab to send the message.
|
||||
// No target tab id means sends to all tabs.
|
||||
// - receiverChannel: Which channel to send the message.
|
||||
//
|
||||
// Optional:
|
||||
// - senderTabId: From which tab the message originates.
|
||||
// - senderChannel: From which channel the message originates.
|
||||
// These optional fields are useful for the target, and may be used
|
||||
// to send back a response to the sender.
|
||||
|
||||
vAPI.messaging.post = function(message) {
|
||||
var port;
|
||||
var chromiumTabId = toChromiumTabId(message.receiverTabId);
|
||||
for ( var portName in this.ports ) {
|
||||
if ( this.ports.hasOwnProperty(portName) === false ) {
|
||||
continue;
|
||||
}
|
||||
port = this.ports[portName];
|
||||
if ( chromiumTabId !== 0 && port.sender.tab.id !== chromiumTabId ) {
|
||||
continue;
|
||||
}
|
||||
port.postMessage({
|
||||
channelName: message.receiverChannel,
|
||||
msg: message
|
||||
});
|
||||
if ( chromiumTabId !== 0 ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
vAPI.net = {};
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -73,157 +73,11 @@ vAPI.shutdown = (function() {
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var MessagingListeners = function(callback) {
|
||||
this.listeners = [];
|
||||
if ( typeof callback === 'function' ) {
|
||||
this.listeners.push(callback);
|
||||
}
|
||||
};
|
||||
|
||||
MessagingListeners.prototype.add = function(callback) {
|
||||
if ( typeof callback !== 'function' ) {
|
||||
return;
|
||||
}
|
||||
if ( this.listeners.indexOf(callback) !== -1 ) {
|
||||
throw new Error('Duplicate listener.');
|
||||
}
|
||||
this.listeners.push(callback);
|
||||
};
|
||||
|
||||
MessagingListeners.prototype.remove = function(callback) {
|
||||
if ( typeof callback !== 'function' ) {
|
||||
return;
|
||||
}
|
||||
if ( this.listeners.indexOf(callback) === -1 ) {
|
||||
throw new Error('Listener not found.');
|
||||
}
|
||||
this.listeners.splice(this.listeners.indexOf(callback), 1);
|
||||
};
|
||||
|
||||
MessagingListeners.prototype.removeAll = function() {
|
||||
this.listeners = [];
|
||||
};
|
||||
|
||||
MessagingListeners.prototype.process = function(msg) {
|
||||
var listeners = this.listeners;
|
||||
var n = listeners.length;
|
||||
for ( var i = 0; i < n; i++ ) {
|
||||
listeners[i](msg);
|
||||
}
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var messagingConnector = function(response) {
|
||||
if ( !response ) {
|
||||
return;
|
||||
}
|
||||
|
||||
var messaging = vAPI.messaging;
|
||||
var channels = messaging.channels;
|
||||
var channel;
|
||||
|
||||
// Sent to all channels
|
||||
if ( response.broadcast === true && !response.channelName ) {
|
||||
for ( channel in channels ) {
|
||||
if ( channels[channel] instanceof MessagingChannel === false ) {
|
||||
continue;
|
||||
}
|
||||
channels[channel].listeners.process(response.msg);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Response to specific message previously sent
|
||||
if ( response.requestId ) {
|
||||
var listener = messaging.pending[response.requestId];
|
||||
delete messaging.pending[response.requestId];
|
||||
delete response.requestId; // TODO: why?
|
||||
if ( listener ) {
|
||||
listener(response.msg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Sent to a specific channel
|
||||
channel = channels[response.channelName];
|
||||
if ( channel instanceof MessagingChannel ) {
|
||||
channel.listeners.process(response.msg);
|
||||
}
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var MessagingChannel = function(name, callback) {
|
||||
this.channelName = name;
|
||||
this.listeners = new MessagingListeners(callback);
|
||||
this.refCount = 1;
|
||||
if ( typeof callback === 'function' ) {
|
||||
var messaging = vAPI.messaging;
|
||||
if ( messaging.port === null ) {
|
||||
messaging.setup();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
MessagingChannel.prototype.send = function(message, callback) {
|
||||
var messaging = vAPI.messaging;
|
||||
if ( messaging.port === null ) {
|
||||
messaging.setup();
|
||||
}
|
||||
var requestId;
|
||||
if ( callback ) {
|
||||
requestId = messaging.requestId++;
|
||||
messaging.pending[requestId] = callback;
|
||||
}
|
||||
messaging.port.postMessage({
|
||||
channelName: this.channelName,
|
||||
requestId: requestId,
|
||||
msg: message
|
||||
});
|
||||
};
|
||||
|
||||
MessagingChannel.prototype.close = function() {
|
||||
this.refCount -= 1;
|
||||
if ( this.refCount !== 0 ) {
|
||||
return;
|
||||
}
|
||||
var messaging = vAPI.messaging;
|
||||
delete messaging.channels[this.channelName];
|
||||
if ( Object.keys(messaging.channels).length === 0 ) {
|
||||
messaging.close();
|
||||
}
|
||||
};
|
||||
|
||||
MessagingChannel.prototype.addListener = function(callback) {
|
||||
if ( typeof callback !== 'function' ) {
|
||||
return;
|
||||
}
|
||||
this.listeners.add(callback);
|
||||
var messaging = vAPI.messaging;
|
||||
if ( messaging.port === null ) {
|
||||
messaging.setup();
|
||||
}
|
||||
};
|
||||
|
||||
MessagingChannel.prototype.removeListener = function(callback) {
|
||||
if ( typeof callback !== 'function' ) {
|
||||
return;
|
||||
}
|
||||
this.listeners.remove(callback);
|
||||
};
|
||||
|
||||
MessagingChannel.prototype.removeAllListeners = function() {
|
||||
this.listeners.removeAll();
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
vAPI.messaging = {
|
||||
port: null,
|
||||
channels: {},
|
||||
pending: {},
|
||||
requestId: 1,
|
||||
auxProcessId: 1,
|
||||
|
||||
setup: function() {
|
||||
this.port = chrome.runtime.connect({name: vAPI.sessionId});
|
||||
@ -258,6 +112,148 @@ vAPI.messaging = {
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var messagingConnector = function(details) {
|
||||
if ( !details ) {
|
||||
return;
|
||||
}
|
||||
|
||||
var messaging = vAPI.messaging;
|
||||
var channels = messaging.channels;
|
||||
var channel;
|
||||
|
||||
// Sent to all channels
|
||||
if ( details.broadcast === true && !details.channelName ) {
|
||||
for ( channel in channels ) {
|
||||
if ( channels[channel] instanceof MessagingChannel === false ) {
|
||||
continue;
|
||||
}
|
||||
channels[channel].sendToListeners(details.msg);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Response to specific message previously sent
|
||||
if ( details.auxProcessId ) {
|
||||
var listener = messaging.pending[details.auxProcessId];
|
||||
delete messaging.pending[details.auxProcessId];
|
||||
delete details.auxProcessId; // TODO: why?
|
||||
if ( listener ) {
|
||||
listener(details.msg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Sent to a specific channel
|
||||
var response;
|
||||
channel = channels[details.channelName];
|
||||
if ( channel instanceof MessagingChannel ) {
|
||||
response = channel.sendToListeners(details.msg);
|
||||
}
|
||||
|
||||
// Respond back if required
|
||||
if ( details.mainProcessId !== undefined ) {
|
||||
messaging.port.postMessage({
|
||||
mainProcessId: details.mainProcessId,
|
||||
msg: response
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var MessagingChannel = function(name, callback) {
|
||||
this.channelName = name;
|
||||
this.listeners = typeof callback === 'function' ? [callback] : [];
|
||||
this.refCount = 1;
|
||||
if ( typeof callback === 'function' ) {
|
||||
var messaging = vAPI.messaging;
|
||||
if ( messaging.port === null ) {
|
||||
messaging.setup();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
MessagingChannel.prototype.send = function(message, callback) {
|
||||
this.sendTo(message, undefined, undefined, callback);
|
||||
};
|
||||
|
||||
MessagingChannel.prototype.sendTo = function(message, toTabId, toChannel, callback) {
|
||||
var messaging = vAPI.messaging;
|
||||
if ( messaging.port === null ) {
|
||||
messaging.setup();
|
||||
}
|
||||
var auxProcessId;
|
||||
if ( callback ) {
|
||||
auxProcessId = messaging.auxProcessId++;
|
||||
messaging.pending[auxProcessId] = callback;
|
||||
}
|
||||
messaging.port.postMessage({
|
||||
channelName: this.channelName,
|
||||
auxProcessId: auxProcessId,
|
||||
toTabId: toTabId,
|
||||
toChannel: toChannel,
|
||||
msg: message
|
||||
});
|
||||
};
|
||||
|
||||
MessagingChannel.prototype.close = function() {
|
||||
this.refCount -= 1;
|
||||
if ( this.refCount !== 0 ) {
|
||||
return;
|
||||
}
|
||||
var messaging = vAPI.messaging;
|
||||
delete messaging.channels[this.channelName];
|
||||
if ( Object.keys(messaging.channels).length === 0 ) {
|
||||
messaging.close();
|
||||
}
|
||||
};
|
||||
|
||||
MessagingChannel.prototype.addListener = function(callback) {
|
||||
if ( typeof callback !== 'function' ) {
|
||||
return;
|
||||
}
|
||||
if ( this.listeners.indexOf(callback) !== -1 ) {
|
||||
throw new Error('Duplicate listener.');
|
||||
}
|
||||
this.listeners.push(callback);
|
||||
var messaging = vAPI.messaging;
|
||||
if ( messaging.port === null ) {
|
||||
messaging.setup();
|
||||
}
|
||||
};
|
||||
|
||||
MessagingChannel.prototype.removeListener = function(callback) {
|
||||
if ( typeof callback !== 'function' ) {
|
||||
return;
|
||||
}
|
||||
var pos = this.listeners.indexOf(callback);
|
||||
if ( pos === -1 ) {
|
||||
throw new Error('Listener not found.');
|
||||
}
|
||||
this.listeners.splice(pos, 1);
|
||||
};
|
||||
|
||||
MessagingChannel.prototype.removeAllListeners = function() {
|
||||
this.listeners = [];
|
||||
};
|
||||
|
||||
MessagingChannel.prototype.sendToListeners = function(msg) {
|
||||
var response;
|
||||
var listeners = this.listeners;
|
||||
for ( var i = 0, n = listeners.length; i < n; i++ ) {
|
||||
response = listeners[i](msg);
|
||||
if ( response !== undefined ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return response;
|
||||
};
|
||||
|
||||
// https://www.youtube.com/watch?v=rT5zCHn0tsg
|
||||
// https://www.youtube.com/watch?v=E-jS4e3zacI
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// No need to have vAPI client linger around after shutdown if
|
||||
// we are not a top window (because element picker can still
|
||||
// be injected in top window).
|
||||
|
@ -1149,12 +1149,152 @@ vAPI.messaging.listen = function(listenerName, callback) {
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
vAPI.messaging.onMessage = function({target, data}) {
|
||||
var messageManager = target.messageManager;
|
||||
vAPI.messaging.onMessage = (function() {
|
||||
var messaging = vAPI.messaging;
|
||||
var toAuxPending = {};
|
||||
|
||||
// Use a wrapper to avoid closure and to allow reuse.
|
||||
var CallbackWrapper = function(messageManager, channelName, listenerId, auxProcessId, timeout) {
|
||||
this.callback = this.proxy.bind(this); // bind once
|
||||
this.init(messageManager, listenerId, channelName, auxProcessId, timeout);
|
||||
};
|
||||
|
||||
CallbackWrapper.prototype.init = function(messageManager, listenerId, channelName, auxProcessId, timeout) {
|
||||
this.messageManager = messageManager;
|
||||
this.listenerId = listenerId;
|
||||
this.channelName = channelName;
|
||||
this.auxProcessId = auxProcessId;
|
||||
this.timerId = timeout !== undefined ?
|
||||
vAPI.setTimeout(this.callback, timeout) :
|
||||
null;
|
||||
return this;
|
||||
};
|
||||
|
||||
CallbackWrapper.prototype.proxy = function(response) {
|
||||
if ( this.timerId !== null ) {
|
||||
clearTimeout(this.timerId);
|
||||
delete toAuxPending[this.timerId];
|
||||
this.timerId = null;
|
||||
}
|
||||
var message = JSON.stringify({
|
||||
auxProcessId: this.auxProcessId,
|
||||
channelName: this.channelName,
|
||||
msg: response !== undefined ? response : null
|
||||
});
|
||||
|
||||
if ( this.messageManager.sendAsyncMessage ) {
|
||||
this.messageManager.sendAsyncMessage(this.listenerId, message);
|
||||
} else {
|
||||
this.messageManager.broadcastAsyncMessage(this.listenerId, message);
|
||||
}
|
||||
|
||||
// Mark for reuse
|
||||
this.messageManager =
|
||||
this.listenerId =
|
||||
this.channelName =
|
||||
this.auxProcessId = null;
|
||||
callbackWrapperJunkyard.push(this);
|
||||
};
|
||||
|
||||
var callbackWrapperJunkyard = [];
|
||||
|
||||
var callbackWrapperFactory = function(messageManager, listenerId, channelName, auxProcessId, timeout) {
|
||||
var wrapper = callbackWrapperJunkyard.pop();
|
||||
if ( wrapper ) {
|
||||
return wrapper.init(messageManager, listenerId, channelName, auxProcessId, timeout);
|
||||
}
|
||||
return new CallbackWrapper(messageManager, listenerId, channelName, auxProcessId, timeout);
|
||||
};
|
||||
|
||||
// "Auxiliary process": any process other than main process.
|
||||
var toAux = function(target, details) {
|
||||
var messageManagerFrom = target.messageManager;
|
||||
|
||||
if ( !messageManager ) {
|
||||
// Message came from a popup, and its message manager is not usable.
|
||||
// So instead we broadcast to the parent window.
|
||||
if ( !messageManagerFrom ) {
|
||||
messageManagerFrom = getOwnerWindow(
|
||||
target.webNavigation.QueryInterface(Ci.nsIDocShell).chromeEventHandler
|
||||
).messageManager;
|
||||
}
|
||||
|
||||
var wrapper;
|
||||
if ( details.auxProcessId !== undefined ) {
|
||||
var channelNameRaw = details.channelName;
|
||||
var pos = channelNameRaw.indexOf('|');
|
||||
wrapper = callbackWrapperFactory(
|
||||
messageManagerFrom,
|
||||
channelNameRaw.slice(0, pos),
|
||||
channelNameRaw.slice(pos + 1),
|
||||
details.auxProcessId,
|
||||
1023
|
||||
);
|
||||
}
|
||||
|
||||
var messageManagerTo = null;
|
||||
var browser = tabWatcher.browserFromTabId(details.toTabId);
|
||||
if ( browser !== null && browser.messageManager ) {
|
||||
messageManagerTo = browser.messageManager;
|
||||
}
|
||||
if ( messageManagerTo === null ) {
|
||||
if ( wrapper !== undefined ) {
|
||||
wrapper.callback();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// As per HTML5, timer id is always an integer, thus suitable to be used
|
||||
// as a key, and which value is safe to use across process boundaries.
|
||||
if ( wrapper !== undefined ) {
|
||||
toAuxPending[wrapper.timerId] = wrapper;
|
||||
}
|
||||
|
||||
var targetId = location.host + ':broadcast';
|
||||
var payload = JSON.stringify({
|
||||
mainProcessId: wrapper && wrapper.timerId,
|
||||
channelName: details.toChannel,
|
||||
msg: details.msg
|
||||
});
|
||||
|
||||
if ( messageManagerTo.sendAsyncMessage ) {
|
||||
messageManagerTo.sendAsyncMessage(targetId, payload);
|
||||
} else {
|
||||
messageManagerTo.broadcastAsyncMessage(targetId, payload);
|
||||
}
|
||||
};
|
||||
|
||||
var toAuxResponse = function(details) {
|
||||
var mainProcessId = details.mainProcessId;
|
||||
if ( mainProcessId === undefined ) {
|
||||
return;
|
||||
}
|
||||
if ( toAuxPending.hasOwnProperty(mainProcessId) === false ) {
|
||||
return;
|
||||
}
|
||||
var wrapper = toAuxPending[mainProcessId];
|
||||
delete toAuxPending[mainProcessId];
|
||||
wrapper.callback(details.msg);
|
||||
};
|
||||
|
||||
return function({target, data}) {
|
||||
// Auxiliary process to auxiliary process
|
||||
if ( data.toTabId !== undefined ) {
|
||||
toAux(target, data);
|
||||
return;
|
||||
}
|
||||
|
||||
// Auxiliary process to auxiliary process: response
|
||||
if ( data.mainProcessId !== undefined ) {
|
||||
toAuxResponse(data);
|
||||
return;
|
||||
}
|
||||
|
||||
// Auxiliary process to main process
|
||||
var messageManager = target.messageManager;
|
||||
|
||||
// Message came from a popup, and its message manager is not usable.
|
||||
// So instead we broadcast to the parent window.
|
||||
if ( !messageManager ) {
|
||||
messageManager = getOwnerWindow(
|
||||
target.webNavigation.QueryInterface(Ci.nsIDocShell).chromeEventHandler
|
||||
).messageManager;
|
||||
@ -1164,13 +1304,14 @@ vAPI.messaging.onMessage = function({target, data}) {
|
||||
var pos = channelNameRaw.indexOf('|');
|
||||
var channelName = channelNameRaw.slice(pos + 1);
|
||||
|
||||
var callback = vAPI.messaging.NOOPFUNC;
|
||||
if ( data.requestId !== undefined ) {
|
||||
callback = CallbackWrapper.factory(
|
||||
// Auxiliary process to main process: prepare response
|
||||
var callback = messaging.NOOPFUNC;
|
||||
if ( data.auxProcessId !== undefined ) {
|
||||
callback = callbackWrapperFactory(
|
||||
messageManager,
|
||||
channelName,
|
||||
channelNameRaw.slice(0, pos),
|
||||
data.requestId
|
||||
channelName,
|
||||
data.auxProcessId
|
||||
).callback;
|
||||
}
|
||||
|
||||
@ -1180,29 +1321,30 @@ vAPI.messaging.onMessage = function({target, data}) {
|
||||
}
|
||||
};
|
||||
|
||||
// Specific handler
|
||||
var r = vAPI.messaging.UNHANDLED;
|
||||
var listener = vAPI.messaging.listeners[channelName];
|
||||
// Auxiliary process to main process: specific handler
|
||||
var r = messaging.UNHANDLED;
|
||||
var listener = messaging.listeners[channelName];
|
||||
if ( typeof listener === 'function' ) {
|
||||
r = listener(data.msg, sender, callback);
|
||||
}
|
||||
if ( r !== vAPI.messaging.UNHANDLED ) {
|
||||
if ( r !== messaging.UNHANDLED ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Default handler
|
||||
r = vAPI.messaging.defaultHandler(data.msg, sender, callback);
|
||||
if ( r !== vAPI.messaging.UNHANDLED ) {
|
||||
// Auxiliary process to main process: default handler
|
||||
r = messaging.defaultHandler(data.msg, sender, callback);
|
||||
if ( r !== messaging.UNHANDLED ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Auxiliary process to main process: no handler
|
||||
console.error('uBlock> messaging > unknown request: %o', data);
|
||||
|
||||
// Unhandled:
|
||||
// Need to callback anyways in case caller expected an answer, or
|
||||
// else there is a memory leak on caller's side
|
||||
callback();
|
||||
};
|
||||
})();
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
@ -1239,55 +1381,6 @@ vAPI.messaging.setup = function(defaultHandler) {
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// "Auxiliary process": any process other than main process.
|
||||
//
|
||||
// Main process to auxiliary processes messaging. The approach is that of
|
||||
// smoke-signal messaging, so emitters have to be ready to deal with no
|
||||
// response at all (i.e. use timeout where needed).
|
||||
//
|
||||
// Mandatory:
|
||||
// - receiverTabId: Which tab to send the message.
|
||||
// No target tab id means sends to all tabs.
|
||||
// - receiverChannel: Which channel to send the message.
|
||||
//
|
||||
// Optional:
|
||||
// - senderTabId: From which tab the message originates.
|
||||
// - senderChannel: From which channel the message originates.
|
||||
// These optional fields are useful for the target, and may be used
|
||||
// to send back a response to the sender.
|
||||
|
||||
vAPI.messaging.post = function(message) {
|
||||
var ffTabId = message.receiverTabId || '';
|
||||
var targetId = location.host + ':broadcast';
|
||||
var payload = JSON.stringify({
|
||||
channelName: message.receiverChannel,
|
||||
msg: message
|
||||
});
|
||||
|
||||
if ( ffTabId === '' ) {
|
||||
this.globalMessageManager.broadcastAsyncMessage(targetId, payload);
|
||||
return;
|
||||
}
|
||||
|
||||
var browser = tabWatcher.browserFromTabId(ffTabId);
|
||||
if ( browser === null ) {
|
||||
return;
|
||||
}
|
||||
|
||||
var messageManager = browser.messageManager || null;
|
||||
if ( messageManager === null ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( messageManager.sendAsyncMessage ) {
|
||||
messageManager.sendAsyncMessage(targetId, payload);
|
||||
} else {
|
||||
messageManager.broadcastAsyncMessage(targetId, payload);
|
||||
}
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
vAPI.messaging.broadcast = function(message) {
|
||||
this.globalMessageManager.broadcastAsyncMessage(
|
||||
location.host + ':broadcast',
|
||||
@ -1297,69 +1390,6 @@ vAPI.messaging.broadcast = function(message) {
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// This allows to avoid creating a closure for every single message which
|
||||
// expects an answer. Having a closure created each time a message is processed
|
||||
// has been always bothering me. Another benefit of the implementation here
|
||||
// is to reuse the callback proxy object, so less memory churning.
|
||||
//
|
||||
// https://developers.google.com/speed/articles/optimizing-javascript
|
||||
// "Creating a closure is significantly slower then creating an inner
|
||||
// function without a closure, and much slower than reusing a static
|
||||
// function"
|
||||
//
|
||||
// http://hacksoflife.blogspot.ca/2015/01/the-four-horsemen-of-performance.html
|
||||
// "the dreaded 'uniformly slow code' case where every function takes 1%
|
||||
// of CPU and you have to make one hundred separate performance optimizations
|
||||
// to improve performance at all"
|
||||
//
|
||||
// http://jsperf.com/closure-no-closure/2
|
||||
|
||||
var CallbackWrapper = function(messageManager, channelName, listenerId, requestId) {
|
||||
this.callback = this.proxy.bind(this); // bind once
|
||||
this.init(messageManager, channelName, listenerId, requestId);
|
||||
};
|
||||
|
||||
CallbackWrapper.junkyard = [];
|
||||
|
||||
CallbackWrapper.factory = function(messageManager, channelName, listenerId, requestId) {
|
||||
var wrapper = CallbackWrapper.junkyard.pop();
|
||||
if ( wrapper ) {
|
||||
wrapper.init(messageManager, channelName, listenerId, requestId);
|
||||
return wrapper;
|
||||
}
|
||||
return new CallbackWrapper(messageManager, channelName, listenerId, requestId);
|
||||
};
|
||||
|
||||
CallbackWrapper.prototype.init = function(messageManager, channelName, listenerId, requestId) {
|
||||
this.messageManager = messageManager;
|
||||
this.channelName = channelName;
|
||||
this.listenerId = listenerId;
|
||||
this.requestId = requestId;
|
||||
};
|
||||
|
||||
CallbackWrapper.prototype.proxy = function(response) {
|
||||
var message = JSON.stringify({
|
||||
requestId: this.requestId,
|
||||
channelName: this.channelName,
|
||||
msg: response !== undefined ? response : null
|
||||
});
|
||||
|
||||
if ( this.messageManager.sendAsyncMessage ) {
|
||||
this.messageManager.sendAsyncMessage(this.listenerId, message);
|
||||
} else {
|
||||
this.messageManager.broadcastAsyncMessage(this.listenerId, message);
|
||||
}
|
||||
|
||||
// Mark for reuse
|
||||
this.messageManager =
|
||||
this.channelName =
|
||||
this.requestId =
|
||||
this.listenerId = null;
|
||||
CallbackWrapper.junkyard.push(this);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var httpObserver = {
|
||||
classDescription: 'net-channel-event-sinks for ' + location.host,
|
||||
classID: Components.ID('{dc8d6319-5f6e-4438-999e-53722db99e84}'),
|
||||
|
@ -67,152 +67,10 @@ vAPI.shutdown = (function() {
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var MessagingListeners = function(callback) {
|
||||
this.listeners = [];
|
||||
if ( typeof callback === 'function' ) {
|
||||
this.listeners.push(callback);
|
||||
}
|
||||
};
|
||||
|
||||
MessagingListeners.prototype.add = function(callback) {
|
||||
if ( typeof callback !== 'function' ) {
|
||||
return;
|
||||
}
|
||||
if ( this.listeners.indexOf(callback) !== -1 ) {
|
||||
throw new Error('Duplicate listener.');
|
||||
}
|
||||
this.listeners.push(callback);
|
||||
};
|
||||
|
||||
MessagingListeners.prototype.remove = function(callback) {
|
||||
if ( typeof callback !== 'function' ) {
|
||||
return;
|
||||
}
|
||||
if ( this.listeners.indexOf(callback) === -1 ) {
|
||||
throw new Error('Listener not found.');
|
||||
}
|
||||
this.listeners.splice(this.listeners.indexOf(callback), 1);
|
||||
};
|
||||
|
||||
MessagingListeners.prototype.removeAll = function() {
|
||||
this.listeners = [];
|
||||
};
|
||||
|
||||
MessagingListeners.prototype.process = function(msg) {
|
||||
var listeners = this.listeners;
|
||||
var n = listeners.length;
|
||||
for ( var i = 0; i < n; i++ ) {
|
||||
listeners[i](msg);
|
||||
}
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var messagingConnector = function(response) {
|
||||
if ( !response ) {
|
||||
return;
|
||||
}
|
||||
|
||||
var messaging = vAPI.messaging;
|
||||
var channels = messaging.channels;
|
||||
var channel;
|
||||
|
||||
// Sent to all channels
|
||||
if ( response.broadcast === true && !response.channelName ) {
|
||||
for ( channel in channels ) {
|
||||
if ( channels[channel] instanceof MessagingChannel === false ) {
|
||||
continue;
|
||||
}
|
||||
channels[channel].listeners.process(response.msg);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Response to specific message previously sent
|
||||
if ( response.requestId ) {
|
||||
var listener = messaging.pending[response.requestId];
|
||||
delete messaging.pending[response.requestId];
|
||||
delete response.requestId; // TODO: why?
|
||||
if ( listener ) {
|
||||
listener(response.msg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Sent to a specific channel
|
||||
channel = channels[response.channelName];
|
||||
if ( channel instanceof MessagingChannel ) {
|
||||
channel.listeners.process(response.msg);
|
||||
}
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var MessagingChannel = function(name, callback) {
|
||||
this.channelName = name;
|
||||
this.listeners = new MessagingListeners(callback);
|
||||
this.refCount = 1;
|
||||
if ( typeof callback === 'function' ) {
|
||||
var messaging = vAPI.messaging;
|
||||
if ( !messaging.connected ) {
|
||||
messaging.setup();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
MessagingChannel.prototype.send = function(message, callback) {
|
||||
var messaging = vAPI.messaging;
|
||||
if ( !messaging.connected ) {
|
||||
messaging.setup();
|
||||
}
|
||||
var requestId;
|
||||
if ( callback ) {
|
||||
requestId = messaging.requestId++;
|
||||
messaging.pending[requestId] = callback;
|
||||
}
|
||||
sendAsyncMessage('ublock0:background', {
|
||||
channelName: self._sandboxId_ + '|' + this.channelName,
|
||||
requestId: requestId,
|
||||
msg: message
|
||||
});
|
||||
};
|
||||
|
||||
MessagingChannel.prototype.close = function() {
|
||||
this.refCount -= 1;
|
||||
if ( this.refCount !== 0 ) {
|
||||
return;
|
||||
}
|
||||
delete vAPI.messaging.channels[this.channelName];
|
||||
};
|
||||
|
||||
MessagingChannel.prototype.addListener = function(callback) {
|
||||
if ( typeof callback !== 'function' ) {
|
||||
return;
|
||||
}
|
||||
this.listeners.add(callback);
|
||||
var messaging = vAPI.messaging;
|
||||
if ( !messaging.connected ) {
|
||||
messaging.setup();
|
||||
}
|
||||
};
|
||||
|
||||
MessagingChannel.prototype.removeListener = function(callback) {
|
||||
if ( typeof callback !== 'function' ) {
|
||||
return;
|
||||
}
|
||||
this.listeners.remove(callback);
|
||||
};
|
||||
|
||||
MessagingChannel.prototype.removeAllListeners = function() {
|
||||
this.listeners.removeAll();
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
vAPI.messaging = {
|
||||
channels: {},
|
||||
pending: {},
|
||||
requestId: 1,
|
||||
auxProcessId: 1,
|
||||
connected: false,
|
||||
connector: function(msg) {
|
||||
messagingConnector(JSON.parse(msg));
|
||||
@ -283,6 +141,143 @@ window.addEventListener('pageshow', vAPI.messaging.toggleListener, true);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var messagingConnector = function(details) {
|
||||
if ( !details ) {
|
||||
return;
|
||||
}
|
||||
|
||||
var messaging = vAPI.messaging;
|
||||
var channels = messaging.channels;
|
||||
var channel;
|
||||
|
||||
// Sent to all channels
|
||||
if ( details.broadcast === true && !details.channelName ) {
|
||||
for ( channel in channels ) {
|
||||
if ( channels[channel] instanceof MessagingChannel === false ) {
|
||||
continue;
|
||||
}
|
||||
channels[channel].sendToListeners(details.msg);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Response to specific message previously sent
|
||||
if ( details.auxProcessId ) {
|
||||
var listener = messaging.pending[details.auxProcessId];
|
||||
delete messaging.pending[details.auxProcessId];
|
||||
delete details.auxProcessId; // TODO: why?
|
||||
if ( listener ) {
|
||||
listener(details.msg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Sent to a specific channel
|
||||
var response;
|
||||
channel = channels[details.channelName];
|
||||
if ( channel instanceof MessagingChannel ) {
|
||||
response = channel.sendToListeners(details.msg);
|
||||
}
|
||||
|
||||
// Respond back if required
|
||||
if ( details.mainProcessId !== undefined ) {
|
||||
sendAsyncMessage('ublock0:background', {
|
||||
mainProcessId: details.mainProcessId,
|
||||
msg: response
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var MessagingChannel = function(name, callback) {
|
||||
this.channelName = name;
|
||||
this.listeners = typeof callback === 'function' ? [callback] : [];
|
||||
this.refCount = 1;
|
||||
if ( typeof callback === 'function' ) {
|
||||
var messaging = vAPI.messaging;
|
||||
if ( !messaging.connected ) {
|
||||
messaging.setup();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
MessagingChannel.prototype.send = function(message, callback) {
|
||||
this.sendTo(message, undefined, undefined, callback);
|
||||
};
|
||||
|
||||
MessagingChannel.prototype.sendTo = function(message, toTabId, toChannel, callback) {
|
||||
var messaging = vAPI.messaging;
|
||||
if ( !messaging.connected ) {
|
||||
messaging.setup();
|
||||
}
|
||||
var auxProcessId;
|
||||
if ( callback ) {
|
||||
auxProcessId = messaging.auxProcessId++;
|
||||
messaging.pending[auxProcessId] = callback;
|
||||
}
|
||||
sendAsyncMessage('ublock0:background', {
|
||||
channelName: self._sandboxId_ + '|' + this.channelName,
|
||||
auxProcessId: auxProcessId,
|
||||
toTabId: toTabId,
|
||||
toChannel: toChannel,
|
||||
msg: message
|
||||
});
|
||||
};
|
||||
|
||||
MessagingChannel.prototype.close = function() {
|
||||
this.refCount -= 1;
|
||||
if ( this.refCount !== 0 ) {
|
||||
return;
|
||||
}
|
||||
delete vAPI.messaging.channels[this.channelName];
|
||||
};
|
||||
|
||||
MessagingChannel.prototype.addListener = function(callback) {
|
||||
if ( typeof callback !== 'function' ) {
|
||||
return;
|
||||
}
|
||||
if ( this.listeners.indexOf(callback) !== -1 ) {
|
||||
throw new Error('Duplicate listener.');
|
||||
}
|
||||
this.listeners.push(callback);
|
||||
var messaging = vAPI.messaging;
|
||||
if ( !messaging.connected ) {
|
||||
messaging.setup();
|
||||
}
|
||||
};
|
||||
|
||||
MessagingChannel.prototype.removeListener = function(callback) {
|
||||
if ( typeof callback !== 'function' ) {
|
||||
return;
|
||||
}
|
||||
var pos = this.listeners.indexOf(callback);
|
||||
if ( pos === -1 ) {
|
||||
throw new Error('Listener not found.');
|
||||
}
|
||||
this.listeners.splice(pos, 1);
|
||||
};
|
||||
|
||||
MessagingChannel.prototype.removeAllListeners = function() {
|
||||
this.listeners = [];
|
||||
};
|
||||
|
||||
MessagingChannel.prototype.sendToListeners = function(msg) {
|
||||
var response;
|
||||
var listeners = this.listeners;
|
||||
for ( var i = 0, n = listeners.length; i < n; i++ ) {
|
||||
response = listeners[i](msg);
|
||||
if ( response !== undefined ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return response;
|
||||
};
|
||||
|
||||
// https://www.youtube.com/watch?v=Cg0cmhjdiLs
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// No need to have vAPI client linger around after shutdown if
|
||||
// we are not a top window (because element picker can still
|
||||
// be injected in top window).
|
||||
|
@ -142,6 +142,8 @@ var renderDOMFull = function(response) {
|
||||
inspector.appendChild(domTree);
|
||||
};
|
||||
|
||||
// https://www.youtube.com/watch?v=IDGNA83mxDo
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var patchIncremental = function(from, delta) {
|
||||
@ -229,6 +231,8 @@ var renderDOMIncremental = function(response) {
|
||||
}
|
||||
};
|
||||
|
||||
// https://www.youtube.com/watch?v=6u2KPtJB9h8
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var countFromNode = function(li) {
|
||||
@ -358,20 +362,17 @@ var onClick = function(ev) {
|
||||
// Toggle selector
|
||||
if ( target.localName === 'code' ) {
|
||||
var original = target.classList.contains('filter') === false;
|
||||
messager.send({
|
||||
what: 'postMessageTo',
|
||||
senderTabId: null,
|
||||
senderChannel: 'logger-ui.js',
|
||||
receiverTabId: inspectedTabId,
|
||||
receiverChannel: 'dom-inspector.js',
|
||||
msg: {
|
||||
messager.sendTo(
|
||||
{
|
||||
what: 'toggleNodes',
|
||||
original: original,
|
||||
target: original !== target.classList.toggle('off'),
|
||||
selector: selectorFromNode(target, original ? 1 : 2),
|
||||
nid: original ? nidFromNode(target) : ''
|
||||
}
|
||||
});
|
||||
},
|
||||
inspectedTabId,
|
||||
'dom-inspector.js'
|
||||
);
|
||||
var cantCreate = inspector.querySelector('#domTree .off') === null;
|
||||
inspector.querySelector('.permatoolbar .revert').classList.toggle('disabled', cantCreate);
|
||||
inspector.querySelector('.permatoolbar .commit').classList.toggle('disabled', cantCreate);
|
||||
@ -387,19 +388,16 @@ var onMouseOver = (function() {
|
||||
|
||||
var timerHandler = function() {
|
||||
mouseoverTimer = null;
|
||||
messager.send({
|
||||
what: 'postMessageTo',
|
||||
senderTabId: null,
|
||||
senderChannel: 'logger-ui.js',
|
||||
receiverTabId: inspectedTabId,
|
||||
receiverChannel: 'dom-inspector.js',
|
||||
msg: {
|
||||
messager.sendTo(
|
||||
{
|
||||
what: 'highlightOne',
|
||||
selector: selectorFromNode(mouseoverTarget),
|
||||
nid: nidFromNode(mouseoverTarget),
|
||||
scrollTo: true
|
||||
}
|
||||
});
|
||||
},
|
||||
inspectedTabId,
|
||||
'dom-inspector.js'
|
||||
);
|
||||
};
|
||||
|
||||
return function(ev) {
|
||||
@ -447,8 +445,8 @@ var cancelPollTimer = function() {
|
||||
/******************************************************************************/
|
||||
|
||||
var onDOMFetched = function(response) {
|
||||
if ( response === undefined || currentTabId() !== inspectedTabId ) {
|
||||
shutdownInspector(inspectedTabId);
|
||||
if ( !response || currentTabId() !== inspectedTabId ) {
|
||||
shutdownInspector();
|
||||
injectInspectorAsync(250);
|
||||
return;
|
||||
}
|
||||
@ -478,21 +476,15 @@ var onDOMFetched = function(response) {
|
||||
/******************************************************************************/
|
||||
|
||||
var fetchDOM = function() {
|
||||
messager.send({
|
||||
what: 'postMessageTo',
|
||||
senderTabId: null,
|
||||
senderChannel: 'logger-ui.js',
|
||||
receiverTabId: inspectedTabId,
|
||||
receiverChannel: 'dom-inspector.js',
|
||||
msg: {
|
||||
messager.sendTo(
|
||||
{
|
||||
what: 'domLayout',
|
||||
fingerprint: fingerprint
|
||||
}
|
||||
});
|
||||
pollTimer = vAPI.setTimeout(function() {
|
||||
pollTimer = null;
|
||||
onDOMFetched();
|
||||
}, 1001);
|
||||
},
|
||||
inspectedTabId,
|
||||
'dom-inspector.js',
|
||||
onDOMFetched
|
||||
);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
@ -504,7 +496,7 @@ var fetchDOMAsync = function(delay) {
|
||||
pollTimer = vAPI.setTimeout(function() {
|
||||
pollTimer = null;
|
||||
fetchDOM();
|
||||
}, delay || 1001);
|
||||
}, delay || 2003);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
@ -543,15 +535,10 @@ var injectInspectorAsync = function(delay) {
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var shutdownInspector = function(tabId) {
|
||||
messager.send({
|
||||
what: 'postMessageTo',
|
||||
senderTabId: null,
|
||||
senderChannel: 'logger-ui.js',
|
||||
receiverTabId: tabId,
|
||||
receiverChannel: 'dom-inspector.js',
|
||||
msg: { what: 'shutdown', }
|
||||
});
|
||||
var shutdownInspector = function() {
|
||||
if ( inspectedTabId !== '' ) {
|
||||
messager.sendTo({ what: 'shutdown' }, inspectedTabId, 'dom-inspector.js');
|
||||
}
|
||||
logger.removeAllChildren(domTree);
|
||||
cancelPollTimer();
|
||||
inspectedTabId = '';
|
||||
@ -569,31 +556,25 @@ var onTabIdChanged = function() {
|
||||
/******************************************************************************/
|
||||
|
||||
var toggleHighlightMode = function() {
|
||||
messager.send({
|
||||
what: 'postMessageTo',
|
||||
senderTabId: null,
|
||||
senderChannel: 'logger-ui.js',
|
||||
receiverTabId: inspectedTabId,
|
||||
receiverChannel: 'dom-inspector.js',
|
||||
msg: {
|
||||
messager.sendTo(
|
||||
{
|
||||
what: 'highlightMode',
|
||||
invert: uDom.nodeFromSelector('#domInspector .permatoolbar .highlightMode').classList.toggle('invert')
|
||||
}
|
||||
});
|
||||
},
|
||||
inspectedTabId,
|
||||
'dom-inspector.js'
|
||||
);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var revert = function() {
|
||||
uDom('#domTree .off').removeClass('off');
|
||||
messager.send({
|
||||
what: 'postMessageTo',
|
||||
senderTabId: null,
|
||||
senderChannel: 'logger-ui.js',
|
||||
receiverTabId: inspectedTabId,
|
||||
receiverChannel: 'dom-inspector.js',
|
||||
msg: { what: 'resetToggledNodes' }
|
||||
});
|
||||
messager.sendTo(
|
||||
{ what: 'resetToggledNodes' },
|
||||
inspectedTabId,
|
||||
'dom-inspector.js'
|
||||
);
|
||||
inspector.querySelector('.permatoolbar .revert').classList.add('disabled');
|
||||
inspector.querySelector('.permatoolbar .commit').classList.add('disabled');
|
||||
};
|
||||
@ -601,11 +582,10 @@ var revert = function() {
|
||||
/******************************************************************************/
|
||||
|
||||
var onMessage = function(request) {
|
||||
var msg = request.what === 'postMessageTo' ? request.msg : request;
|
||||
switch ( msg.what ) {
|
||||
switch ( request.what ) {
|
||||
case 'domLayout':
|
||||
cancelPollTimer();
|
||||
onDOMFetched(msg);
|
||||
onDOMFetched(request);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -1286,6 +1286,8 @@ var netFilteringManager = (function() {
|
||||
};
|
||||
})();
|
||||
|
||||
// https://www.youtube.com/watch?v=XyNYrmmdUd4
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
|
@ -141,12 +141,6 @@ var onMessage = function(request, sender, callback) {
|
||||
vAPI.tabs.open(request.details);
|
||||
break;
|
||||
|
||||
// Passthrough for auxiliary process to auxiliary process messaging.
|
||||
case 'postMessageTo':
|
||||
request.senderTabId = tabId;
|
||||
vAPI.messaging.post(request);
|
||||
break;
|
||||
|
||||
case 'reloadTab':
|
||||
if ( vAPI.isBehindTheSceneTabId(request.tabId) === false ) {
|
||||
vAPI.tabs.reload(request.tabId);
|
||||
|
@ -561,6 +561,8 @@ var domLayout = (function() {
|
||||
};
|
||||
})();
|
||||
|
||||
// https://www.youtube.com/watch?v=qo8zKhd4Cf0
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var highlightElements = function(scrollTo) {
|
||||
@ -724,6 +726,8 @@ var toggleNodes = function(nodes, originalState, targetState) {
|
||||
}
|
||||
};
|
||||
|
||||
// https://www.youtube.com/watch?v=L5jRewnxSBY
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var resetToggledNodes = function() {
|
||||
@ -757,20 +761,19 @@ var shutdown = function() {
|
||||
/******************************************************************************/
|
||||
|
||||
var onMessage = function(request) {
|
||||
var msg = request.what === 'postMessageTo' ? request.msg : request;
|
||||
var response;
|
||||
|
||||
switch ( msg.what ) {
|
||||
switch ( request.what ) {
|
||||
case 'domLayout':
|
||||
response = domLayout.get(msg.fingerprint);
|
||||
response = domLayout.get(request.fingerprint);
|
||||
break;
|
||||
|
||||
case 'highlightMode':
|
||||
svgRoot.classList.toggle('invert', msg.invert);
|
||||
svgRoot.classList.toggle('invert', request.invert);
|
||||
break;
|
||||
|
||||
case 'highlightOne':
|
||||
hightlightNodes(msg.selector, msg.nid, msg.scrollTo);
|
||||
hightlightNodes(request.selector, request.nid, request.scrollTo);
|
||||
break;
|
||||
|
||||
case 'resetToggledNodes':
|
||||
@ -778,8 +781,8 @@ var onMessage = function(request) {
|
||||
break;
|
||||
|
||||
case 'toggleNodes':
|
||||
highlightedElements = selectNodes(msg.selector, msg.nid);
|
||||
toggleNodes(highlightedElements, msg.original, msg.target);
|
||||
highlightedElements = selectNodes(request.selector, request.nid);
|
||||
toggleNodes(highlightedElements, request.original, request.target);
|
||||
highlightElements(true);
|
||||
break;
|
||||
|
||||
@ -791,16 +794,7 @@ var onMessage = function(request) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ( response !== undefined && request.what === 'postMessageTo' ) {
|
||||
localMessager.send({
|
||||
what: 'postMessageTo',
|
||||
senderTabId: null,
|
||||
senderChannel: 'dom-inspector.js',
|
||||
receiverTabId: request.senderTabId,
|
||||
receiverChannel: request.senderChannel,
|
||||
msg: response
|
||||
});
|
||||
}
|
||||
return response;
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
Loading…
Reference in New Issue
Block a user