Formatos web personalizados para la API de Async Clipboard

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 depura para, por ejemplo, quitar elementos script o vínculos javascript: incorporados de una cadena HTML o evitar ataques de bomba de descompresión PNG.

Sin embargo, en algunos casos, puede ser conveniente admitir contenido no depurado en el portapapeles:

  • Situaciones en las que la aplicación se ocupa de la limpieza en sí.
  • Situaciones en las que es fundamental que los datos copiados sean idénticos a los que se pegaron

En estos casos, la API de Async Clipboard ahora admite formatos web personalizados que permiten a los desarrolladores escribir datos arbitrarios en el portapapeles.

Navegadores compatibles

A partir de Chromium 76, se admite la API de Async Clipboard per se compatible con imágenes. Los formatos personalizados web para la API de Async Clipboard son compatibles con computadoras de escritorio y con Chromium para dispositivos móviles a partir de la versión 104.

Escribiendo formatos web personalizados en el portapapeles

Escribir formatos personalizados web en el portapapeles es casi idéntico a escribir formatos depurados, excepto por el requisito de anteponer la string "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);
}

Leyendo formatos personalizados de la Web desde el portapapeles

Al igual que con la escritura, leer formatos personalizados web desde el portapapeles es casi idéntico a leer formatos depurados. La única diferencia es que la app ahora 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 específicas de la plataforma típicas comprendan (ya que esperarían image/jpeg). Con el tiempo, se espera que las apps en cuestión agreguen compatibilidad con dichos formatos si sus desarrolladores consideran que la compatibilidad con formatos personalizados en la Web es relevante para sus usuarios. En el portapapeles del sistema operativo, los distintos formatos están presentes en varios formatos listos para el consumo, como se puede ver en la captura de pantalla de macOS a continuación.

Ejecutor de portapapeles en macOS que muestra un mapa de formato personalizado que enumera dos formatos personalizados web.

Demostración

Puedes probar la siguiente demostración y ver el código fuente para ver cómo funciona.

Agradecimientos

Joe Medley y François Beaufort revisaron este artículo. Hero image de Neon Tommy, utilizada bajo una licencia CC BY-SA 2.0.