Hasta ahora, la API de Async Clipboard admitía un conjunto limitado de tipos de MIME para copiar y pegar desde el portapapeles del sistema, específicamente: text/plain
, text/html
y image/png
. Por lo general, el navegador lo limpia para, por ejemplo, quitar elementos script
o vínculos javascript:
incorporados de una cadena HTML, o para evitar ataques de bomba de descompresión de PNG.
Sin embargo, en algunos casos, puede ser conveniente admitir contenido no sanitizado en el portapapeles:
- Situaciones en las que la aplicación se encarga de la limpieza.
- Situaciones en las que es fundamental que los datos copiados sean idénticos a los pegados.
En esos casos, la API de Async Clipboard ahora admite formatos web personalizados que permiten a los desarrolladores escribir datos arbitrarios en el portapapeles.
Navegadores compatibles
La API de Async Clipboard per se con compatibilidad con imágenes es compatible a partir de Chromium 76. Los formatos personalizados web para la API de Async Clipboard son compatibles con Chromium para computadoras y dispositivos móviles a partir de la versión 104.
Cómo escribir formatos web personalizados en el portapapeles
Escribir formatos web personalizados en el portapapeles es casi idéntico a escribir formatos limpios, excepto por la necesidad de agregar la cadena "web "
(incluido el espacio final) al tipo de MIME del 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);
}
Cómo leer formatos web personalizados desde el portapapeles
Al igual que con la escritura, leer formatos web personalizados desde el portapapeles es casi idéntico a leer formatos limpios. La única diferencia es que ahora la app debe buscar elementos del portapapeles cuyo tipo comience con "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);
}
Interoperabilidad con apps específicas de la plataforma
Los formatos personalizados web, como web image/jpeg
, no son algo que las aplicaciones típicas específicas de la plataforma comprendan (ya que esperarían image/jpeg
). Con el tiempo, se espera que las apps en cuestión agreguen compatibilidad con esos formatos como una opción de habilitación si sus desarrolladores consideran que la compatibilidad con los formatos personalizados web es relevante para sus usuarios. En el portapapeles del sistema operativo, los diferentes formatos están presentes en varios formatos listos para su uso, como se puede ver en la captura de pantalla de macOS que aparece a continuación.
Demostración
Puedes probar la demostración y ver el código fuente para ver cómo funciona.
Agradecimientos
Joe Medley y François Beaufort revisaron este documento.