it-swarm.com.ru

javascript вырезать/копировать/вставить в буфер обмена: как Google решил это?

Да, этот вопрос задавался снова и снова: как копировать и вставлять из и в системный буфер обмена с помощью javascript? До сих пор я нашел только частичные решения и взломы .. Причина, по которой его так часто спрашивали в прошлом, заключается в том, что до сих пор нет рабочего решения. Тем не менее, я увидел, что Google Docs теперь имеет работающее решение как для событий клавиатуры, так и для кнопок. Итак, это возможно, но как они это делают? Статья Software Salad, Доступ к системному буферу обмена с помощью JavaScript - Святой Грааль? , дает хороший обзор проблемы (но ей несколько лет).

Короче:

  • вы можете использовать события клавиатуры ctrl + x, ctrl + c, ctrl + v, чтобы либо скопировать текст из скрытой текстовой области с подготовленными данными, либо перехватить вставленный текст в скрытом поле, а затем что-то сделать с ним

  • вы можете использовать взлом через Flash или Java-апплет, чтобы скопировать что-то в системный буфер обмена без необходимости одобрения пользователя.

  • вы можете использовать «реальное» решение с clipboardData.setData для IE и execCommand для других браузеров, что зависит от одобрения пользователя.

Есть идеи, как Google решил проблему с буфером обмена?

22
Jos de Jong

[Примечание: Этот ответ был точным на момент написания и правильно ответил на вопрос ОП. Тем не менее, технологии развивались с тех пор; если вы заинтересованы в поддержке копирования и вставки в своем веб-приложении, см. другие, более свежие ответы на этой странице. -ruakh]


Тем не менее, я увидел, что Google Docs теперь имеет работающее решение как для событий клавиатуры, так и для кнопок.

Нет, это не так. На самом деле, нет. Для событий клавиатуры Google Docs ничего не делает; он просто не выполняет блок функцию копирования и вставки по умолчанию в браузере; Таким образом, пользователи могут свободно копировать и вставлять, не мешая Документам Google. Что касается кнопок, Google Docs не поддерживает буфер обмена system, но имеет собственный «веб-буфер обмена», который полностью находится в Google Docs. Вы не можете использовать кнопки панели инструментов для копирования текста для вставки в другую программу на вашем компьютере или для вставки текста, скопированного из другой программы на вашем компьютере.

Для получения дополнительной информации об этом см. «Копирование и вставка в Google Docs» . (Это ориентировано на пользователя, а не на разработчика, но оно делает достойную работу, давая понять, что поддерживается и не поддерживается.)

10
ruakh

Я знаю, что этот вопрос был опубликован давно, но мне нужно было проверить, как Google это делает, так что, возможно, кто-то найдет это полезным.

На самом деле Google использует также системный буфер обмена, но это немного сложно. В случае, когда вы используете сочетание клавиш, вы можете перехватить событие копирования/вставки/вырезания, например, на. окно:

window.addEventListener('copy', function (ev) {
    console.log('copy event');
    // you can set clipboard data here, e.g.
    ev.clipboardData.setData('text/plain', 'some text pushed to clipboard');
    // you need to prevent default behaviour here, otherwise browser will overwrite your content with currently selected 
    ev.preventDefault();
});

живой пример для сочетания клавиш: http://jsfiddle.net/tyk9U/

К сожалению, это только решение для сочетания клавиш, и существует проблема с контекстным меню, потому что вы не можете получить доступ к данным буфера обмена без собственного (доверенного) события копирования/вырезания/вставки. Но Google делает интересный трюк. Существует API document.execCommand(), который позволяет вам запускать команды для contenteditable элемента, и есть команда «copy», которую вы можете вызвать с помощью document.execCommand('copy'). Но когда вы попробуете это в консоли в Chrome, он вернет false. Я потратил немного времени на изучение этого, и оказалось, что у них установлено расширение Chrome, которое называется «Диск Google» (перейдите по адресу chrome: // apps /, и вы можете увидеть его там), которое обеспечивает доступ к буферу обмена для доменов drive.google. com и docs.google.com. Откройте какой-нибудь документ или электронную таблицу и введите в консоли document.execCommand('copy') - он вернет true. При удалении расширения вы не сможете использовать операции с буфером обмена из контекстного меню.

Вы можете создать такое приложение для себя с очень простым файлом манифеста (подробности здесь https://developer.chrome.com/apps/first_app ):

{
    "manifest_version": 2,
    "name": "App name",
    "description": "App description",
    "version": "1.0",
    "app": {
        "urls": [
            "http://your.app.url.here/"
        ],
        "launch": {
            "web_url": "http://your.app.url.here/"
        }
    },
    "icons": {
        "128": "x-128.png"
    },
    "permissions": [
        "clipboardRead",
        "clipboardWrite"
    ]
}

Поле «разрешения» здесь включает операции с буфером обмена.

Теперь, когда вы включили эту функцию, вы можете выполнить document.execCommand('copy'), и она будет работать (вернет true). Но это еще не все - document.execCommand('copy') в chrome вызывает событие копирования, и вы можете поймать его с помощью того же кода, который используется для перехвата сочетаний клавиш клавиатуры. Это сейчас Google делает это.

Конечно, это описание действительно только для Chrome.

25
Mateusz W

В дополнение к тому, что другие уже опубликовали в этой теме, я создал полностью рабочий пример, который демонстрирует подход сочетания клавиш (CTRL + C или CMD + C в Mac OS X), а также подход с использованием настраиваемой кнопки, запускающий действие копирования. 

Полное демо можно найти здесь: http://jsfiddle.net/rve7d/

Я нашел ответ Mateusz W очень полезным при попытке создать эту демонстрацию, но он не принял во внимание поддержку IE, которая ведет себя немного иначе и использует разные типы данных в качестве первого параметра.

if(window.clipboardData) {
    // use just 'Text' or 'Url' as a first param otherwise strange exception is thrown
    window.clipboardData.setData('Text', 'Text that will be copied to CB');        
} else if(ev.originalEvent.clipboardData) {
    ev.originalEvent.clipboardData.setData('text/plain', 'Text that will be copied to CB');      
} else {
    alert('Clipboard Data are not supported in this browser. Sorry.');
}

PS: мне понадобилась эта функциональность для нашего пользовательского компонента просмотра электронных таблиц, и я по дороге проанализировал исходный код электронных таблиц Google, поэтому мое решение в основном соответствует их решению.

4
Marek Suscak

Google использует очень простой, но классный метод. Используя firebug, вы узнаете, что загруженный HTML-код имеет текстовую область в начале размера 1. Что делает документ Google, так это то, что когда пользователь выбирает текст и нажимает Ctrl + C, он захватывает событие и по какой-то методике получает текст, который выбирается в контейнере документов и устанавливает значение текстовой области для этого содержимого. Чем он фокусируется и выделяет текстовую область. Теперь он выпускает событие ctrl + c. Но теперь текст выделен в текстовой области, поэтому при повторном выпуске события браузер копирует текст в текстовой области, и таким образом мы получаем скопированный текст

3
coder hacker
<p>COPY : </p>
<p>Email me at <a class="js-emaillink" href="mailto:[email protected]">[email protected]</a></p>
<p><button class="js-emailcopybtn" value="clipboard" >clipboard</button></p>
<textarea rows="10" cols = "12"></textarea>
<p>CUT: </p>
<p><textarea class="js-cuttextarea">Hello I'm some text</textarea></p>
<p><button class="js-textareacutbtn" disable>Cut Textarea</button></p>
<script>
//copy clipboard
var copyEmailBtn = document.querySelector('.js-emailcopybtn');
copyEmailBtn.addEventListener('click', function(event) {
  // Выборка ссылки с электронной почтой
  var emailLink = document.querySelector('.js-emaillink');
  var range = document.createRange();
  range.selectNode(emailLink);
  window.getSelection().addRange(range);
  try {
    // Теперь, когда мы выбрали текст ссылки, выполним команду копирования
    var successful = document.execCommand('copy');
    var msg = successful ? 'successful' : 'unsuccessful';
    console.log('Copy email command was ' + msg);
  } catch(err) {
    console.log('Oops, unable to copy');
  }
  // Снятие выделения - ВНИМАНИЕ: вы должны использовать
  // removeRange(range) когда это возможно
  window.getSelection().removeAllRanges();
});
//cut
var cutTextareaBtn = document.querySelector('.js-textareacutbtn');
cutTextareaBtn.addEventListener('click', function(event) {
  var cutTextarea = document.querySelector('.js-cuttextarea');
  cutTextarea.select();
  try {
    var successful = document.execCommand('cut');
    var msg = successful ? 'successful' : 'unsuccessful';
    console.log('Cutting text command was ' + msg);
  } catch(err) {
    console.log('Oops, unable to cut');
  }
});
</script>
0
zloctb