未定义函数或拒绝访问 Greasemonkey 中的对象的权限
function not defined or permission denied to access object in Greasemonkey
我正在开发一个 Greasemonkey 脚本,该脚本将一个按钮注入聊天系统 (Gitter),允许您发送默认消息。 (不是垃圾邮件。管理员可以像行为准则一样发送消息)。
假设我已经注入了一个按钮:
<button onclick='setTimeout( function() { showMsg() }, 10 );'>Send default message</button>
遵循这个问题的建议:Javascript: Function is defined, but Error says.. Function is not found ! (Strange) 使用 setTimeout()
因为 GM 中定义的函数不适用于主要的 Window。
出于测试目的,该函数是一个简单的控制台日志:
function showMsg(){
console.log('showMsg triggered');
}
问题是这还是returns我一个"showMsg is not defined"。所以按照前面提到的问题中提供的另一个divse,我尝试了:
unsafeWindow.showMsg = function(){
console.log('showMsg triggered');
}
这可是returns我:
Error: Permission denied to access object
奇怪的是,这似乎只发生在创建 div 元素并使用 innerHTML
将按钮插入到 div 中时。实际创建这样的按钮时:
var btn = document.createElement('button');
btn.onclick = function(){ showMsg(); };
它按预期工作。
一些可能有助于找到答案的附加信息:
Gitter 聊天为聊天消息和消息输入字段使用 iframe。 iframe 在同一台服务器上,因此不存在同源策略问题。
按钮被注入到主体中。这是我如何尝试注入它们的 2 个示例。
(工作版)
var iframe, iframeDoc;
var chatContainer;
var chatInput, chatText;
var msgMenu;
$(document).ready(function() {
iframe = document.getElementById('content-frame');
iframe.onload = function(){
iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
chatContainer = iframeDoc.getElementById('chat-container');
chatInput = iframeDoc.getElementById('chat-input');
chatText = iframeDoc.getElementById('chat-input-textarea');
loadButton();
}
});
function loadButton(){
var div = document.createElement('div');
var btn = document.createElement('button');
var btnText = document.createTextNode('Send default message');
// Lots of CSS here that ads absolute positioning
// and makes the div float in the middle of the screen
btn.onclick = function(){ showMsg(); };
btn.appendChild(btnText);
div.appendChild(btn);
div.setAttribute("id", "msgMenu");
document.body.appendChild(div);
msgMenu = document.getElementById('msgMenu');
return false;
}
function showMsg(){
console.log('showMsg triggered');
}
将 loadButton 函数更改为此时,会导致提到的问题:
function loadButton(){
var div = document.createElement('div');
div.innerHTML = "<button onclick='setTimeout( function() { showMsg() }, 10 );'>Send default message</button>";
div.setAttribute("id", "msgMenu");
document.body.appendChild(div);
msgMenu = document.getElementById('msgMenu');
return false;
}
您的用户脚本是一个“content script”,运行在 Greasemonkey 扩展(或其他用户脚本管理器)的上下文中,并且可以访问 Greasemonkey API。之所以称为内容脚本,是因为它可以访问网页的内容,即DOM.
从网页的 HTML 调用的脚本是 "page scripts",在单独的上下文中 运行。他们无法直接访问内容脚本的范围,包括您的用户脚本。
在您的两个示例中,showMsg()
函数仅存在于内容脚本的范围内。在工作示例中,将匿名函数附加到按钮的 onclick
处理程序的代码在同一范围内执行,其中 showMsg()
可见。对匿名函数的引用附加到 <button>
节点,创建一个 closure 使其即使在主用户脚本执行完毕后仍保留在内存中。闭包还意味着该函数可以访问定义该函数时范围内的相同对象,包括 showMsg()
(和 GM API 对象)。
在第二个示例中,按钮是通过在页面脚本范围内评估其父级 <div>
的 innerHTML
创建的。这意味着 showMsg()
在点击处理程序附加到按钮时不可见,在调用处理程序时出现 "not defined" 错误。
问题不在于您使用 innerHTML
来注入按钮;这是你用它来附加点击处理程序。此代码也有效,使用 innerHTML
创建按钮,但从内容脚本范围附加处理程序:
function loadButton(){
var div = document.createElement('div');
div.innerHTML = "<button id='myButton'>Send default message</button>";
document.body.appendChild(div);
msgMenu = document.getElementById('msgMenu');
document.getElementById('myButton').addEventListener('click', showMsg);
return false;
}
我无法准确解释为什么您会收到 unsafeWindow
的错误消息,但如果您使用的是 Greasemonkey v4 或更高版本,and/or Firefox v57 或更高版本,则可能是由于最近 Firefox 处理扩展的方式发生了变化。有关更多线索,请参阅 MDN and the Greasemonkey blog。
如果确实需要给网页本身添加功能,比较简单可靠的方法是在DOM中注入一个<script>
节点。请注意,插入的函数将无法访问用户脚本范围内的任何内容。 MDN 上有 more documentation 描述了与页面脚本交互的更复杂的方式,但其中一些只适用于 Firefox。
我正在开发一个 Greasemonkey 脚本,该脚本将一个按钮注入聊天系统 (Gitter),允许您发送默认消息。 (不是垃圾邮件。管理员可以像行为准则一样发送消息)。
假设我已经注入了一个按钮:
<button onclick='setTimeout( function() { showMsg() }, 10 );'>Send default message</button>
遵循这个问题的建议:Javascript: Function is defined, but Error says.. Function is not found ! (Strange) 使用 setTimeout()
因为 GM 中定义的函数不适用于主要的 Window。
出于测试目的,该函数是一个简单的控制台日志:
function showMsg(){
console.log('showMsg triggered');
}
问题是这还是returns我一个"showMsg is not defined"。所以按照前面提到的问题中提供的另一个divse,我尝试了:
unsafeWindow.showMsg = function(){
console.log('showMsg triggered');
}
这可是returns我:
Error: Permission denied to access object
奇怪的是,这似乎只发生在创建 div 元素并使用 innerHTML
将按钮插入到 div 中时。实际创建这样的按钮时:
var btn = document.createElement('button');
btn.onclick = function(){ showMsg(); };
它按预期工作。
一些可能有助于找到答案的附加信息:
Gitter 聊天为聊天消息和消息输入字段使用 iframe。 iframe 在同一台服务器上,因此不存在同源策略问题。
按钮被注入到主体中。这是我如何尝试注入它们的 2 个示例。
(工作版)
var iframe, iframeDoc;
var chatContainer;
var chatInput, chatText;
var msgMenu;
$(document).ready(function() {
iframe = document.getElementById('content-frame');
iframe.onload = function(){
iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
chatContainer = iframeDoc.getElementById('chat-container');
chatInput = iframeDoc.getElementById('chat-input');
chatText = iframeDoc.getElementById('chat-input-textarea');
loadButton();
}
});
function loadButton(){
var div = document.createElement('div');
var btn = document.createElement('button');
var btnText = document.createTextNode('Send default message');
// Lots of CSS here that ads absolute positioning
// and makes the div float in the middle of the screen
btn.onclick = function(){ showMsg(); };
btn.appendChild(btnText);
div.appendChild(btn);
div.setAttribute("id", "msgMenu");
document.body.appendChild(div);
msgMenu = document.getElementById('msgMenu');
return false;
}
function showMsg(){
console.log('showMsg triggered');
}
将 loadButton 函数更改为此时,会导致提到的问题:
function loadButton(){
var div = document.createElement('div');
div.innerHTML = "<button onclick='setTimeout( function() { showMsg() }, 10 );'>Send default message</button>";
div.setAttribute("id", "msgMenu");
document.body.appendChild(div);
msgMenu = document.getElementById('msgMenu');
return false;
}
您的用户脚本是一个“content script”,运行在 Greasemonkey 扩展(或其他用户脚本管理器)的上下文中,并且可以访问 Greasemonkey API。之所以称为内容脚本,是因为它可以访问网页的内容,即DOM.
从网页的 HTML 调用的脚本是 "page scripts",在单独的上下文中 运行。他们无法直接访问内容脚本的范围,包括您的用户脚本。
在您的两个示例中,showMsg()
函数仅存在于内容脚本的范围内。在工作示例中,将匿名函数附加到按钮的 onclick
处理程序的代码在同一范围内执行,其中 showMsg()
可见。对匿名函数的引用附加到 <button>
节点,创建一个 closure 使其即使在主用户脚本执行完毕后仍保留在内存中。闭包还意味着该函数可以访问定义该函数时范围内的相同对象,包括 showMsg()
(和 GM API 对象)。
在第二个示例中,按钮是通过在页面脚本范围内评估其父级 <div>
的 innerHTML
创建的。这意味着 showMsg()
在点击处理程序附加到按钮时不可见,在调用处理程序时出现 "not defined" 错误。
问题不在于您使用 innerHTML
来注入按钮;这是你用它来附加点击处理程序。此代码也有效,使用 innerHTML
创建按钮,但从内容脚本范围附加处理程序:
function loadButton(){
var div = document.createElement('div');
div.innerHTML = "<button id='myButton'>Send default message</button>";
document.body.appendChild(div);
msgMenu = document.getElementById('msgMenu');
document.getElementById('myButton').addEventListener('click', showMsg);
return false;
}
我无法准确解释为什么您会收到 unsafeWindow
的错误消息,但如果您使用的是 Greasemonkey v4 或更高版本,and/or Firefox v57 或更高版本,则可能是由于最近 Firefox 处理扩展的方式发生了变化。有关更多线索,请参阅 MDN and the Greasemonkey blog。
如果确实需要给网页本身添加功能,比较简单可靠的方法是在DOM中注入一个<script>
节点。请注意,插入的函数将无法访问用户脚本范围内的任何内容。 MDN 上有 more documentation 描述了与页面脚本交互的更复杂的方式,但其中一些只适用于 Firefox。