Chrome Selection.addRange() не выбирает (вариант использования execCommand('copy'))

Написание крошечного расширения браузера в Chrome для копирования определенного текста с определенных веб-страниц в буфер обмена. В формате HTML, чтобы люди могли вставлять его в офисные программы, такие как Word, Outlook и т. д.

document.execCommand('copy') — это команда, которую я использую, она запускается комбинацией клавиш document.onkeydown (Alt+1) и работает нормально, но только в первый раз. Если вы попытаетесь нажать комбинацию клавиш еще раз, это ничего не даст.

Я нашел причину этого, document.queryCommandEnabled("copy") возвращает true в первый раз и false при любой дополнительной попытке. Если я перезагружу страницу, она снова возвращает true в первый раз. Кроме того, если я щелкну за пределами окна браузера после загрузки страницы, а затем щелкну в браузере и использую комбинацию клавиш, он немедленно вернет false, даже в первый раз.

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, без изменений.


person fault-tolerant    schedule 13.07.2017    source источник
comment
Включили ли вы clipboardWrite разрешение в свой манифест?   -  person Derek 朕會功夫    schedule 13.07.2017
comment
Спасибо, и нет, я этого не делал, но попробовал это сейчас после вашего комментария, и результат тот же. Добавлен (обновленный) файл манифеста.   -  person fault-tolerant    schedule 13.07.2017


Ответы (1)


При попытке кода из вопроса Chromium 59 зарегистрировал это предупреждение:

[Устаревшее] Поведение, при котором Selection.addRange() объединяет существующий диапазон и указанный диапазон, было удалено. Дополнительные сведения см. на странице https://www.chromestatus.com/features/6680566019653632.

Тот

  1. #P4# <блочная цитата> #P5# #P6#
  2. привести меня к обсуждению той спецификации W3C, которая

  3. заставил меня прочитать спецификацию W3C.

Согласно спецификации addRange() ничего не должен делать, если уже есть выбор:

  1. Если rangeCount не равен 0, прервите эти шаги.

Что интересно, вроде уже есть выбор. Проверка window. getSelection().rangeCount подтвердила это. Я не могу объяснить, почему это так, но это причина проблемы, упомянутой в вопросе.

Звонок removeAllRanges() до того, как addRange() решил проблему:

var sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
person try-catch-finally    schedule 15.07.2017
comment
Опять же, теперь я столкнулся с другой проблемой: команда addRange выбирает весь HTML-код документа, то есть автоматически сгенерированный HTML-документ, вместе с временным элементом div: <script src="background.js"></script> <div contenteditable="true" style="opacity: 0; position: absolute; pointer-events: none; z-index: -1;"> <a href="link.address.com" style="all: initial">Just the link text</a></div>" Сюда также входит <br class="Apple-interchange-newline"> сразу после <script>. - person fault-tolerant; 16.07.2017
comment
Выбор всего содержимого веб-страницы решается с помощью функции selectText из этого ответа. Спасибо, @try-catch-finally! - person fault-tolerant; 17.07.2017
comment
@try-catch-наконец-то ты гений! добавление removeAllRanges() до addRange() работает отлично. - person user2677034; 18.12.2017