Hit*_*tin 1 javascript jquery cross-domain browser-plugin firefox-addon-webextensions
我正在使用webExtensions开发一个Firefox扩展,这将帮助我简化以下场景的工作。
我必须在站点上单击大约 50-60 个按钮来更新任务状态。单击此按钮后,网页将调用网页的updTask(id)JavaScript 函数,然后调用 Web 服务来更新任务。
我无法使用以下代码从我的内容脚本中执行此操作:
清单.json:
"permissions": [
"activeTab",
"cross-domain-content": ["http://workdomain.com/","http://workdomain.org/","http://www.workdomain.com/","http://www.workdomain.org/"]
]
Run Code Online (Sandbox Code Playgroud)
内容脚本代码:
function taskUpdate(request, sender, sendResponse) {
console.log(request.start + 'inside task update');
updateTask(45878);
chrome.runtime.onMessage.removeListener(taskUpdate);
}
function updateTask(id) {
//TODO: code to get all buttons and task id's
updTask(id); // Not working
}
Run Code Online (Sandbox Code Playgroud)
插件脚本:
document.addEventListener("click", function(e) {
if (e.target.classList.contains("startButton")) {
chrome.tabs.executeScript(null, {
file: "/content_scripts/taskUpdate.js"
});
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, {start: "start"});
});
return;
}
else if (e.target.classList.contains("clear")) {
chrome.tabs.reload();
window.close();
return;
}
});
Run Code Online (Sandbox Code Playgroud)
有人可以指出我正确的方向,我在这里错过了什么?
您的内容脚本与页面脚本(网页中已存在的脚本)的上下文/范围不同。您的内容脚本具有比授予页面脚本更高的权限。将内容脚本与页面脚本分开是浏览器扩展的正常架构,这是出于安全原因。
由于您的内容脚本与页面脚本处于不同的上下文中,因此您无法从内容脚本直接访问在页面脚本中定义的函数和变量。您可以通过几种不同的方式访问页面上下文中的信息。这样做的跨浏览器方法是使代码的某些特定部分在页面上下文中执行。我发现最方便且跨浏览器兼容的方法是创建一个<script>元素并将其插入到包含您要执行的代码的页面的 DOM 中。
你可以这样做:
function updateTask(id) {
let newScript = document.createElement('script');
newScript.innerHTML='updTask(' + id + ');';
document.head.appendChild(newScript);
//newScript.remove(); //Can be removed, if desired.
}
Run Code Online (Sandbox Code Playgroud)
添加的脚本在页面上下文中运行,因为它现在是<script>DOM 中的一个元素。一旦插入<script>元素的脚本不再处理,浏览器就会识别出添加了元素并对其进行评估(执行包含的代码)。对于您添加到 DOM 的任何其他元素,它的作用基本相同。因为它是页面的一部分,所以里面的代码在页面脚本上下文/范围中运行。
有多种方式可以在页面上下文中运行的代码与内容脚本上下文中的代码之间进行通信。我的首选方法是使用CustomEvents。我在这个答案的第一部分描述了原因。通常,我使用至少一种自定义事件类型从页面上下文到内容脚本上下文,以及从内容脚本上下文到页面上下文的另一种。您可以根据需要使用任意数量的CustomEvent类型。我经常使用多个事件,每个事件传达不同的内容,而不是我解析几种不同类型消息的单一事件类型。
维护将在页面上下文中执行的代码的最简单方法是将其编写为内容脚本中的函数,然后将该函数注入到页面上下文中。这是一些通用代码,它们将在将参数传递给您在页面上下文中执行的函数时执行此操作:
此实用程序函数executeInPage()将在页面上下文中执行一个函数并将任何提供的参数传递给该函数。参数必须是Object, Array, function, RegExp,Date和/或其他原语(Boolean, null, undefined , Number, String, 但不是Symbol)。
function updateTask(id) {
let newScript = document.createElement('script');
newScript.innerHTML='updTask(' + id + ');';
document.head.appendChild(newScript);
//newScript.remove(); //Can be removed, if desired.
}
Run Code Online (Sandbox Code Playgroud)
excuteInPage():/* executeInPage takes a function defined in this context, converts it to a string
* and inserts it into the page context inside a <script>. It is placed in an IIFE and
* passed all of the additional parameters passed to executeInPage.
* Parameters:
* func The function which you desire to execute in the page.
* leaveInPage If this does not evaluate to a truthy value, then the <script> is
* immediately removed from the page after insertion. Immediately
* removing the script can normally be done. In some corner cases,
* it's desirable for the script to remain in the page. However,
* even for asynchronous functionality it's usually not necessary, as
* the context containing the code will be kept with any references
* (e.g. the reference to a callback function).
* id If this is a non-blank string, it is used as the ID for the <script>
* All additional parameters are passed to the function executing in the page.
* This is done by converting them to JavaScript code-text and back.
* All such parameters must be Object, Array, functions, RegExp,
* Date, and/or other primitives (Boolean, null, undefined, Number,
* String, but not Symbol). Circular references are not supported.
* If you need to communicate DOM elements, you will need to
* pass selectors, or other descriptors of them (e.g. temporarily
* assign them a unique class), or otherwise communicate them to the
* script (e.g. you could dispatch a custom event once the script is
* inserted into the page context).
*/
function executeInPage(functionToRunInPage, leaveInPage, id) {
//Execute a function in the page context.
// Any additional arguments passed to this function are passed into the page to the
// functionToRunInPage.
// Such arguments must be JSON-ifiable (also Date, Function, and RegExp) (prototypes
// are not copied).
// Using () => doesn't set arguments, so can't use it to define this function.
// This has to be done without jQuery, as jQuery creates the script
// within this context, not the page context, which results in
// permission denied to run the function.
function convertToText(args) {
//This uses the fact that the arguments are converted to text which is
// interpreted within a <script>. That means we can create other types of
// objects by recreating their normal JavaScript representation.
// It's actually easier to do this without JSON.strigify() for the whole
// Object/Array.
var asText = '';
var level = 0;
function lineSeparator(adj, isntLast) {
level += adj - ((typeof isntLast === 'undefined' || isntLast) ? 0 : 1);
asText += (isntLast ? ',' : '') +'\n'+ (new Array(level * 2 + 1)).join('');
}
function recurseObject(obj) {
if (Array.isArray(obj)) {
asText += '[';
lineSeparator(1);
obj.forEach(function(value, index, array) {
recurseObject(value);
lineSeparator(0, index !== array.length - 1);
});
asText += ']';
} else if (obj === null) {
asText +='null';
//undefined
} else if (obj === void(0)) {
asText +='void(0)';
//Special cases for Number
} else if (Number.isNaN(obj)) {
asText +='Number.NaN';
} else if (obj === 1/0) {
asText +='1/0';
} else if (obj === 1/-0) {
asText +='1/-0';
//function
} else if (obj instanceof RegExp || typeof obj === 'function') {
asText += obj.toString();
} else if (obj instanceof Date) {
asText += 'new Date("' + obj.toJSON() + '")';
} else if (typeof obj === 'object') {
asText += '{';
lineSeparator(1);
Object.keys(obj).forEach(function(prop, index, array) {
asText += JSON.stringify(prop) + ': ';
recurseObject(obj[prop]);
lineSeparator(0, index !== array.length - 1);
});
asText += '}';
} else if (['boolean', 'number', 'string'].indexOf(typeof obj) > -1) {
asText += JSON.stringify(obj);
} else {
console.log('Didn\'t handle: typeof obj:', typeof obj, ':: obj:', obj);
}
}
recurseObject(args);
return asText;
}
var newScript = document.createElement('script');
if(typeof id === 'string' && id) {
newScript.id = id;
}
var args = [];
//using .slice(), or other Array methods, on arguments prevents optimization
for(var index=3;index<arguments.length;index++){
args.push(arguments[index]);
}
newScript.textContent = '(' + functionToRunInPage.toString() + ').apply(null,'
+ convertToText(args) + ");";
(document.head || document.documentElement).appendChild(newScript);
if(!leaveInPage) {
//Synchronous scripts are executed immediately and can be immediately removed.
//Scripts with asynchronous functionality of any type must remain in the page
// until complete.
document.head.removeChild(newScript);
}
return newScript;
};
Run Code Online (Sandbox Code Playgroud)
这个答案的文字主要取自我的其他答案:this one和this one。
| 归档时间: |
|
| 查看次数: |
3892 次 |
| 最近记录: |