Javascript - Копировать строку в буфер обмена как text/html
Есть ли способ в javascript скопировать строку html (т.е. <b>xx<b>
) в буфер обмена как text/html, чтобы затем можно было вставить в него, например, сообщение gmail с форматированием (т.е. xx жирным шрифтом )
Существуют решения для копирования в буфер обмена как текст (текст/обычный), например qaru.site/info/314/..., но не как text/html
Мне нужно решение non flash, не jquery, которое будет работать хотя бы на IE11 FF42 и Chrome.
В идеале я хотел бы сохранить как текстовые, так и html-версии строки в буфере обмена так, чтобы правый можно вставить в зависимости от того, поддерживает ли объект html или нет.
Ответы
Ответ 1
Я сделал несколько изменений в тексте Loilo выше:
-
(а затем и восстановление) фокус на скрытый div запрещает FF переходить в бесконечную рекурсию при копировании из текстового поля
-
установка диапазона для внутренних дочерних элементов div предотвращает добавление хром в начало <br>
в начале
-
removeAllRanges on getSelection() предотвращает добавление существующего выбора (возможно, не требуется)
-
попробуйте/поймайте execCommand
-
лучше спрятать копию div
В OSX это не сработает. Safari не поддерживает execCommand, а хром OSX имеет известную ошибку https://bugs.chromium.org/p/chromium/issues/detail?id=552975
код:
clipboardDiv = document.createElement('div');
clipboardDiv.style.fontSize = '12pt'; // Prevent zooming on iOS
// Reset box model
clipboardDiv.style.border = '0';
clipboardDiv.style.padding = '0';
clipboardDiv.style.margin = '0';
// Move element out of screen
clipboardDiv.style.position = 'fixed';
clipboardDiv.style['right'] = '-9999px';
clipboardDiv.style.top = (window.pageYOffset || document.documentElement.scrollTop) + 'px';
// more hiding
clipboardDiv.setAttribute('readonly', '');
clipboardDiv.style.opacity = 0;
clipboardDiv.style.pointerEvents = 'none';
clipboardDiv.style.zIndex = -1;
clipboardDiv.setAttribute('tabindex', '0'); // so it can be focused
clipboardDiv.innerHTML = '';
document.body.appendChild(clipboardDiv);
function copyHtmlToClipboard(html) {
clipboardDiv.innerHTML=html;
var focused=document.activeElement;
clipboardDiv.focus();
window.getSelection().removeAllRanges();
var range = document.createRange();
range.setStartBefore(clipboardDiv.firstChild);
range.setEndAfter(clipboardDiv.lastChild);
window.getSelection().addRange(range);
var ok=false;
try {
if (document.execCommand('copy')) ok=true; else utils.log('execCommand returned false !');
} catch (err) {
utils.log('execCommand failed ! exception '+err);
}
focused.focus();
}
см. jsfiddle, где вы можете ввести html-сегмент в текстовое поле и скопировать в буфер обмена ctrl + c.
Ответ 2
Поскольку этот ответ привлек некоторое внимание, я полностью переписал грязный оригинал, чтобы его было легче понять. Если вы хотите посмотреть на предварительно исправленную версию, вы можете найти ее здесь.
Сложенный вопрос:
Могу ли я использовать JavaScript, чтобы скопировать форматированный вывод некоторого HTML-кода в буфер обмена пользователя?
Ответ:
Да, с некоторыми ограничениями, вы можете.
Решение:
Ниже приведена функция, которая будет делать именно это. Я протестировал его с вашими необходимыми браузерами, он работает во всех из них. Однако IE 11 запросит подтверждение этого действия.
Объяснение того, как это работает, можно найти ниже, вы можете в интерактивном режиме протестировать функцию в этом jsFiddle.
// This function expects an HTML string and copies it as rich text.
function copyFormatted (html) {
// Create container for the HTML
// [1]
var container = document.createElement('div')
container.innerHTML = html
// Hide element
// [2]
container.style.position = 'fixed'
container.style.pointerEvents = 'none'
container.style.opacity = 0
// Detect all style sheets of the page
var activeSheets = Array.prototype.slice.call(document.styleSheets)
.filter(function (sheet) {
return !sheet.disabled
})
// Mount the container to the DOM to make 'contentWindow' available
// [3]
document.body.appendChild(container)
// Copy to clipboard
// [4]
window.getSelection().removeAllRanges()
var range = document.createRange()
range.selectNode(container)
window.getSelection().addRange(range)
// [5.1]
document.execCommand('copy')
// [5.2]
for (var i = 0; i < activeSheets.length; i++) activeSheets[i].disabled = true
// [5.3]
document.execCommand('copy')
// [5.4]
for (var i = 0; i < activeSheets.length; i++) activeSheets[i].disabled = false
// Remove the container
// [6]
document.body.removeChild(container)
}
Объяснение:
Посмотрите на комментарии в коде выше, чтобы увидеть, где вы находитесь в следующем процессе:
- Мы создаем контейнер для размещения нашего HTML-кода.
- Мы делаем стиль контейнера скрытым и определяем активные таблицы стилей страницы. Причина будет объяснена в ближайшее время.
- Мы помещаем контейнер в страницу DOM.
- Мы удаляем, возможно, существующие выборы и выбираем содержимое нашего контейнера.
-
Мы делаем само копирование. На самом деле это многошаговый процесс: Chrome будет копировать текст так, как он его видит, с примененными стилями CSS, в то время как другие браузеры будут копировать его со стилями браузера по умолчанию. Поэтому мы отключим все пользовательские стили перед копированием, чтобы получить максимально согласованный результат.
- Прежде чем мы это сделаем, мы преждевременно выполняем команду
copy
. Это взлом для IE11: в этом браузере копирование должно быть подтверждено вручную один раз. Пока пользователь не нажмет кнопку "Подтвердить", пользователи IE будут видеть страницу без каких-либо стилей. Чтобы избежать этого, мы сначала копируем, ждем подтверждения, затем отключаем стили и копируем снова. На этот раз мы не получим диалоговое окно подтверждения, так как IE запоминает наш последний выбор. - Мы фактически отключаем стили страницы.
- Теперь мы снова выполняем команду
copy
. - Мы снова включаем таблицы стилей.
- Снимаем контейнер со страницы DOM.
И мы сделали.
Предостережения:
-
Отформатированный контент не будет идеально согласован в разных браузерах.
Как объяснено выше, Chrome (т.е. Механизм Blink) будет использовать другую стратегию, нежели Firefox и IE: Chrome будет копировать содержимое с использованием своих стилей CSS, но исключая любые стили, которые не определены.
Firefox и IE, с другой стороны, не будут применять CSS для конкретной страницы, они будут применять стили браузера по умолчанию. Это также означает, что к ним будут применены некоторые странные стили, например, шрифт по умолчанию (обычно это Times New Roman).
-
Из соображений безопасности браузеры разрешают выполнение функции только в результате взаимодействия с пользователем (например, щелчок, нажатие клавиши и т.д.)
Ответ 3
Прошло почти два года, и в настоящее время существует более простой способ достичь этого, используя clipboard.js.
Для этого требуется современный браузер (Chrome 42+, Firefox 41+, Opera 29+, Internet Explorer 9+, Safari 10+), но он скрывает сложность вставки текста с расширенным текстом (меньше кода для записи):
1) Ссылка clipboard.js
2) Создайте кнопку и в своем обработчике кликов создайте как неформатированный, так и форматированный (богатый) текст и используйте для копирования в буфер обмена:
clipboard.copy({
"text/plain": "Normal text comes here",
"text/html": "<b>Normal text</b> comes <div style="color: blue;">here</div>"
})
.then(
function() {
// success code here
},
function(err) {
// failure code here
}
);