Stosowanie zaawansowanych funkcji edycyjnych w aplikacjach internetowych nie zawsze było łatwe dla programistów. Platforma internetowa umożliwia edytowanie zarówno w postaci zwykłego tekstu, jak i dokumentów HTML. Służą do tego elementy takie jak <input>
i <textarea>
. Można też stosować do nich atrybut contenteditable
. Podstawowe możliwości tych elementów często nie wystarczają jednak do osiągnięcia tego, co deweloperzy chcą osiągnąć w swoich aplikacjach.
Deweloperzy często wdrażają własny niestandardowy widok edytora, który zapewnia funkcje potrzebne użytkownikom. Widok edytora może być utworzony za pomocą złożonego modelu DOM lub nawet z elementem <canvas>
. Ponieważ jednak jedyny sposób, w jaki deweloper może otrzymywać dane wejściowe, wymaga skupionego elementu możliwego do edytowania, więc nadal musi umieścić ukryty element contenteditable
na stronie.
W efekcie użytkownik wydaje się, że edytuje bezpośrednio zawartość w edytorze niestandardowym, a deweloper otrzymuje dane wejściowe za pomocą modułów obsługi zdarzeń w ukrytym elemencie, a następnie powiela je w widocznym widoku edytora. Może to spowodować problemy, ponieważ deweloper będzie walczyć z domyślnym działaniem edycji w ukrytym elemencie contenteditable
.
Aby rozwiązać ten problem, zespół Microsoft Edge wprowadził standaryzację EditContext – nowego interfejsu API platformy internetowej, który umożliwia programistom bezpośrednie otrzymywanie tekstu wejściowego bez konieczności uzależniania się od domyślnych ustawień edycji w przeglądarce.
Autentyczny przykład
na przykład gdy użytkownicy współpracują w Word Online. Użytkownicy mogą wspólnie edytować i widzieć zmiany wprowadzane przez innych oraz pozycje kursorów. Jeśli jednak jeden współpracownik używa okna edytora metody wprowadzania (IME) do tworzenia tekstu w języku japońskim, jego edytor nie zostanie zaktualizowany i będzie pokazywać zmiany wprowadzone przez innych użytkowników, dopóki użytkownik IME nie skończy tworzyć kompozycji. Dzieje się tak, ponieważ wprowadzanie zmian w obszarze edytowanego elementu DOM przy aktywnej kompozycji IME może spowodować jej przedwczesne anulowanie. Aby zaktualizować widok, aplikacja musi poczekać do zamknięcia okna IME. Może to spowodować opóźnienia i utrudnić współpracę.
Aby zapewnić lepsze wrażenia programistom i użytkownikom, programiści potrzebują sposobu na oddzielenie wpisanego tekstu od widoku HTML DOM. Rozwiązaniem tego problemu jest interfejs EditContext API.
Podstawy EditContext
Dzięki funkcji EditContext można otrzymywać dane wejściowe dotyczące tekstu i kompozycji bezpośrednio przez platformę EditContext API, a nie przez obserwację zmian DOM. Zapewni to ściślejszą kontrolę nad sposobem obsługi danych wejściowych, a nawet umożliwi edytowanie elementu <canvas>
.
Powiązanie instancji EditContext z elementem umożliwia jej edytowanie:
// 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);
});
Obowiązki autora
Interfejs EditContext API ułatwia obsługę zaawansowanych metod wprowadzania, takich jak okna tworzenia IME, selektory emotikonów i inne platformy wejściowe systemu operacyjnego. Aby było to możliwe w edytowalnym elemencie, interfejs EditContext API wymaga pewnych informacji. Korzystając z interfejsu EditContext API, musisz nie tylko renderować tekst i zaznaczać tekst, ale też wykonywać inne czynności.
Zarządzanie stroną edytowalnego obszaru lub zmianą wyboru użytkownika
Wywołuj metody updateControlBounds()
i updateSelectionBounds()
, aby informować instancję EditContext o każdej zmianie rozmiaru obszaru do edycji lub zmiany wyboru użytkownika. Pomaga to platformie określić, gdzie mają być wyświetlane okna IME i inne elementy interfejsu edycji przeznaczone na daną platformę.
// 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);
Zarządzanie położeniem interfejsu edytora
Wykrywaj zdarzenie characterboundsupdate
i w odpowiedzi wywołaj updateCharacterBounds()
, aby pomóc platformie zdecydować, gdzie mają wyświetlać się okna IME i inny interfejs do edycji specyficzny dla danej platformy.
Stosuję formatowanie
Wykryj zdarzenie textformatupdate
i zastosuj w widoku edytora formatowanie określone przez zdarzenie. Te dekoracje tekstu są używane przez edytory IME podczas tworzenia określonych języków. Na przykład w japońskim edytorze tekstu zastosowano podkreślenie, aby pokazać, która część tekstu jest obecnie tworzona.
Obsługa zachowań związanych z edytowaniem tekstu sformatowanego
Słuchaj zdarzenia beforeinput
, aby obsługiwać działania związane z edytowaniem tekstu sformatowanego, które chcesz obsługiwać, takie jak klawisze skrótów do pogrubienia lub kursywy albo stosowanie korekty pisowni.
Zarządzanie zmianami w wyborach użytkowników
Gdy wybór użytkownika zmieni się w wyniku działania klawiatury lub myszy, musisz poinformować o zmianie wystąpienie EditContext. Jest to konieczne, ponieważ interfejs EditContext API ma zastosowanie w wielu różnych przypadkach, w tym w przypadku edytorów renderowanych za pomocą elementu <canvas>
, gdy przeglądarka nie może automatycznie wykryć zmian wyboru.
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);
});
Jeśli element używany z elementem EditContext jest też elementem <canvas>
, musisz też zaimplementować zachowania wyboru i nawigowania po kursorze, takie jak nawigowanie po tekście za pomocą klawiszy strzałek. Poza tym wbudowane sprawdzanie pisowni w przeglądarce działa tylko w elementach spoza <canvas>
.
EditContext a contenteditable
EditContext to doskonały wybór, jeśli wdrażasz w pełni funkcjonalny edytor i chcesz mieć pełną kontrolę nad sposobem wprowadzania tekstu lub dodajesz zaawansowane funkcje, takie jak wspólne edytowanie z wieloma użytkownikami. Biorąc jednak pod uwagę wszystkie poprzednie wymagania dotyczące korzystania z elementu EditContext i potrzebujesz jedynie prostej edycji tekstu, prawdopodobnie nadal będziesz używać elementów <input>
, <textarea>
lub atrybutu contenteditable
.
Plany na przyszłość
Zespół Microsoft Edge wdrożył EditContext w Chromium we współpracy z inżynierami Chrome i jest wysyłany wraz z wersją 121 (stycznia 2024 r.) zarówno przeglądarki Chrome, jak i Edge. Obecnie jest on dostępny tylko w przeglądarkach opartych na Chromium, ale pozycje Mozilli i WebKit można odczytać w interfejsie EditContext API.
Chcemy ułatwić programistom internetowym tworzenie zaawansowanych funkcji niestandardowych edycji w internecie. Jesteśmy przekonani, że interfejs EditContext API pozwala to rozwiązać, eliminując istniejące problemy i oferując bardziej bezpośredni sposób obsługi wprowadzania tekstu.
Więcej informacji o interfejsie API znajdziesz w dokumentacji MDN. Aby przesłać opinię na temat projektu interfejsu API, zgłoś problem w repozytorium na GitHubie interfejsu EditContext API. Aby zgłosić błędy związane z implementacją interfejsu API, zgłoś błąd na stronie crbug.com.