Представляем новый способ создания пользовательских возможностей веб-редактирования с помощью API EditContext.

Разработчикам не всегда было легко внедрить расширенные возможности редактирования в свои веб-приложения. Веб-платформа обеспечивает возможность редактирования как обычного текста, так и документов HTML с помощью таких элементов, как <input> и <textarea> , или путем применения атрибута contenteditable к элементам. Однако базовых возможностей этих типов элементов часто недостаточно для того, чего разработчики хотят достичь в своих приложениях.

Разработчики часто реализуют собственное представление редактора, реализующее функциональные возможности, необходимые их пользователям. Представление редактора может быть построено с использованием сложного DOM или даже элемента <canvas> , но поскольку единственный способ для разработчика получить текстовый ввод требует сфокусированного редактируемого элемента, ему все равно придется поместить скрытый элемент contenteditable на их страница где-то.

В результате, хотя создается впечатление, что пользователь напрямую редактирует содержимое в представлении пользовательского редактора приложения, разработчик на самом деле получает входные данные с помощью обработчиков событий в скрытом элементе, а затем отражает их в видимом представлении редактора. Это может привести к проблемам, поскольку разработчику приходится бороться с поведением редактирования по умолчанию в браузере в скрытом элементе contenteditable .

Чтобы решить этот класс проблем, команда Microsoft Edge провела стандартизацию EditContext , нового API веб-платформы, который позволяет разработчикам получать ввод текста напрямую, не привязываясь к стандартному поведению браузера при редактировании.

Реальный пример

Например, когда пользователи совместно работают в Word Online. Пользователи могут совместно редактировать и видеть изменения друг друга и положения курсора. Однако если один из соавторов использует окно редактора метода ввода (IME) , например, для составления текста на японском языке, его редактор не будет обновляться для отображения изменений, внесенных другими пользователями, пока пользователь IME не завершит свое составление. Это связано с тем, что внесение изменений в редактируемую область DOM при наличии активной композиции IME может привести к преждевременной отмене композиции. Приложению приходится ждать закрытия окна IME, чтобы обновить представление, что может вызвать задержки и затруднить совместную работу.

Проблемы с совместной работой в Word Online при написании текста

Чтобы обеспечить лучший опыт для разработчиков и пользователей, разработчикам нужен способ отделить ввод текста от представления HTML DOM. API EditContext является решением этой проблемы.

Основы EditContext

С помощью EditContext вы можете получать входные данные текста и композиции непосредственно через поверхность API EditContext, а не путем наблюдения за изменениями в DOM. Это позволяет более жестко контролировать обработку ввода и даже позволяет добавить возможность редактирования к элементу <canvas> .

Связывание экземпляра EditContext с элементом делает его редактируемым:

// 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);
 });

Обязанности автора

Использование API EditContext упрощает поддержку расширенных методов ввода, таких как окна композиции IME, средства выбора смайлов и другие поверхности ввода операционной системы. Чтобы все это стало возможным в вашем редактируемом элементе, API EditContext требует некоторой информации. Помимо рендеринга текста и выделения, при использовании EditContext API необходимо выполнить некоторые другие действия.

Управление стороной редактируемой области или изменением выбора пользователя

Вызовите методы updateControlBounds() и updateSelectionBounds() , чтобы информировать экземпляр EditContext всякий раз, когда изменяется размер редактируемой области или выбор пользователя. Это помогает платформе решить, где показывать окна IME и другой пользовательский интерфейс редактирования, специфичный для платформы.

// 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);

Управление положением пользовательского интерфейса редактора

Прослушайте characterboundsupdate и вызовите updateCharacterBounds() в ответ, чтобы помочь платформе решить, где показывать окна IME и другой пользовательский интерфейс редактирования, специфичный для платформы.

Применение форматирования

Прослушайте событие textformatupdate и примените форматирование, указанное событием, к представлению редактора. Эти текстовые украшения используются IME при составлении определенных языков. Например, японский IME будет использовать подчеркивание, чтобы показать, какая часть текста активно составляется.

Снимок экрана окна редактора метода ввода, используемого для ввода японских символов.

Обработка поведения при редактировании форматированного текста

Прослушайте событие beforeinput , чтобы обработать любые варианты редактирования форматированного текста, которые вы хотели бы поддерживать, например, горячие клавиши для выделения текста жирным шрифтом или курсивом или применение исправления проверки орфографии.

Управление изменениями в выборе пользователей

Когда выбор пользователя изменяется из-за ввода с клавиатуры или мыши, вам необходимо сообщить об этом экземпляру EditContext. Это необходимо из-за применимости API EditContext к широкому числу случаев использования, включая редакторы, отображаемые с помощью элемента <canvas> , где браузер не может автоматически обнаружить изменения выбора.

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);
});

Если элемент, который вы используете с EditContext, является элементом <canvas> , вам также потребуется реализовать поведение выбора и навигации по курсору, например навигацию по тексту с помощью клавиш со стрелками. Кроме того, встроенная в браузере проверка орфографии работает только с элементами, отличными от <canvas> .

EditContext против contenteditable

EditContext — отличный выбор, если вы реализуете полнофункциональный редактор и хотите иметь полный контроль над тем, как обрабатывается ввод текста, или если вы добавляете расширенные функции, такие как совместное редактирование с несколькими пользователями. Однако, учитывая все предыдущие требования для использования EditContext, если все, что вам нужно, это простая поддержка редактирования текста, вы, вероятно, все равно захотите использовать элементы <input> , <textarea> или атрибут contenteditable .

С нетерпением жду

Команда Microsoft Edge внедрила EditContext в Chromium в сотрудничестве с инженерами Chrome и выпускает версию 121 (январь 2024 г.) как Chrome, так и Edge. На данный момент он доступен только в браузерах на базе Chromium, но вы можете ознакомиться с позициями Mozilla и WebKit по API EditContext.

Мы хотим, чтобы веб-разработчикам было проще создавать мощные возможности пользовательского редактирования в Интернете, и мы считаем, что EditContext API достигает этой цели, решая существующие проблемы и предлагая более прямой способ обработки ввода текста.

Если вы хотите узнать больше об API, обратитесь к документации MDN . Чтобы оставить отзыв о дизайне API, откройте проблему в репозитории EditContext API на Github . Чтобы сообщить об ошибках в реализации API, отправьте сообщение об ошибке на crbug.com .