Nem sempre foi uma tarefa simples para os desenvolvedores incorporar recursos avançados de edição aos aplicativos da Web. A plataforma da Web oferece recursos de edição para documentos de texto simples e HTML usando elementos como <input>
e <textarea>
ou aplicando o atributo contenteditable
aos elementos. No entanto, os recursos básicos desses tipos de elementos geralmente não são suficientes para o que os desenvolvedores querem alcançar nos apps.
Os desenvolvedores geralmente implementam a própria visualização de editor personalizada que implementa a funcionalidade necessária para os usuários. A visualização do editor pode ser criada com um DOM complexo ou até mesmo com um elemento <canvas>
. No entanto, como a única maneira de o desenvolvedor receber a entrada de texto exige um elemento editável focado, ele ainda precisa colocar um elemento contenteditable
oculto na página em algum lugar.
O resultado é que, enquanto o usuário parece estar editando o conteúdo diretamente na visualização de editor personalizada do aplicativo, o desenvolvedor está, na verdade, recebendo a entrada com manipuladores de eventos no elemento oculto e, em seguida, espelhando-a na visualização do editor visível. Isso pode causar problemas, já que o desenvolvedor acaba conflitando com o comportamento de edição padrão do navegador no elemento contenteditable
oculto.
Para resolver esse tipo de problema, a equipe do Microsoft Edge promoveu a padronização do EditContext, uma nova API da plataforma da Web que permite que os desenvolvedores recebam entrada de texto diretamente sem estarem vinculados aos comportamentos de edição padrão do navegador.
Exemplo real
Por exemplo, quando os usuários estão colaborando no Word Online. Os usuários podem editar em conjunto e conferir as mudanças e posições do cursor uns dos outros. No entanto, se um colaborador estiver usando uma janela Editor de método de entrada (IME, na sigla em inglês) para escrever texto em japonês, por exemplo, o editor não será atualizado para mostrar alterações de outros usuários até que o usuário do IME termine a composição. Isso ocorre porque fazer mudanças na área do DOM que está sendo editada enquanto há uma composição de IME ativa pode fazer com que a composição seja cancelada prematuramente. O aplicativo precisa esperar até que a janela do IME seja fechada para atualizar a visualização, o que pode causar atrasos e dificultar a colaboração.
Para oferecer uma melhor experiência ao desenvolvedor e ao usuário, os desenvolvedores precisam de uma maneira de separar a entrada de texto da visualização DOM HTML. A API EditContext é a solução para esse problema.
Princípios básicos do EditContext
Com o EditContext, é possível receber entrada de texto e composição diretamente pela plataforma da API EditContext, em vez de observar mudanças no DOM. Isso permite um controle mais rígido sobre como a entrada é processada e até mesmo adicionar editabilidade ao elemento <canvas>
.
Associar uma instância do EditContext a um elemento o torna editável:
// This will be our editable element.
const element = document.querySelector('#editor-element');
// Creating the EditContext object.
const editContext = new EditContext();
// Associating the EditContext object with our DOM element.
// The element is now focusable and can receive text input.
element.editContext = editContext;
// In order to render the text typed by the user onto the
// page, as well as the user's selection, you'll need to
// receive the input in a textupdate event callback.
editContext.addEventListener('textupdate', event => {
element.textContent = editContext.text;
// For brevity, the code to render the selection
// isn't shown here.
renderSelection(event.selectionStart, event.selectionEnd);
});
Responsabilidades do autor
O uso da API EditContext facilita o suporte a métodos de entrada avançados, como janelas de composição de IME, seletores de emoji e outras plataformas de entrada do sistema operacional. Para que tudo isso seja possível no elemento editável, a API EditContext precisa de algumas informações. Além de renderizar o texto e a seleção, há outras coisas que você precisa fazer ao usar a API EditContext.
Gerenciar o lado de uma região editável ou se a seleção do usuário mudar
Chame os métodos updateControlBounds()
e updateSelectionBounds()
para informar a instância do EditContext sempre que o tamanho da região editável ou a seleção do usuário mudar. Isso ajuda a plataforma a decidir onde mostrar as janelas do IME e outras interfaces de edição específicas da plataforma.
// It's necessary to provide bounds information because EditContext
// is generic enough to work with any type of web editor, even
// <canvas>-based editors. The API doesn't make any assumptions as
// to how the editor is implemented or how the selection is rendered.
// Bounds are given in the client coordinate space.
const controlBound = editorElement.getBoundingClientRect();
const selection = document.getSelection();
const selectionBound = selection.getRangeAt(0).getBoundingClientRect();
editContext.updateControlBounds(controlBound);
editContext.updateSelectionBounds(selectionBound);
Gerenciar a posição da interface do editor
Detecte o evento characterboundsupdate
e chame updateCharacterBounds()
para ajudar a plataforma a decidir onde mostrar as janelas do IME e outras interfaces de edição específicas da plataforma.
Como aplicar formatação
Detecte o evento textformatupdate
e aplique a formatação especificada pelo evento à visualização do editor. Essas decorações de texto são usadas pelos IMEs ao digitar em determinados idiomas. Por exemplo, um IME japonês usa um sublinhado para mostrar qual parte do texto está sendo ativamente composta.
Processamento de comportamentos de edição de rich text
Ouça o evento beforeinput
para processar todos os comportamentos de edição de rich text que você quer oferecer, como teclas de atalho para negrito ou itálico do texto ou aplicação de uma correção de verificação ortográfica.
Como gerenciar mudanças nas seleções de usuários
Quando a seleção do usuário muda devido à entrada do teclado ou do mouse, é necessário informar a instância do EditContext da mudança. Isso é necessário devido à aplicabilidade da API EditContext a um grande número de casos de uso, incluindo editores renderizados com o elemento <canvas>
em que o navegador não consegue detectar mudanças de seleção automaticamente.
document.addEventListener('selectionchange', () => {
const selection = document.getSelection();
// EditContext doesn't handle caret navigation, so all the caret navigation/selection that happens
// in DOM space needs to be mapped to plain text space by the author and passed to EditContext.
// This example code assumes the editable area only contains text under a single node.
editContext.updateSelection(selection.anchorOffset, selection.focusOffset);
});
Se o elemento que você está usando com o EditContext for um elemento <canvas>
, também será necessário implementar comportamentos de seleção e navegação com a seta, como navegar pelo texto com as teclas de seta. Além disso, a verificação ortográfica integrada do navegador só funciona em elementos que não sejam <canvas>
.
EditContext e contenteditable
O EditContext é uma ótima opção se você estiver implementando um editor completo e quiser ter controle total sobre como a entrada de texto é processada ou se estiver adicionando recursos avançados, como a edição colaborativa com vários usuários. No entanto, considerando todos os requisitos anteriores para usar o EditContext, se tudo o que você precisa é de suporte simples de edição de texto, provavelmente ainda vai querer usar <input>
, elementos <textarea>
ou o atributo contenteditable
.
Para o futuro
A equipe do Microsoft Edge implementou o EditContext no Chromium em colaboração com os engenheiros do Chrome e está sendo enviado com a versão 121 (janeiro de 2024) do Chrome e do Edge. Por enquanto, ele só está disponível em navegadores baseados no Chromium, mas você pode ler as posições do Mozilla e do WebKit (links em inglês) na API EditContext.
Queremos facilitar a criação de experiências de edição personalizadas e eficientes na Web. A API EditContext faz isso ao resolver desafios e oferecer uma maneira mais direta de processar entradas de texto.
Se você quiser saber mais sobre a API, consulte a documentação do MDN. Para enviar feedback sobre o design da API, abra um problema no repositório do GitHub da API EditContext. Para informar bugs na implementação da API, envie um bug em crbug.com.