Input Events (original) (raw)
This specification defines additions to events for text and related input to allow for the monitoring and manipulation of default browser behavior in the context of text editor applications and other applications that deal with text input and text formatting. This specification builds on the UI events spec [[UI-EVENTS]].
Input Events Level 2 replaces the first version of Input Events [[INPUT-EVENTS]] and includes:
- Inputtypes for beforeinput events for the start and end of IME compositions that allow isolation of the IME composition process.
- More requirements for cancelability of beforeinput events, so that all beforeinput events apart from those being emited within an IME composition process are cancelable.
The test suite and implementation reports for the Input Events specification are still work in progress.
Introduction
This document describes editing related additions to 2 events -input and beforeinput which are described in the UI events spec [[UI-EVENTS]]. The goal of these events is to allow authors to understand and/or override default edit behavior both before and after editing occurs.
Definitions
express intention
A user can express an intention to execute a specific editing operation by means of keyboard, IME, speech, or similar method. Specific input actions are mapped to intentions following platform-specific conventions.
kill buffer
This definition is not normative.
A kill buffer is a in-memory store of richtext content that is separate from the clipboard which allows for the temporal storage of content that was deleted using specific deletion commands. The user can replace the current selection with the content held in the kill buffer by indicating an intention to yank the kill buffer.
Problems solved
This section is not normative.
Creating a webbased texteditor requires a considerable amount of JavaScript on top of the browser code, among other things because:
- Browsers do not handle all editing operations the same way.
- Browsers are often buggy in the way they handle certain editing operations.
- Individual sites may have custom preferences for how they want to handle certain editing operations.
- The development of high-level text editing features in browsers has not followed the principles laid out in the Extensible Web Manifesto in that development of these features has not always been in coordination with the needs of the web developer community.
This spec seeks to alleviate the problem by providing a simple way for web developers to both override browser handling of all user input related to text editing through the beforeinput event, and to monitor what browsers have changed in the DOM due to user input through the input event.
Use cases
This section is not normative.
- Creating a JavaScript text editor in which the -tag is used instead of the -tag to mark text that the user marks as bold, using any browser-builtin way to mark a text as bold, without having access to all existing browsers.
- Creating a JavaScript text editor which works with a data model in the background where JavaScript takes care of rendering changes to the edited text to the DOM.
- Creating a JavaScript editor which only allows a subset of richtext editing (for example: bold is allowed, but italic not).
- Creating a collaborative editor in which JavaScript is used to render changes to the DOM, based on user intentions with users using different browsers with different ways of expressing specific intentions.
- Creating a JavaScript editor with different user access options, where some users only can add or delete text and other users only can add or remove certain types of formatting.
Input Event Types
Input events are sent before (beforeinput event) and after (input event) a user attempts to edit the markup. This includes insertion and deletion of content, and formatting changes.
Input events are [=dispatched=] on elements that act as [=editing hosts=], including elements with the contenteditable attribute set, [^textarea^] elements, and [^input^] elements that permit text input.
Interface InputEvent
partial interface InputEvent {
readonly attribute DataTransfer? dataTransfer;
sequence<StaticRange> getTargetRanges();
};
partial dictionary InputEventInit {
DataTransfer? dataTransfer = null;
sequence<StaticRange> targetRanges = [];
};
The attributes {{InputEvent/inputType}}, dataTransfer andtargetRanges of {{InputEventInit}} initialize the corresponding attributes of the {{InputEvent}} object.
Overview
This section is not normative.
The following table provides a summary of when the data anddataTransfer attributes contain contents and when they are null as well as when the getTargetRanges() method returns an empty or non-empty Array, based on the inputType.
Editing host | inputType | data | dataTransfer | getTargetRanges() |
---|---|---|---|---|
Contenteditable | "insertText","insertCompositionText","formatSetBlockTextDirection","formatSetInlineTextDirection","formatBackColor","formatFontColor","formatFontName", "insertLink" | Yes | null | Non-empty Array |
Contenteditable | "insertFromPaste","insertFromPasteAsQuotation","insertFromDrop","insertReplacementText","insertFromYank" | null | Yes | Non-empty Array |
"insertText","insertCompositionText","insertFromPaste","insertFromPasteAsQuotation","insertFromDrop","insertReplacementText","insertFromYank","formatSetBlockTextDirection","formatSetInlineTextDirection","formatBackColor","formatFontColor","formatFontName", "insertLink" | Yes | null | Empty Array | |
All | "historyUndo", "historyRedo" | null | null | Empty Array |
Contenteditable | All Remaining | null | null | Non-empty Array |
All Remaining | null | null | Empty Array |
Attributes
The cancelability of the beforeinput event depends on the inputType.
The inputType to be picked depends on the user's expression of intention, whether or not the editing takes place during an IME composition and the state of the selection.
This specification defines the inputType values as the values in the inputType column of the following table.
inputType | User's expression of intention | Part of IME composition | beforeinput cancelable | State of selection |
---|---|---|---|---|
"insertText" | insert typed plain text | No | Yes | Any |
"insertReplacementText" | insert or replace existing content by means of a spell checker, auto-correct, writing suggestions or similar | No | Yes | Any |
"insertLineBreak" | insert a line break | No | Yes | Any |
"insertParagraph" | insert a paragraph break | No | Yes | Any |
"insertOrderedList" | insert a numbered list | No | Yes | Any |
"insertUnorderedList" | insert a bulleted list | No | Yes | Any |
"insertHorizontalRule" | insert a horizontal rule | No | Yes | Any |
"insertFromYank" | replace the current selection with content stored in akill buffer | No | Yes | Any |
"insertFromDrop" | insert content by means of drop | No | Yes | Any |
"insertFromPaste" | paste content from clipboard or paste image from client provided image library | No | Yes | Any |
"insertFromPasteAsQuotation" | paste content from the clipboard as a quotation | No | Yes | Any |
"insertTranspose" | transpose the last two [=grapheme cluster=]. that were entered | No | Yes | Any |
"insertCompositionText" | replace the current composition string | Yes | No | Any |
"insertLink" | insert a link | No | Yes | Any |
"deleteWordBackward" | delete a word directly before the caret position | No | Yes | Collapsed |
"deleteWordForward" | delete a word directly after the caret position | No | Yes | Collapsed |
"deleteSoftLineBackward" | delete from the caret to the nearest visual line break before the caret position | No | Yes | Collapsed |
"deleteSoftLineForward" | delete from the caret to the nearest visual line break after the caret position | No | Yes | Collapsed |
"deleteEntireSoftLine" | delete from the nearest visual line break before the caret position to the nearest visual line break after the caret position | No | Yes | Collapsed |
"deleteHardLineBackward" | delete from the caret to the nearest beginning of a block element or br element before the caret position | No | Yes | Collapsed |
"deleteHardLineForward" | delete from the caret to the nearest end of a block element or br element after the caret position | No | Yes | Collapsed |
"deleteByDrag" | remove content from the DOM by means of drag | No | Yes | Any |
"deleteByCut" | remove the current selection as part of a cut | No | Yes | Any |
"deleteContent" | delete the selection without specifying the direction of the deletion and this intention is not covered by another inputType | No | Yes | Non-collapsed |
"deleteContentBackward" | delete the content directly before the caret position and this intention is not covered by another inputType or delete the selection with the selection collapsing to its start after the deletion | No | Yes | Any |
"deleteContentForward" | delete the content directly after the caret position and this intention is not covered by another inputType or delete the selection with the selection collapsing to its end after the deletion | No | Yes | Any |
"historyUndo" | undo the last editing action | No | Yes | Any |
"historyRedo" | to redo the last undone editing action | No | Yes | Any |
"formatBold" | initiate bold text | No | Yes | Any |
"formatItalic" | initiate italic text | No | Yes | Any |
"formatUnderline" | initiate underline text | No | Yes | Any |
"formatStrikeThrough" | initiate stricken through text | No | Yes | Any |
"formatSuperscript" | initiate superscript text | No | Yes | Any |
"formatSubscript" | initiate subscript text | No | Yes | Any |
"formatJustifyFull" | make the current selection fully justified | No | Yes | Any |
"formatJustifyCenter" | center align the current selection | No | Yes | Any |
"formatJustifyRight" | right align the current selection | No | Yes | Any |
"formatJustifyLeft" | left align the current selection | No | Yes | Any |
"formatIndent" | indent the current selection | No | Yes | Any |
"formatOutdent" | outdent the current selection | No | Yes | Any |
"formatRemove" | remove all formatting from the current selection | No | Yes | Any |
"formatSetBlockTextDirection" | set the text block direction | No | Yes | Any |
"formatSetInlineTextDirection" | set the text inline direction | No | Yes | Any |
"formatBackColor" | change the background color | No | Yes | Any |
"formatFontColor" | change the font color | No | Yes | Any |
"formatFontName" | change the font-family | No | Yes | Any |
Other specifications may expand on this definition.
The existence of the above mentioned inputTypes
does not mean that any given implementation will support all of these. But if a given browser supports an editing operation which potentially leads to a change of the DOM, it MUST [=dispatch=] the corresponding beforeinput
and input
events.
If the selection is collapsed, "deleteContentBackward"
will be used both when the user asks for text deletion within a text node, and when the user shows the intention to deletion of more complex elements or merge paragraphs if the caret is at the start of a text node.
If the selection is collapsed, "deleteContentForward"
will be used both when the user asks for text deletion within a text node, and when the user shows the intention to deletion of more complex elements or merge paragraphs if the caret is at the end of a text node.
data
holds information plaintext data related to what is to be added to the document.
inputType | Editing host | data |
---|---|---|
"insertText" or"insertCompositionText" | Any | the plain text string to be inserted |
"insertFromPaste","insertFromPasteAsQuotation","insertFromDrop","insertTranspose","insertReplacementText" or"insertFromYank" | input ortextarea | the plain text string to be inserted |
"formatSetInlineTextDirection" or"formatSetBlockTextDirection" | Any | "ltr", "rtl", "auto" or "null" |
"formatBackColor" or"formatFontColor" | Any | a string containing a serialized CSS component value [[CSSOM]] of the proposed color |
"formatFontName" | Any | the proposed value of the font-family CSS property |
"insertLink" | Any | the url of the proposed link |
All remaining | Any | null |
dataTransfer holds information about richtext and plaintext data that is to be taken from or added to the document in a {{DataTransfer}} object if there is relevant data.
inputType | Editing host | dataTransfer |
---|---|---|
"insertFromPaste","insertFromPasteAsQuotation","insertFromDrop","insertTranspose","insertReplacementText" or"insertFromYank" | contenteditable | A prepopulated {{DataTransfer}} object so that: The {{DataTransfer}} object's drag data store is inread-only mode. [[HTML]] If the pasted content is a file, the {{DataTransfer}} object's drag data store item list contains one entry with the drag data item type string being the file's [=mime type=], whosekind is_File_, and whose data is a File object corresponding to the pasted file. [[HTML]] The {{DataTransfer}} object's drag data store item list contains one entry with the drag data item type string "text/html", whosekind is_Plain Unicode string_, and whose data is a HTML representation of the content that is in the clipboard, or in the kill buffer, to be dropped or otherwise the content that is to be added. [[HTML]] The {{DataTransfer}} object's drag data store item list contains one entry with the drag data item type string "text/plain", whosekind is_Plain Unicode string_, and whose data is a plain text representation of the content that is to be pasted, dropped or otherwise added. [[HTML]] If the content to be pasted is a link, the {{DataTransfer}} object's drag data store item list contains one entry with the drag data item type string "text/uri-list", whosekind is_Plain Unicode string_, and whose data is a plain text representation of the link that is dropped or otherwise added. [[HTML]] |
All remaining | Any | null |
getTargetRanges() returns an array ofStaticRanges representing the content that the event will modify if it is not canceled. The returned StaticRanges MUST cover only the code points that the browser would normally replace, even if they are only part of a [=grapheme cluster=].
This note is not normative.
Depending on the script and the platform, deleting backward or forward in a text node with a collapsed selection may affect one or multiple code points or an entire [=grapheme cluster=]. For example, deleting backward in a text node containing “café” may remove either the acute accent or the entire “é” character, depending on the script and the platform.
Methods
inputType | Editing host | Response of getTargetRanges() |
---|---|---|
"historyUndo" or "historyRedo" | Any | empty Array |
All remaining | contenteditable | an Array of StaticRanges [[DOM]] associated with event |
All remaining | input ortextarea | an empty Array |
returns , unless the inputType is "historyUndo"
or"historyRedo"
or the [=editing host=] is not a contenteditable element, in which case it returns an empty Array.
Event definitions
Type | beforeinput |
---|---|
Interface | InputEvent |
Sync / Async | Sync |
Bubbles | Yes |
Trusted Targets | Any Element that is an [=editing host=]. |
Default action [[UI-EVENTS]] | For contentEditable=typing editing hosts for inputTypes "insertCompositionText" and"deleteCompositionText": 'Update the DOM'. For contentEditable="true" [=editing hosts=] for all inputTypes: 'Update the DOM'. For EditContext editing hosts for EditContext-handled inputTypes: Handle input for EditContext given the [=editing host=] element. None otherwise. |
Context (trusted events) | InputEvent.data: the string containing the data that was added to the element, which MAY be null if it doesn't apply. InputEvent.dataTransfer: richtext data added or removed from element, which MAY be null if it doesn't apply. InputEvent.getTargetRanges(): returns an array of StaticRanges which will be affected by the change to the DOM if it is not canceled. |
A [=user agent=] MUST [=dispatch=] this event when the user has attempted to input in a contenteditable element. It does not necessarily mean the [=user agent=] will then update the DOM.
A [=user agent=] MUST NOT [=dispatch=] this event due to events that are not caused by attempted user input, such as system events.
Type | input |
---|---|
Interface | InputEvent |
Sync / Async | Sync |
Bubbles | Yes |
Trusted Targets | Any Element with contenteditable attribute enabled. |
Default action [[UI-EVENTS]] | None |
Context (trusted events) | InputEvent.data: the string containing the data that was added to the element, which MAY be null if it doesn't apply. InputEvent.dataTransfer: richtext data added or removed from element, which MAY be null if it doesn't apply. |
A [=user agent=] MUST [=dispatch=] this event immediately after the DOM has been updated due to user expressed intention to change the document contents which the browser has handled. If the browser makes no DOM change, either because the editing host is an EditContext editing host (which does not do automatic DOM changes) or because the [=user agent=] concludes that no DOM change is needed, the user agent MUST NOT dispatch this event.
Input Event Order During Composition
The start of a composition is marked by dispatching acompositionstart event.
During a composition session, whenever a text composition system updates its active text passage, a compositionupdate event is dispatched.
After each compositionupdate event, a pair of {{beforeinput}} and {{input}} events are dispatched. The {{beforeinput}} and {{input}} events:
- Are not cancellable
- Have an {{InputEvent/inputType}} set to
"insertCompositionText"
- Have a {{data}} attribute equal to that of the compositionupdate event
- Have a {{InputEvent/targetRange}} that surrounds the active text passage of the composition
The DOM contents of the active text passage are updated after the {{beforeinput}} event is dispatched and before the {{input}} event is dispatched.
The end of a composition session is marked by dispatching acompositionend event.
Event order when using "insertFromPaste"
When an "insertFromPaste"
{{beforeinput}} event is dispatched, it MUST be preceded by a paste [[CLIPBOARD-APIS]] event.
Privacy and security considerations
This section is not normative.
There are no known security or privacy impacts of this feature beyondfingerprinting [[fingerprinting-guidance]] techniques that already are available through existing events, such as the keydown
and keypress
[[UI-EVENTS]] events.
If this feature replaces existing events, it MAY lead to a decline in available fingerprinting [[fingerprinting-guidance]] techniques, as users' intentions are recorded, and not the particular type of hardware they used toexpress this intention.
Acknowledgements
Thanks to: Michael Aufreiter, Adrian Bateman, Oliver Buchtala, Robin Berjon, Enrica Casucci, Bo Cupp, Domenic Denicola, Emil Eklund, Olivier Forget, Aryeh Gregor, Marijn Haverbeke, Yoshifumi Inoue, Koji Ishii, Gary Kacmarcik, Ian Kilpatrick, Frederico Caldeira Knabben, Takayoshi Kochi, Piotrek Koszuliński, Travis Leithead, Grisha Lyukshin, Miles Maxfield, Chaals McCathie Nevile, Masayuki Nakano, Ryosuke Niwa, Julie Parent, Ben Peters, Florian Rivoal, Morgan Smith, Hallvord R. M. Steen, Johan Sörlin, Cristian Talau, Dave Tapuska, Ojan Vafai, Léonie Watson, Xiaoqian Wu, Chong Zhang, Joanmarie, and everyone in the Editing Taskforce for their input and feedback.