Start · Sprachen · JavaScript · Referenz · EditContext

EditContext

Schnittstelle

Stellt den Textbearbeitungskontext eines Elements dar, das über die EditContext API bearbeitbar gemacht wird – Texteingabe und Darstellung sind dabei getrennt.

seit JavaScript Chrome/Edge 121+ (experimentell, nicht in Firefox/ Kategorie: webapi

Signatur

interface EditContext extends EventTarget

Beschreibung

EditContext ist das zentrale Objekt der EditContext API. Damit lassen sich eigene Editoren bauen, zum Beispiel für Code, Rich Text oder auf einem <canvas> gezeichneten Text, ohne auf contenteditable angewiesen zu sein. Der Browser liefert die Texteingabe, auch über Eingabemethoden (IME) für Chinesisch, Japanisch oder Koreanisch, über Bildschirmtastaturen und über Diktierfunktionen. Das Rendern übernimmt vollständig die eigene Anwendung.

Verknüpft wird der Kontext über die Eigenschaft element.editContext. Sobald das Element den Fokus hat, feuert der Kontext das Ereignis textupdate, wenn Text eingefügt, gelöscht oder ersetzt wird. Die Anwendung aktualisiert daraufhin ihr eigenes Modell und zeichnet die Ansicht neu. Weitere Ereignisse sind textformatupdate (Unterstreichungen während einer IME-Komposition), characterboundsupdate (der Browser braucht Zeichenpositionen, um das IME-Fenster zu platzieren) sowie compositionstart und compositionend.

Wichtige Eigenschaften (nur lesbar): text, selectionStart, selectionEnd und characterBoundsRangeStart. Wichtige Methoden:

  • updateText(rangeStart, rangeEnd, text) ändert den Text des Kontexts, wenn er von außen geändert wird (z. B. Einfügen per Skript).
  • updateSelection(start, end) hält die Auswahl mit dem Editor-Modell synchron.
  • updateControlBounds(rect) und updateSelectionBounds(rect) teilen dem Betriebssystem die Position des Editors bzw. der Auswahl mit (als DOMRect in Viewport-Koordinaten).
  • updateCharacterBounds(rangeStart, rects) liefert die Rechtecke der einzelnen Zeichen, meist als Antwort auf characterboundsupdate.
  • attachedElements() gibt die verknüpften Elemente zurück, characterBounds() die zuletzt gemeldeten Zeichenrechtecke.

Die Schnittstelle lohnt sich vor allem für anspruchsvolle Editoren wie Web-IDEs oder Office-Anwendungen, die volle Kontrolle über Layout und Rendering brauchen und trotzdem sauber mit IME und Barrierefreiheit umgehen sollen.

Parameter

Name Typ Default Beschreibung
$options Object {} Optionales Objekt für den Konstruktor new EditContext(options).
$options.text string "" Anfangstext des Bearbeitungskontexts.
$options.selectionStart number 0 Startposition der Auswahl (Offset in UTF-16-Codeeinheiten).
$options.selectionEnd number 0 Endposition der Auswahl. Ist sie gleich selectionStart, ist nur der Cursor gesetzt und nichts markiert.

Rückgabewert

Typ
EditContext
Beschreibung
Eine neue EditContext-Instanz. Sie wird über element.editContext = ctx an ein Element gebunden.

Beispiele

EditContext erzeugen und an ein Canvas binden

const canvas = document.querySelector('#editor');
canvas.tabIndex = 0; // Canvas fokussierbar machen

const ctx2d = canvas.getContext('2d');
const editContext = new EditContext({ text: 'Hallo', selectionStart: 5, selectionEnd: 5 });
canvas.editContext = editContext;

const render = () => {
  ctx2d.clearRect(0, 0, canvas.width, canvas.height);
  ctx2d.font = '20px monospace';
  ctx2d.fillText(editContext.text, 10, 30);
};

editContext.addEventListener('textupdate', (event) => {
  console.log(`Ersetze ${event.updateRangeStart}–${event.updateRangeEnd} durch "${event.text}"`);
  render();
});

render();
console.log(editContext.attachedElements()[0] === canvas);
true // nach Eingabe von " Welt": // Ersetze 5–5 durch " " // Ersetze 6–6 durch "W" ...

Editor mit div: eigene Darstellung und Auswahl synchron halten

const view = document.querySelector('#code-view');
const editContext = new EditContext();
view.editContext = editContext;

const renderView = () => {
  view.textContent = editContext.text;
};

editContext.addEventListener('textupdate', () => {
  renderView();
});

// Text per Skript einfügen, z. B. über eine Toolbar-Schaltfläche
document.querySelector('#insert-snippet').addEventListener('click', () => {
  const pos = editContext.selectionEnd;
  const snippet = 'console.log();';
  editContext.updateText(pos, pos, snippet);
  editContext.updateSelection(pos + snippet.length, pos + snippet.length);
  renderView();
});

IME-Unterstützung: Positionen und Kompositionsformate melden

const canvas = document.querySelector('#editor');
const editContext = new EditContext();
canvas.editContext = editContext;
const charWidth = 12, lineHeight = 24;

// Position des Editors dem Betriebssystem mitteilen
const syncBounds = () => {
  const rect = canvas.getBoundingClientRect();
  editContext.updateControlBounds(rect);
  const x = rect.left + editContext.selectionStart * charWidth;
  editContext.updateSelectionBounds(new DOMRect(x, rect.top, 1, lineHeight));
};

editContext.addEventListener('characterboundsupdate', (event) => {
  const rect = canvas.getBoundingClientRect();
  const bounds = [];
  for (let i = event.rangeStart; i < event.rangeEnd; i++) {
    bounds.push(new DOMRect(rect.left + i * charWidth, rect.top, charWidth, lineHeight));
  }
  editContext.updateCharacterBounds(event.rangeStart, bounds);
});

editContext.addEventListener('textformatupdate', (event) => {
  for (const format of event.getTextFormats()) {
    console.log(format.rangeStart, format.rangeEnd, format.underlineStyle, format.underlineThickness);
  }
});

editContext.addEventListener('compositionstart', () => console.log('Komposition beginnt'));
editContext.addEventListener('compositionend', () => console.log('Komposition beendet'));

canvas.addEventListener('focus', syncBounds);
window.addEventListener('resize', syncBounds);
Komposition beginnt 0 2 "solid" "thin" Komposition beendet

Feature-Erkennung mit Rückfall auf contenteditable

const el = document.querySelector('#editor-host');

if ('EditContext' in window) {
  el.editContext = new EditContext();
  console.log('EditContext aktiv');
} else {
  el.contentEditable = 'true';
  console.log('Rückfall auf contenteditable');
}
EditContext aktiv // in Chrome/Edge 121+ Rückfall auf contenteditable // in Firefox/Safari