No Chrome 120, uma nova opção unsanitized
está disponível na área de transferência assíncrona
API. Essa opção pode ajudar em situações especiais com HTML, em que você precisa
cole o conteúdo da área de transferência idêntico ao que estava quando ela foi copiada.
Ou seja, sem nenhuma etapa de sanitização intermediária que os navegadores comumente - e
por um bom motivo, faça sua inscrição. Aprenda a usá-la neste guia.
Ao trabalhar com o API Async Clipboard, na maioria dos casos, os desenvolvedores não precisam se preocupar com a integridade o conteúdo na área de transferência e podem presumir que o que foi gravado na área de transferência (cópia) é o mesmo que eles vão receber quando ler os dados da área de transferência (colar).
Isso é verdade para texto. Tente colar o seguinte código no DevTools
Console e, em seguida, mude o foco da página imediatamente. O setTimeout()
é necessário
para que você tenha tempo suficiente para focar na página, o que é um requisito do
API Clipboard. A entrada é exatamente igual à saída.
setTimeout(async () => {
const input = 'Hello';
await navigator.clipboard.writeText(input);
const output = await navigator.clipboard.readText();
console.log(input, output, input === output);
// Logs "Hello Hello true".
}, 3000);
Com imagens é um pouco diferente. Para evitar os chamados ataques de bomba de compressão, navegadores recodificar imagens como PNGs, mas as imagens de entrada e saída são visualmente exatamente o mesmo, pixel por pixel.
setTimeout(async () => {
const dataURL =
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVQYV2NgYAAAAAMAAWgmWQ0AAAAASUVORK5CYII=';
const input = await fetch(dataURL).then((response) => response.blob());
await navigator.clipboard.write([
new ClipboardItem({
[input.type]: input,
}),
]);
const [clipboardItem] = await navigator.clipboard.read();
const output = await clipboardItem.getType(input.type);
console.log(input.size, output.size, input.type === output.type);
// Logs "68 161 true".
}, 3000);
Mas o que acontece com o texto HTML? Como você deve ter adivinhado, com o HTML,
é diferente. Aqui, o navegador limpa o código HTML para evitar
que aconteçam coisas como, por exemplo, removendo tags <script>
do HTML.
(e outros, como <meta>
, <head>
e <style>
) e inline do CSS.
Considere o exemplo a seguir e teste no Console do DevTools. Você vai
observe que a saída é muito diferente da entrada.
setTimeout(async () => {
const input = `<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="ProgId" content="Excel.Sheet" />
<meta name="Generator" content="Microsoft Excel 15" />
<style>
body {
font-family: HK Grotesk;
background-color: var(--color-bg);
}
</style>
</head>
<body>
<div>hello</div>
</body>
</html>`;
const inputBlob = new Blob([input], { type: 'text/html' });
await navigator.clipboard.write([
new ClipboardItem({
'text/html': inputBlob,
}),
]);
const [clipboardItem] = await navigator.clipboard.read();
const outputBlob = await clipboardItem.getType('text/html');
const output = await outputBlob.text();
console.log(input, output);
}, 3000);
A sanitização de HTML geralmente é positiva. Você não quer se expor a problemas de segurança, permitindo HTML sem correção na maioria dos casos. são cenários, porém, em que o desenvolvedor sabe exatamente o que está fazendo e em que a integridade do HTML de entrada e de saída é crucial para o correto e funcionamento do app. Nessas circunstâncias, você tem duas opções:
- Se você controlar a ação de copiar e colar, por exemplo, de dentro do aplicativo para colar dentro do aplicativo, use Formatos personalizados da Web para a API Async Clipboard. Pare de ler aqui e confira o artigo vinculado.
- Se você controlar apenas a extremidade de colar no app, mas não a de cópia,
talvez porque a operação de cópia aconteça em um app nativo que não suporte
formatos personalizados da Web, use a opção
unsanitized
, que é explicado no restante deste artigo.
A limpeza inclui ações como remover tags script
, estilos in-line e
garantindo que o HTML esteja bem formado. Essa lista não está completa e muito mais
etapas podem ser adicionadas no futuro.
Copiar e colar HTML não limpo
Quando você write()
(copia) HTML para a área de transferência com a API Async Clipboard,
o navegador verifica se a formatação está correta, executando-o por meio de um analisador DOM
e serializando a string HTML resultante, mas nenhuma limpeza está acontecendo na
nesta etapa. Você não precisa fazer nada. Quando você read()
o HTML colocado no
área de transferência por outro aplicativo e seu aplicativo da web estiver optando por obter a
conteúdo de fidelidade total e precisar realizar qualquer sanitização em seu próprio código,
é possível transmitir um objeto de opções para o método read()
com uma propriedade.
unsanitized
e um valor de ['text/html']
. Isoladamente, o resultado será semelhante a este:
navigator.clipboard.read({ unsanitized: ['text/html'] })
: O exemplo de código a seguir
abaixo é quase igual à mostrada anteriormente, mas com o unsanitized
é a melhor opção. Ao testá-lo no Console do DevTools, você verá que a entrada e
e a saída é a mesma.
setTimeout(async () => {
const input = `<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="ProgId" content="Excel.Sheet" />
<meta name="Generator" content="Microsoft Excel 15" />
<style>
body {
font-family: HK Grotesk;
background-color: var(--color-bg);
}
</style>
</head>
<body>
<div>hello</div>
</body>
</html>`;
const inputBlob = new Blob([input], { type: 'text/html' });
await navigator.clipboard.write([
new ClipboardItem({
'text/html': inputBlob,
}),
]);
const [clipboardItem] = await navigator.clipboard.read({
unsanitized: ['text/html'],
});
const outputBlob = await clipboardItem.getType('text/html');
const output = await outputBlob.text();
console.log(input, output);
}, 3000);
Suporte a navegadores e detecção de recursos
Não há uma forma direta de verificar se o recurso é compatível. Portanto,
baseada na observação do comportamento. Portanto, o exemplo a seguir
depende da detecção da sobrevivência de uma tag <style>
, que
indica compatibilidade, ou está sendo em linha, o que indica não compatível. Observe que
Para que isso funcione, a página já precisa ter a área de transferência
permissão.
const supportsUnsanitized = async () => {
const input = `<style>p{color:red}</style><p>a`;
const inputBlob = new Blob([input], { type: 'text/html' });
await navigator.clipboard.write([
new ClipboardItem({
'text/html': inputBlob,
}),
]);
const [clipboardItem] = await navigator.clipboard.read({
unsanitized: ['text/html],
});
const outputBlob = await clipboardItem.getType('text/html');
const output = await outputBlob.text();
return /<style>/.test(output);
};
Demonstração
Para ver a opção unsanitized
em ação, consulte o
demonstração do Glitch e confira
código-fonte.
Conclusões
Conforme descrito na introdução, a maioria dos desenvolvedores nunca vai precisar se preocupar com
limpeza da área de transferência e podem trabalhar com as opções de limpeza padrão
feita pelo navegador. Nos raros casos em que os desenvolvedores precisam se importar, os
A opção unsanitized
já existe.
Links úteis
Agradecimentos
Este artigo foi revisado por Anupam Snigdha e Rachel Andrew. A API foi especificada e implementado pela equipe do Microsoft Edge.