JavaScript. Работа с буфером, Ctrl+C Ctrl+V

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Как копировать в буфер картинки. Какие типы данных можно класть в буфер. Поддержка кастомных типов. Как сделать свои кнопки копировать/вставить.

Рис 1. Копирование между вкладками редактора блок-схем и Google Docs
Рис 1. Копирование между вкладками редактора блок-схем и Google Docs

Задача

Сделать копирование для редактора блок-схем dgrm.net.

  • Копировать можно между вкладками.

  • Можно копировать в Word/Google docs, тогда схема вставляется как картинка.

  • Должны работать горячие клавиши Ctrl+C, Ctrl+V, Ctrl+X.

  • Свои кнопки копировать/вставить, чтобы можно было копировать мышкой.

  • Поддержка мобильных.

Варианты API работы с буфером

document.execCommand('copy') не работает

Это API устарело и не работает. Не пытайтесь с его помощью обойти ограничения других API.

Работа с буфером в обработчиках событий 'copy', 'paste', 'cut'

document.addEventListener('copy', evt => {
	evt.preventDefault();
	evt.clipboardData.setData('text/plain', 'text to clipboard');
});

Листинг 1. Пишем в буфер на событии “вставить”

В этом варианте нет возможности сделать свою кнопку “копировать”, пользователь должен нажать Ctrl+C.

navigator.clipboard.read/wright

btn.addEventListener('click', async _ => 
	await navigator.clipboard.writeText('text to clipboard')
);

Листинг 2. Пишем в буфер по клику на кнопке

Можно сделать свою кнопку “копировать”. Работает во всех браузерах и на мобильных.
В Safari есть ограничение: нельзя использовать в callback-ах. Так в Safari не работает:

btn.addEventListener('click', async _ => 
	// create png from svg
	svgToPng(
		svg,
		// callback
		async png => await navigator.clipboard.write(...))
);

Листинг 3. Не работает в Safari. Нельзя использовать navigator.clipboard в callback-ах. Как писать картинку в буфер в следующем разделе.

Это ограничение безопасности: когда придет callback не понятно, пользователь может уже и передумал копировать.
Можно сделать так: строку гарантированно пишем в буфер, если браузер разрешит запишем картинку.

// guaranteed clipboard write
await navigator.clipboard.writeText('text to clipboard');

// try to write img
// if ok -> clipboard will be overwritten
try {
	// create png from svg
	svgToPng(
		svg,
		// callback
		async png => await navigator.clipboard.write(...));
} catch { }

Листинг 4. Запись текста в буфер гарантирована, если браузер разрешит запишем картинку

Как записать картинку в буфер

await navigator.clipboard.write([new window.ClipboardItem({
	'image/png': Promise.resolve(png), // png is Blob
	'text/plain': Promise.resolve(new Blob(['text to clipboard'], { type: 'text/plain' }))
})]);

Листинг 5. Запись картинки и альтернативного текста в буфер.

В буфер можно записать одновременно несколько типов данных. Например, картинку и текст. Если вставить в Word - вставится картинка, если в блокнот - текст.

Можно записывать такие типы:

  • text/plain

  • text/html

  • image/png

Некоторые браузеры поддерживают больше типов. Эти три работают везде.

Копировать в буфер можно только png. Другие форматы картинок не поддерживаются.
При копировании браузер “очищает” png. Для безопасности браузер удаляет из png метаданные.
Неприятность для dgrm.net. Dgrm.net хранит в метаданных описание схемы. Благодаря метаданным можно открыть картинку на редактирование - рис 2.

Рис 2. dgrm.net умеет открывать схемы из PNG картинок
Рис 2. dgrm.net умеет открывать схемы из PNG картинок

Кастомные типы данных в буфере

‘text/plain’ из буфера можно вставить куда угодно. Хорошо использовать свой тип данных, который читает только ваше приложение. Например ‘text/dgrm’.
Для безопасности браузер связывает самодельный тип с доменом. Таким образом посторонний сайт не прочитает из буфера ваш тип данных.

Не все браузеры поддерживают самодельные типы. В Chrome можно использовать кастомные типы, они обязательно должны иметь префикс ‘web ’ -> ‘web text/dgrm’.

Не все браузеры позволяют записать не ‘text/plain’ в буфер с помощью navigator.clipboard.write. Разрешают только в обработчиках событий 'copy', 'cut'. Т.е. свою кнопку “копировать” нельзя сделать.

В итоге остановился на navigator.clipboard.writeText который везде работает.

Чтение из буфера

Чтение буфера еще опаснее чем запись. Еще больше ограничений. В FireFox читать можно только в обработчике события ‘paste’. Свою кнопку “вставить” сделать нельзя, нужно чтобы пользователь нажал Ctrl V.

document.addEventListener('paste', evt => {
	const txt = evt.clipboardData.getData('text/plain');
});

Листинг 6. Чтение из буфера на событии ‘paste’

В других браузерах можно использовать navigator.clipboard API.

btn.addEventListener('click', async _ => 
	await navigator.clipboard.readText()
);

Листинг 7. Чтение из буфера по кнопке

Браузер запросит разрешение пользователя. iOS Safari будет спрашивать при каждом вызове navigator.clipboard.readText.

О редакторе dgrm.net

Dgrm.net - быстрый редактор без лишних кнопок.
Развиваю редактор. Анонсы обновлений начал писать в телеграм.
Попробуйте, напишите что нравится/не нравится. Все читаю, веду список предложений.

Источник: https://habr.com/ru/post/724904/


Интересные статьи

Интересные статьи

«В хосписе» — приложение, которое создали для сотрудников хосписов студенты Нетологии совместно с «Инновационным центром Ай-Теко». Ещё до релиза проект получил премию «Время инноваций 2021» как социал...
Привет! Меня зовут Иван Аксенов, я Ruby-разработчик в компании Домклик. Расскажу о своём подходе к анализу причин выпуска неудачных релизов.Человек склонен совершать ошибки в любой деятельности. Иногд...
Продолжаем рассказывать о сервисах, позволяющих записать собственный трек — будь то для домашнего проекта или чтобы отвлечься от рабочих задач.
Данные — краеугольный камень любой большой компании, которая так или иначе работает с людьми. Чем больше компания, тем больше пользователей её услуг и сервисов, тем больше этих самых данных о клиентах...
История началась в конце 2019 года... На тот момент я уже работал ведущим разработчиком в хайлоад стартапе в Москве в технически сильной команде, которая прошла школу топовых интернет компаний России....