mirror of https://github.com/gorhill/uBlock.git
Script injection, element picker, messaging
- Add script injection to vAPI, plus a raw implementation for Safari (element-picker.js requires it) - Tweak element picker to work with Safari - Revert a change from previous commit: element-picker.js' background message handler (since actually it can have its own messaging channel) - Don't send "undefined" reponses from background to content
This commit is contained in:
parent
88a7910bcb
commit
d38ca13107
|
@ -19,7 +19,7 @@
|
|||
Home: https://github.com/gorhill/uBlock
|
||||
*/
|
||||
|
||||
/* global messager, CSS */
|
||||
/* global CSS */
|
||||
'use strict';
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -120,6 +120,8 @@
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
var localMessager = vAPI.messaging.channel('element-picker.js');
|
||||
|
||||
// https://github.com/gorhill/uBlock/issues/314#issuecomment-58878112
|
||||
// Using an id makes uBlock's CSS rules more specific, thus prevents
|
||||
// surrounding external rules from winning over own rules.
|
||||
|
@ -203,11 +205,11 @@ var highlightElements = function(elems, force) {
|
|||
}
|
||||
targetElements = elems;
|
||||
|
||||
var ow = svgRoot.getAttribute('width');
|
||||
var ow = parseInt(svgRoot.style.width, 10);
|
||||
var ocean = [
|
||||
'M0 0',
|
||||
'h', ow,
|
||||
'v', svgRoot.getAttribute('height'),
|
||||
'v', parseInt(svgRoot.style.height, 10),
|
||||
'h-', ow,
|
||||
'z'
|
||||
];
|
||||
|
@ -231,7 +233,7 @@ var highlightElements = function(elems, force) {
|
|||
islands.push(poly);
|
||||
}
|
||||
svgOcean.setAttribute('d', ocean.join(''));
|
||||
svgIslands.setAttribute('d', islands.join(''));
|
||||
svgIslands.setAttribute('d', islands.join('') || 'M 0 0');
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -502,7 +504,7 @@ var onDialogClicked = function(ev) {
|
|||
else if ( ev.target.id === 'create' ) {
|
||||
var filter = userFilterFromCandidate();
|
||||
if ( filter ) {
|
||||
messager.send({ what: 'createUserFilter', filters: filter });
|
||||
localMessager.send({ what: 'createUserFilter', filters: filter });
|
||||
removeElements(elementsFromFilter(taCandidate.value));
|
||||
stopPicker();
|
||||
}
|
||||
|
@ -588,12 +590,12 @@ var showDialog = function(options) {
|
|||
/******************************************************************************/
|
||||
|
||||
var elementFromPoint = function(x, y) {
|
||||
svgRoot.style.pointerEvents = 'none';
|
||||
svgRoot.style.display = 'none';
|
||||
var elem = document.elementFromPoint(x, y);
|
||||
if ( elem === document.body || elem === document.documentElement ) {
|
||||
elem = null;
|
||||
}
|
||||
svgRoot.style.pointerEvents = 'auto';
|
||||
svgRoot.style.display = '';
|
||||
return elem;
|
||||
};
|
||||
|
||||
|
@ -641,8 +643,8 @@ var onScrolled = function() {
|
|||
var newHeight = this.scrollY + this.innerHeight;
|
||||
if ( newHeight > svgHeight ) {
|
||||
svgHeight = newHeight;
|
||||
svgRoot.setAttribute('height', svgHeight);
|
||||
svgRoot.setAttribute("viewBox", '0 0 ' + svgWidth + ' ' + svgHeight);
|
||||
svgRoot.style.height = svgHeight + 'px';
|
||||
svgRoot.setAttribute('viewBox', '0 0 ' + svgWidth + ' ' + svgHeight);
|
||||
}
|
||||
highlightElements(targetElements, true);
|
||||
};
|
||||
|
@ -654,19 +656,19 @@ var onScrolled = function() {
|
|||
|
||||
var stopPicker = function() {
|
||||
if ( pickerRoot !== null ) {
|
||||
document.removeEventListener('keydown', onKeyPressed);
|
||||
window.removeEventListener('scroll', onScrolled);
|
||||
window.removeEventListener('keydown', onKeyPressed, true);
|
||||
window.removeEventListener('scroll', onScrolled, true);
|
||||
taCandidate.removeEventListener('input', onCandidateChanged);
|
||||
divDialog.removeEventListener('click', onDialogClicked);
|
||||
svgRoot.removeEventListener('mousemove', onSvgHovered);
|
||||
svgRoot.removeEventListener('click', onSvgClicked);
|
||||
pickerRoot.parentNode.removeChild(pickerRoot)
|
||||
pickerRoot.parentNode.removeChild(pickerRoot);
|
||||
pickerRoot =
|
||||
divDialog =
|
||||
svgRoot = svgOcean = svgIslands =
|
||||
taCandidate =
|
||||
urlNormalizer = null;
|
||||
messager.close();
|
||||
localMessager.close();
|
||||
}
|
||||
targetElements = [];
|
||||
};
|
||||
|
@ -740,7 +742,6 @@ var startPicker = function() {
|
|||
'position: absolute;',
|
||||
'top: 0;',
|
||||
'left: 0;',
|
||||
'pointer-events: auto;',
|
||||
'cursor: crosshair;',
|
||||
'z-index: 4999999999;',
|
||||
'}',
|
||||
|
@ -846,7 +847,8 @@ var startPicker = function() {
|
|||
pickerRoot.appendChild(pickerStyle);
|
||||
|
||||
svgRoot = document.createElementNS(svgns, 'svg');
|
||||
svgRoot.innerHTML = '<path /><path />';
|
||||
svgRoot.appendChild(document.createElementNS(svgns, 'path'));
|
||||
svgRoot.appendChild(document.createElementNS(svgns, 'path'));
|
||||
svgWidth = document.documentElement.scrollWidth;
|
||||
svgHeight = Math.max(
|
||||
document.documentElement.scrollHeight,
|
||||
|
@ -854,11 +856,11 @@ var startPicker = function() {
|
|||
);
|
||||
svgRoot.setAttribute('x', 0);
|
||||
svgRoot.setAttribute('y', 0);
|
||||
svgRoot.setAttribute('width', svgWidth);
|
||||
svgRoot.setAttribute('height', svgHeight);
|
||||
svgRoot.setAttribute("viewBox", '0 0 ' + svgWidth + ' ' + svgHeight);
|
||||
svgOcean = svgRoot.querySelector('path:first-child');
|
||||
svgIslands = svgRoot.querySelector('path + path');
|
||||
svgRoot.style.width = svgWidth + 'px';
|
||||
svgRoot.style.height = svgHeight + 'px';
|
||||
svgRoot.setAttribute('viewBox', '0 0 ' + svgWidth + ' ' + svgHeight);
|
||||
svgOcean = svgRoot.firstChild;
|
||||
svgIslands = svgRoot.lastChild;
|
||||
pickerRoot.appendChild(svgRoot);
|
||||
|
||||
// TODO: do not rely on element ids, they could collide with whatever
|
||||
|
@ -892,8 +894,8 @@ var startPicker = function() {
|
|||
taCandidate = divDialog.querySelector('textarea');
|
||||
taCandidate.addEventListener('input', onCandidateChanged);
|
||||
urlNormalizer = document.createElement('a');
|
||||
window.addEventListener('scroll', onScrolled);
|
||||
document.addEventListener('keydown', onKeyPressed);
|
||||
window.addEventListener('scroll', onScrolled, true);
|
||||
window.addEventListener('keydown', onKeyPressed, true);
|
||||
|
||||
highlightElements([], true);
|
||||
|
||||
|
@ -970,13 +972,16 @@ var startPicker = function() {
|
|||
}
|
||||
};
|
||||
|
||||
messager.send({ what: 'elementPickerArguments' }, initPicker);
|
||||
localMessager.send({ what: 'elementPickerArguments' }, initPicker);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
startPicker();
|
||||
|
||||
// This triggers the hiding of the popover in Safari
|
||||
window.focus();
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// https://www.youtube.com/watch?v=sociXdKnyr8
|
||||
|
|
|
@ -339,9 +339,41 @@ var onMessage = function(details, sender, callback) {
|
|||
response = filterRequest(pageStore, details);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
callback(response);
|
||||
};
|
||||
|
||||
// the following is used by element-picker.js
|
||||
vAPI.messaging.listen('contentscript-end.js', onMessage);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
})();
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
// element-picker.js
|
||||
|
||||
(function() {
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var µb = µBlock;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var onMessage = function(request, sender, callback) {
|
||||
// Async
|
||||
switch ( request.what ) {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Sync
|
||||
var response;
|
||||
|
||||
switch ( request.what ) {
|
||||
case 'elementPickerArguments':
|
||||
response = {
|
||||
i18n: {
|
||||
|
@ -371,7 +403,7 @@ var onMessage = function(details, sender, callback) {
|
|||
callback(response);
|
||||
};
|
||||
|
||||
vAPI.messaging.listen('contentscript-end.js', onMessage);
|
||||
vAPI.messaging.listen('element-picker.js', onMessage);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
|
|
|
@ -602,14 +602,14 @@
|
|||
if ( chrome.runtime.lastError ) {
|
||||
return;
|
||||
}
|
||||
chrome.tabs.executeScript(tabId, {
|
||||
vAPI.tabs.injectScript(tabId, {
|
||||
file: 'js/contentscript-end.js',
|
||||
allFrames: true,
|
||||
runAt: 'document_idle'
|
||||
}, scriptDone);
|
||||
};
|
||||
var scriptStart = function(tabId) {
|
||||
chrome.tabs.executeScript(tabId, {
|
||||
vAPI.tabs.injectScript(tabId, {
|
||||
file: 'js/contentscript-start.js',
|
||||
allFrames: true,
|
||||
runAt: 'document_idle'
|
||||
|
|
|
@ -252,7 +252,7 @@
|
|||
|
||||
µBlock.elementPickerExec = function(tabId, targetElement) {
|
||||
this.elementPickerTarget = targetElement || '';
|
||||
this.XAL.injectScript(tabId, { file: 'js/element-picker.js' });
|
||||
vAPI.tabs.injectScript(tabId, { file: 'js/element-picker.js' });
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
|
|
@ -136,7 +136,19 @@ if (window.chrome) {
|
|||
wrapper();
|
||||
}
|
||||
},
|
||||
close: chrome.tabs.remove.bind(chrome.tabs)
|
||||
close: chrome.tabs.remove.bind(chrome.tabs),
|
||||
injectScript: function(tabId, details, callback) {
|
||||
if (!callback) {
|
||||
callback = function(){};
|
||||
}
|
||||
|
||||
if (tabId) {
|
||||
chrome.tabs.executeScript(tabId, details, callback);
|
||||
}
|
||||
else {
|
||||
chrome.tabs.executeScript(details, callback);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Must read: https://code.google.com/p/chromium/issues/detail?id=410868#c8
|
||||
|
@ -176,7 +188,7 @@ if (window.chrome) {
|
|||
var onMessage = function(request) {
|
||||
var callback = function(response) {
|
||||
// stfu
|
||||
if (chrome.runtime.lastError) {
|
||||
if (chrome.runtime.lastError || response === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -492,6 +504,29 @@ if (window.chrome) {
|
|||
if (tab) {
|
||||
tab.close();
|
||||
}
|
||||
},
|
||||
injectScript: function(tabId, details, callback) {
|
||||
var tab = tabId ? this.stack[tabId] : safari.application.activeBrowserWindow.activeTab;
|
||||
|
||||
if (details.file) {
|
||||
var xhr = new XMLHttpRequest;
|
||||
xhr.overrideMimeType('application/x-javascript;charset=utf-8');
|
||||
xhr.open('GET', details.file, false);
|
||||
xhr.send();
|
||||
details.code = xhr.responseText;
|
||||
}
|
||||
|
||||
tab.page.dispatchMessage('message', {
|
||||
portName: 'vAPI',
|
||||
msg: {
|
||||
cmd: 'runScript',
|
||||
details: details
|
||||
}
|
||||
});
|
||||
|
||||
if (typeof callback === 'function') {
|
||||
setTimeout(callback, 13);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -624,7 +659,7 @@ if (window.chrome) {
|
|||
}
|
||||
|
||||
var callback = function(response) {
|
||||
if (request.message.requestId) {
|
||||
if (request.message.requestId && response !== undefined) {
|
||||
request.target.page.dispatchMessage(
|
||||
'message',
|
||||
{
|
||||
|
|
|
@ -27,12 +27,12 @@ var messagingConnector = function(response) {
|
|||
|
||||
if (response.requestId) {
|
||||
listener = vAPI.messaging.listeners[response.requestId];
|
||||
}
|
||||
|
||||
if (!listener) {
|
||||
channel = vAPI.messaging.channels[response.portName];
|
||||
listener = channel && channel.listener;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof listener === 'function') {
|
||||
delete vAPI.messaging.listeners[response.requestId];
|
||||
|
@ -230,7 +230,6 @@ if (window.chrome) {
|
|||
// relevant?
|
||||
// https://developer.apple.com/library/safari/documentation/Tools/Conceptual/SafariExtensionGuide/MessagesandProxies/MessagesandProxies.html#//apple_ref/doc/uid/TP40009977-CH14-SW12
|
||||
vAPI.messaging = {
|
||||
port: null,
|
||||
requestId: 0,
|
||||
listeners: {},
|
||||
channels: {},
|
||||
|
@ -240,10 +239,19 @@ if (window.chrome) {
|
|||
vAPI.messaging.connector(msg.message);
|
||||
};
|
||||
safari.self.addEventListener('message', this._connector, false);
|
||||
|
||||
this.channels['vAPI'] = {
|
||||
listener: function(msg) {
|
||||
if (msg.cmd === 'runScript' && msg.details.code) {
|
||||
Function(msg.details.code).call(window);
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
close: function() {
|
||||
if (this._connector) {
|
||||
safari.self.removeEventListener('message', this._connector, false);
|
||||
this.channels = this.listeners = null;
|
||||
}
|
||||
},
|
||||
channel: function(name, callback) {
|
||||
|
|
|
@ -31,12 +31,6 @@
|
|||
var exports = {};
|
||||
var noopFunc = function(){};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
|
||||
exports.injectScript = function(id, details) {
|
||||
chrome.tabs.executeScript(id, details);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
|
|
Loading…
Reference in New Issue