如何配置Firefox以允许Javascript拦截从剪贴板粘贴的值?

16
我需要过滤掉用户从剪贴板粘贴时的某些字符。(实际上,我不想修改剪贴板中的内容。)我已经在IE中实现了这个功能。叹气...

简而言之:user.js中的capability.policy项目会进入prefs.js,但不会生效。

FYI,我可以合理地让所有用户安装user.js。但是我们都没有管理员权限,所以这就是我关于配置能做的全部。

感谢任何帮助!

注意:

  1. 为了本问题的目的,我不想“绕过”访问剪贴板 --
    例如,我不想在粘贴发生后操作DOM元素的值
  2. 我不想要需要框架/库(如jQuery、Dojo、Prototype、YUI等)的解决方案

跟随的步骤

1. 通过访问URL about:support => Profile Directory => Open Containing Folder 确定了profile文件夹的位置。 2. 通过创建包含以下行的user.js尝试在Firefox中启用剪贴板
user_pref("just.mike", "test to see if user.js works.");
user_pref("capability.policy.policynames", "allowclipboard");
user_pref("capability.policy.allowclipboard.sites", "https://my-site.com");
user_pref("capability.policy.allowclipboard.Clipboard.cutcopy", "allAccess");
user_pref("capability.policy.allowclipboard.Clipboard.paste", "allAccess");
注意:https://my-site.com不是真实网站。 3. 由于Bugzilla Bug 284673 - about:config hides "capability.policy" preferencescapability.policy项在about:config中不可见。但是,我认为这些user.js项“起作用”,并且文件位于正确的文件夹中,因为之后:
  • about:config显示了just.mike条目
  • prefs.js包含所有新行,但按字母顺序排列:
    user_pref("capability.policy.allowclipboard.Clipboard.cutcopy", "allAccess");
    user_pref("capability.policy.allowclipboard.Clipboard.paste", "allAccess");
    user_pref("capability.policy.allowclipboard.sites", "https://my-site.com");
    user_pref("capability.policy.policynames", "allowclipboard");
    ...
    user_pref("just.mike", "test to see if user.js works.");
    
(顺便说一下,我还尝试在所有地方使用Zallowclipboard,以使policynames行由于按字母顺序排列而首先出现,但这也不起作用。) 4. 在onpaste事件之后,尝试在Firefox中读取剪贴板,代码如下:
var clipboard = Components.classes["@mozilla.org/widget/clipboard;1"].getService(Components.interfaces.nsIClipboard);
if (!clipboard) {
    throw new Error('internal error -- could not create clipboard object');
}
var transferable = Components.classes["@mozilla.org/widget/transferable;1"].createInstance(Components.interfaces.nsITransferable); if (!transferable) { throw new Error('internal error -- could not create transferable object'); }
transferable.addDataFlavor("text/unicode"); clipboard.getData(transferable, clipboard.kGlobalClipboard);
var clipboard_data = new Object(); var clipboard_length = new Object();
transferable.getTransferData("text/unicode", clipboard_data, clipboard_length);
var clipboard_text = ''; if (!!clipboard_data) { var clipboard_nsISupportsString = clipboard_data.value.QueryInterface(Components.interfaces.nsISupportsString); clipboard_text = clipboard_nsISupportsString.data.substring(0, clipboard_length.value / 2); }
return(clipboard_text);
5. 该代码在第一行失败,在Firebug控制台返回以下错误:
Permission denied for <https://my-site.com> to get property XPCComponents.classes
注意:我实际上在真实的URL上运行它,该URL会显示在错误消息中--这里只是将其更改为虚拟名称。 6. 我还看到一些其他示例,在第一行使用createInstance而不是getService,但第一行仍然生成相同的错误文本:
var clipboard = Components.classes["@mozilla.org/widget/clipboard;1"].createInstance(Components.interfaces.nsIClipboard);
// ...


环境 (这超出了我的控制范围)

  • 没有计算机管理员访问权限
  • Windows Vista
  • Mozilla Firefox 10

参考资料


你说你不想“绕过”访问剪贴板。为什么?在我看来,唯一的解决方案是检测文本区/输入框上的control-v,然后从那里编辑文本。这有什么问题吗?性能?除非你真的对文本进行了大量操作,否则我认为你不会看到任何闪烁或其他问题。 - lbstr
我已经在谷歌上搜索了一下这个问题,并找到了一些代码,其中显示了在nsISupportsStringnsITransferable之后初始化nsIClipboard,也许这可能会产生影响。https://developer.mozilla.org/en/Using_the_Clipboard - filype
1
你的问题到底是什么?这听起来很奇怪,但也许你正在用你认为可能是解决方案的方式来克服你的问题。公开“你想要的最终结果”可以给我们更多的空间来开拓新的解决方案。 - Ricardo Souza
3个回答

1
简而言之,我认为按照你想要的方式做你想做的事情是不可能的。Mozilla(以及大多数现代浏览器)出于安全原因限制了剪贴板访问。你似乎已经轻松地绕过了IE中的这个限制,这并不是一个令人放心的想法。
话虽如此,插件与网页有不同的限制,你可以通过编写插件(甚至利用Flash)来绕过这个限制。即使使用插件,我认为阻止某人将某些东西粘贴到Web表单(或其他任何地方)的唯一方法是预先清除他们的剪贴板。
如果你只想防止某些字符串被输入到文本框中,最好的办法是监视文本框本身的事件。
如果我理解你的意思正确,那么你想强制用户在表单中键入(并且只键入)某些内容,我无法想到一个简单的方法来实现这一点。一些非平凡的选择:
  1. 将文本框设置为readonly,并弹出虚拟键盘,强制用户使用鼠标“输入”到文本框中(您需要自己用HTML和JavaScript构建键盘,或在其他地方找到合适的解决方案)。
  2. 监视oninput事件;如果文本框更快地发生变化,超出了一个人可以合理地输入的速度,则拒绝这些更改。

这两种方法都不是很美观,但如果您想使用开放式网络技术创建解决方案,那么您必须接受所构建系统的限制以及其优点


0

一种简单但适用于不同浏览器的方法是在 onchange 事件中将当前输入值与先前输入值进行比较。

如果长度增加或值差异过大(不仅限于缩小,还有很多新字符)-- 可能是从剪贴板中粘贴了一些内容。 可以使用类似以下代码:

$('input, textarea').change(function(){
  var prev = $(this).data('prev-val'), 
      current = $(this).val();
  if (is_big_changes(prev,current)) {
    $(this).val(my_filter_func(current));
  }
  if (!prev) {
     $(this).data('prev-val', current);
  } 
})

(这只是概念验证,所以我使用了jQuery来避免大量编码)

is_big_changes和my_filter_func - 这些是您需要实现的函数。

警告:这种方法可能存在许多恶意漏洞,我知道它看起来非常丑陋。我的目的是提出建议。


我感谢 Nayjest 的尝试,但请查看我在问题顶部的“编辑说明”澄清。 - just mike
Nayjest 采用了正确的方法,如果你不喜欢 jQuery(我也没有特别喜欢它),只需使用纯 JavaScript 编写相同的代码即可。 - axkibe

0
我们可以这样说,您所要的替代方案是检测剪贴板粘贴吗?因为当您知道之前有什么内容时,就知道已经发生了什么变化。
那么为什么不只是挂钩 onchange 呢?从内容开头和结尾相同的所有字符都不会被粘贴。如果您想将其与简单的按键区分开来,请同时侦听 keydown/keypress ,然后您就知道哪些更改来自“其他地方”。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接