Chrome Selection.addRange() 不 select (一个 execCommand('copy') 用例)

Chrome Selection.addRange() does not select (an execCommand('copy') use case)

在 Chrome 中编写一个小型浏览器扩展程序,以将某些特定文本从特定网页复制到剪贴板。以 HTML 格式,以便人们可以将其粘贴到 word、outlook 等办公程序中。

document.execCommand('copy') 是我使用的命令,它由 document.onkeydown 组合键 (Alt+1) 触发,并且工作正常 - 但只是第一次。如果您再次尝试按组合键,它将不会执行任何操作。

我找到了原因,document.queryCommandEnabled("copy") returns 第一次是正确的,任何其他尝试都是错误的。如果我重新加载页面,它会再次 returns 为真。此外,如果我在加载页面后在浏览器外部单击 window,然后在浏览器中单击并使用组合键,即使是第一次,也会立即 returns 错误。

function copy(text) {
  var sel = document.createElement("div"); // Creating temporary holder for text to copy

  sel.style.opacity = 0;             sel.style.position = "absolute";  // These are not really required,
  sel.style.pointerEvents = "none";  sel.style.zIndex = -1;            // at least for Chrome

  sel.innerHTML = text; // Put the text to copy into the temporary holder

  document.body.appendChild(sel); // Add the temporary holder to the page

  var range = document.createRange();     // All this is required to select the text,
  range.selectNode(sel);                  // since the holder is not an editable text
  window.getSelection().addRange(range);  // field and must be treated differently.

  // document.designMode = 'on'; (Tried this, no effect)

  /* Debugging */ alert("Enabled = " + document.queryCommandEnabled("copy") + " Design mode = " + document.designMode);

  try {
    document.execCommand('copy'); // Copy to clipbopard
  }
  catch (err) {
    alert('Unable to copy');
    console.log('Unable to copy'); // Copy failed?!
  }

  // document.designMode = 'off'; (Tried this, no effect)

  document.body.removeChild(sel); // Clean up removing the temporary holder
}

document.onkeydown=function(e){
  if(e.altKey && e.which == 49) { // Alt+1
    copy(link_variable);
    return false;
  }
}

有什么想法吗?

正在添加清单文件:

{
  "manifest_version": 2,
  "name": "Usage text",
  "version": "0.2",
  "description": "Whatever",
  "content_scripts": [
    {
      "matches": [
        "*://some.specific.site.com/*"
      ],
      "js": ["content.js"]
    }
  ],
  "background": {
    "scripts": ["background.js"]
  },
  "browser_action": {
      "name": "Whatever",
      "default_icon": "icon.png"
  },
  "permissions": [
    "tabs",
    "clipboardWrite"
  ]
}

更新:

将操作从content脚本转移到background脚本,没有变化。

尝试 Chromium 59 问题中的代码时记录了此警告:

[Deprecation] The behavior that Selection.addRange() merges existing Range and the specified Range was removed. See https://www.chromestatus.com/features/6680566019653632 for more details.

那个

  1. 带我去提到的 Chrome status

    In a case where document already has text selection and Selection.addRange() is called, Blink merges the Range and the existing text selection into one if they have overlap, and does nothing otherwise. We'll change it so that Blink always ignore the Range. It matches to Edge.

    哪个

  2. 带我去 discussion on that W3C specification 哪个

  3. 让我读了 W3C specification

根据规范 addRange() 如果已经有选择则什么都不做:

  1. If rangeCount is not 0, abort these steps.

有趣的是,似乎已经有了一个选择。检查 window. getSelection().rangeCount 证实了这一点。我无法解释这是为什么,但这是问题中提到的问题的原因。

addRange() 之前调用 removeAllRanges() 解决了问题:

var sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);