Пользовательские веб-форматы для API Async Clipboard

До сих пор API Async Clipboard поддерживал ограниченный набор типов MIME для копирования и вставки из системного буфера обмена, а именно: text/plain , text/html и image/png . Браузер обычно очищает это, например, чтобы удалить встроенные элементы script или ссылки javascript: из строки HTML или предотвратить атаки бомбы декомпрессии PNG.

Однако в некоторых случаях может быть желательно поддерживать несанкционированный контент в буфере обмена:

  • Ситуации, когда приложение занимается непосредственно дезинфекцией.
  • Ситуации, когда крайне важно, чтобы скопированные данные были идентичны вставленным данным.

Для таких случаев API асинхронного буфера обмена теперь поддерживает пользовательские веб-форматы, которые позволяют разработчикам записывать произвольные данные в буфер обмена.

Поддержка браузера

API асинхронного буфера обмена как таковой с поддержкой изображений поддерживается с версии Chromium 76. Пользовательские веб-форматы для API асинхронного буфера обмена поддерживаются на настольных компьютерах и мобильных устройствах Chromium с версии 104.

Запись пользовательских веб-форматов в буфер обмена

Запись пользовательских веб-форматов в буфер обмена практически идентична записи очищенных форматов , за исключением требования добавлять строку "web " (включая конечный пробел) к MIME-типу BLOB-объекта.

// Fetch remote JPEG and GIF images and obtain their blob representations. const [jpegBlob, gifBlob] = await Promise.all([   fetch('image.jpg').then((response) => response.blob()),   fetch('image.gif').then((response) => response.blob()), ]);  try {   // Write the image data to the clipboard, prepending the blobs' actual   // types (`"image/jpeg"` and "image/gif") with the string `"web "`, so   // they become `"web image/jpeg"` and `"web image/gif"` respectively.   // The code elegantly makes use of computed property names:   // https://developer.mozilla.org/docs/Web/JavaScript/Reference/Operators/Object_initializer#computed_property_names.   const clipboardItem = new ClipboardItem({     [`web ${jpegBlob.type}`]: jpegBlob,     [`web ${gifBlob.type}`]: gifBlob,   });   await navigator.clipboard.write([clipboardItem]); } catch (err) {   console.error(err.name, err.message); } 

Чтение пользовательских веб-форматов из буфера обмена

Как и в случае с записью, чтение пользовательских веб-форматов из буфера обмена практически идентично чтению очищенных форматов . Единственное отличие заключается в том, что теперь приложению необходимо искать элементы буфера обмена, тип которых начинается с "web " .

try {   // Iterate over all clipboard items.   const clipboardItems = await navigator.clipboard.read();   for (const clipboardItem of clipboardItems) {     for (const type of clipboardItem.types) {       // Discard any types that are not web custom formats.       if (!type.startsWith('web ')) {         continue;       }       const blob = await clipboardItem.getType(type);       // Sanitize the blob if you need to, then process it in your app.     }   } } catch (err) {   console.error(err.name, err.message); } 

Взаимодействие с приложениями, специфичными для платформы

Пользовательские веб-форматы, такие как web image/jpeg не являются тем, что понимают типичные платформенно-зависимые приложения (поскольку они ожидают image/jpeg ). Со временем соответствующие приложения, как ожидается, добавят поддержку таких форматов в качестве опции, если их разработчики посчитают поддержку пользовательских веб-форматов актуальной для своих пользователей. В буфере обмена операционной системы различные форматы присутствуют в нескольких форматах, готовых к использованию, как можно увидеть на снимке экрана для macOS ниже.

Ожидатель буфера обмена в macOS, показывающий карту пользовательских форматов, в которой перечислены два пользовательских веб-формата.

Демо

Вы можете попробовать демо-версию и просмотреть исходный код, чтобы увидеть, как она работает.

Благодарности

Этот документ был проверен Джо Медли и Франсуа Бофортом .