EditContext API 编辑上下文接口

W3C 工作草案

关于本文档的更多细节
本版本:
https://www.w3.org/TR/2025/WD-edit-context-20251112/
最新发布版本:
https://www.w3.org/TR/edit-context/
最新编辑者草稿:
https://w3c.github.io/edit-context/
历史:
https://www.w3.org/standards/history/edit-context/
提交历史
编辑:
(微软)
前编辑:
(微软) - 至
(微软) - 至
(微软) - 至
反馈:
GitHub w3c/edit-context (拉取请求, 新建议, 开放的建议)
public-editing-tf@w3.org 主题行 [edit-context] … 信息主题 … (存档)
参与
我们在 GitHub。
提交 bug。
提交历史。
邮件列表。

摘要

EditContext 是一个 API,允许作者更直接参与文本输入流程。

本文档状态

本节描述了该文档在发布时的状态。当前 W3C 的出版物列表以及本技术报告的最新修订可在 W3C 标准和草案索引中查阅。

本文档由 Web 编辑工作组 作为工作草案发布,采用 推荐路线

作为工作草案发布不代表 W3C 及其成员的认可。

本文档为草稿,有可能随时被更新、替换或废弃。引用此文档时只适合作为正在进行中的工作。

本文档由在 W3C 专利政策 下运作的组织编写。 W3C 维持着 与工作成果相关的专利公开名单 该页面还包含披露专利的说明。知晓专利并认为其包含 必要权利要求 的个人必须根据 W3C 专利政策第6条 披露相关信息。

本文档受 2025年8月18日 W3C 流程文档 管理。

1. 引言

1.1 背景和动机

本节为非规范性内容。

现代操作系统提供了多种生成文本的机制:语音转文本、虚拟键盘、手写识别等。应用想要从这些不同来源接收文本输入,首先必须向操作系统提供其当前可编辑文本的视图。可编辑文本的视图提供了一种通用语言,使得具有各种不同文档模型的应用和具有各种不同输入方式的文本来源都能理解。应用和输入来源双方都通过将其对公共视图状态的期望更改表达为事件,并由对方处理,从而完成文本输入过程。

在本文档中,文本的生产者称为 Text Input Method(文本输入法)。希望消费文本的应用所提供的视图称为 Text Edit Context(文本编辑上下文)。操作系统为 Text Edit ContextText Input Methods 编辑所提供的服务称为 Text Input Service(文本输入服务)。

1 多个 Text Input Methods 使用同一个 Text Input Service,通过各自的 Text Edit Contexts 与多个应用进行通信。

下面是一个更详细的典型文本输入流程:

  1. 用户将焦点置于应用中的某个可编辑区域。
  2. 应用生成一个 Text Edit Context,按照 Text Input Service 规定的标准描述其可编辑区域,并将该 Text Edit Context 提供给 Text Input Service
  3. Text Input Service 触发某个 Text Input Method,为用户提供捕获文本输入的用户界面,并将应用生成的 Text Input Method 所需的 Text Edit Context 一并提供给它。
  4. Text Input MethodText Edit Context 读取选区位置及其附近文本,以便定制其用户体验。
  5. Text Input Method 还可以读取选区和可编辑区域在屏幕上的坐标,从而将其用户界面正确地定位在被编辑文本附近。
  6. 用户通过 Text Input Method 的用户界面,以某种该 Text Input Method 特定的方式输入文本。
  7. Text Input Method 根据用户输入,描述其希望对 Text Edit Context 中的文本和选区进行的修改。
  8. 应用处理描述对其 Text Edit Context 所需修改的事件,并将结果渲染给用户。
2 展示典型文本输入流程的时序图。

现有用户代理会处理上述文本输入流程中的细节,因此作者的职责仅限于声明文档中哪些元素代表可编辑区域。作者通过使用 input 元素、textarea 元素、contenteditable 元素,或将 designMode 属性设置为 "on" 来标记整个文档为可编辑,从而表达哪些区域是可编辑的。

当文档中的某个可编辑区域被 focused 时,用户代理会自动根据该可编辑区域的内容及其中的选区位置生成 Text Edit Context。当某个 Text Input Method 生成文本时,用户代理会将针对其 Text Edit Context 的事件转换为一系列 DOM 和样式修改——目前只有一部分通过现有事件暴露给作者可以处理。

希望提供复杂编辑体验的作者可能会受到现有方式的限制。例如,如果文本和选区被渲染到 canvas 中,用户代理就无法生成驱动文本输入过程的 Text Edit Context。作者通常会借助离屏可编辑元素来弥补,但这种方式会对可访问性产生负面影响、降低输入体验,并且需要复杂的代码来同步离屏可编辑元素中的文本位置与 canvas 中相应文本的位置。

通过引入 EditContext API,作者可以更直接地参与文本输入协议,从而避免上述问题。

1.2 EditContext 模型

Text Input ServiceText Edit Context 是在许多操作系统上抽象出文本输入共性的一组概念。 EditContextText Edit Context 的 JavaScript 映射。 当 Text Edit ContextText Input Service 修改时,这些更改会以事件的形式异步反映给作者,这些事件会派发到 active EditContext 上。 当作者对 active EditContext 进行更改时,这些更改会在下一次生命周期更新时反映到 Text Edit Context 中。

1.2.1 EditContext 状态

Text Edit ContextEditContext 都具有一个 text state,保存前述更新中交换的信息。text state 由以下内容组成:

  • text:一个 DOMString,表示可编辑内容。初始值为空字符串。
  • selection start:指向 text 中选区起始位置的偏移量。初始值为 0。
  • selection end:指向 text 中选区结束位置的偏移量。初始值为 0。对于“反向”选区(顺序与文档顺序相反),selection end 可以小于 selection start
  • is composing:指示当前是否存在激活的合成。初始值为 false。
  • composition start:指向 text 中正在进行合成的文本起始位置的偏移量。初始值为 0。
  • composition end:指向 text 中正在进行合成的文本结束位置的偏移量。初始值为 0。composition end 必须始终大于或等于 composition start
  • text formats:一个由 text format 组成的数组。该数组初始为空。
  • control bounds:一个 DOMRect,描述视口中显示 text 的区域。它使用 client coordinate system,其初始 x、y、width 和 height 均为 0。
  • selection bounds:一个 DOMRect,描述选区的位置。它使用 client coordinate system,其初始 x、y、width 和 height 均为 0。
  • codepoint rects start index:指向 text 中的一个偏移量,表示在 codepoint rects 数组第一个成员所报告的位置之前的那个码点位置。
  • codepoint rects:一个由 DOMRect 组成的数组,用于定义每个码点的边界框。该数组初始为空。

text format 是一个结构体,用于指示应应用于某些 text 范围的装饰属性。该结构体包含:

  • range start:指向 text 中的一个偏移量,表示要被装饰的第一个码点之前的位置。
  • range end :指向 text 中的一个偏移量,表示要被装饰的最后一个码点之后的位置。
  • underline style:一个 UnderlineStyle,表示被装饰 text 范围的首选下划线样式。
  • underline thickness:一个 UnderlineThickness,表示被装饰 text 范围的首选下划线粗细。
Note

Codepoint rects 为用户代理提供了一种手段,可以针对一定范围的 text 进行位置查询。Text Input Service 会结合 control boundsselection bounds 使用这些信息, 以支持 Text Input Method 正确显示其用户界面。例如,这些信息可用于将 IME 窗口定位到正在合成的文本附近。 不同平台为了响应来自 Text Input Service 的查询,可能需要缓存不同的位置信息。 用户代理会通过触发 CharacterBoundsUpdateEvent 来指示需要哪些位置。

Control boundsselection boundscodepoint rects 使用 client coordinate system 表示。该坐标系被定义为一个二维笛卡尔坐标系 (x, y),其原点位于 layout viewport 的左上角, x 轴指向 layout viewport 的右上方, y 轴指向 layout viewport 的左下方。 client 坐标系的单位为 CSS 像素

Note

由于 EditContext 的各类 bounds 是使用 client coordinates 定义的, 页面上某段内容对应的坐标会随着用户滚动文档而变化,即便该内容在文档中的位置并未改变。 一个需要作者考虑此问题的场景是:用户在存在激活合成的情况下滚动页面。 如果作者没有更新 EditContext 的 bounds 信息(例如在滚动事件监听函数中更新), IME 窗口在整个合成过程中就可能不再与正在合成的文本对齐。

然而,某些平台在激活合成期间不会调整 IME 窗口的位置, 因此在合成中途更新 bounds 信息并不能保证 IME 窗口会立即重新定位, 而可能要等到关闭并重新打开之后才会重新定位。

1.2.2 关联与激活

一个 EditContext 具有一个 associated element,即一个 HTMLElement。 当把某个 EditContext 赋值给元素的 editContext 属性时,该元素就成为该 associated element 。 一个 HTMLElement 至多可以与一个 EditContext associated

Note

一个 EditContext 会保持其 associated element 存活, 因此开发者需要注意,将某个 EditContext 赋值给元素的 editContext 属性, 会阻止该元素被垃圾回收,直到该属性被清除,或该 EditContext 本身被垃圾回收。

如果某个 EditContextassociated element父节点 既不是 editable,也不是其 designMode 属性为 "on" 的 Document, 则该 associated element 会成为一个 EditContext editing hostEditContext editing host 是一种 editing host, 其行为在 1.2.3 Differences for an EditContext editing host 中有详细描述。

Note

这其中有几点影响。首先,如果某个元素已经因为 contenteditable 而成为一个 editing host, 然后又成为某个 EditContextassociated element, 那么该元素会成为 EditContext editing host。 换言之,如果在一个元素上同时设置了 EditContextcontenteditable, 则以 EditContext 的行为为准。

其次,如果某个元素是 editable, 但本身不是 editing host(即它是某个 editing host 子树中的子节点), 那么将其设为某个 EditContextassociated element 对该元素不会产生任何影响。这与 contenteditable 的行为类似:为一个 editable 且不是 editing host 的元素设置 contenteditable 为 "true" 并不会产生效果。综合来看,这些规则意味着,一个可编辑的节点树将要么遵循 EditContext 行为,要么遵循非 EditContext 行为,两者不能混用。

一个 Document 具有一个 active EditContext,其值可以为 null。

Issue 1

一旦行为更改在 [input-events] 中落地,下面这一段即可移除。

当某个 EditContext editing hostText Input Service 接收到文本输入时, 作为由该输入触发的 beforeinput 事件的 默认动作, 用户代理必须对该 EditContext editing host 运行 Handle Input for EditContext

1.2.3 EditContext 编辑宿主的区别

在许多方面,一个 EditContext editing host 的行为与其他类型的 editing host(例如设置了 contenteditable 的元素)相同。显著的相似点包括:

同时,一个 EditContext editing host 也有一些与其他 editing hosts 不同的地方:

1.2.4 EditContext 事件

用户代理会在 EditContext 上触发多种事件, 以告知作者何时必须在 DOM 中更新状态来响应来自 Text Input Service 的更改, 或响应来自 Text Input Service 的查询。 由于 Text Input Service 的时序是平台相关的, 作者应避免依赖这些事件触发时机的具体细节。

1.2.5 事件循环变更

在 HTML 事件循环处理模型中,会在 Update the rendering 步骤中新增一个子步骤,紧跟在第 15 步(为其 focused area 变为不可聚焦的 Document 运行 focusing steps)之后。 该步骤为:对每个 fully activeDocument doc, 使用 docrelevant global object, 在 DOM manipulation task sourcequeue a global task, 来运行给定 docUpdate the Text Edit Context 步骤。

1.2.6 示例

本节为非规范性内容。

借助 EditContext,作者可以通过将一个 associatingEditContext 对象附加到某个元素上来标记文档的某个区域为可编辑,如下例所示:

在下面的示例中,作者使用 canvas 来绘制一个可编辑区域,使用户可以输入使用等宽字体渲染的单行文本。该可编辑区域的文本由作者以 String 的形式维护;选区在可编辑区域中的文本偏移由作者以一对 Number(selectionStart 和 selectionEnd)维护,这两个 Number 表示从文本起始处到选区起点和终点分别包含多少个 UTF-16 码点。为了便于将当前选区和可编辑区域的边界矩形(使用 CSS 像素)告知文本输入服务,作者还会计算选区及可编辑区域在文档中的边界矩形。这些矩形的偏移相对于 canvas 元素的原点给出,因为作者正是将 EditContext associated 到该 canvas 元素上的。由于作者对文本和选区位置的表示方式与 EditContext API 期望的形式一致,作者只需在这些值变化时,将它们赋值给与 canvas associated 的 EditContext 即可。

在前一个示例的基础上,作者在响应用户输入时,应同时处理可编辑元素(本例中为 canvas)和 EditContext 上的事件。

针对 DOM 的输入事件继续描述用户的意图。

下面的示例展示了如何处理 TextUpdateEventTextFormatUpdateEventCharacterBoundsUpdateEvent, 以更新模型并将结果渲染到 canvas。

1.3 与其他编辑原语的交互

本节为非规范性内容。

作者并不一定要将 EditContext 与 canvas 元素配合使用。在下面的示例中,作者使用 div 来建立文档中的可编辑区域,并通过各种样式化元素、图片和文本将内容渲染到该可编辑区域中。这使得作者可以利用用户代理提供的其他内置编辑原语,如选区与拼写检查。

2. 一致性

除标记为非规范性的章节外,本规范中的所有编写指南、图表、示例和注释均为非规范性内容。本规范中的其他所有内容均为规范性内容。

本规范定义的符合性标准适用于单一产品:实现本规范所包含接口的用户代理。

以算法或具体步骤表述的符合性要求可以以任何方式实现,只要最终结果等效即可。(尤其是,本规范中定义的算法旨在易于理解,而非追求性能。)

3. EditContext API

3.1 对 HTMLElement 接口的扩展

WebIDLpartial interface HTMLElement {
     attribute EditContext? editContext;
};

HTMLElement 具有一个内部槽 [[EditContext]],它是对一个 EditContext 的引用,初始值为 null。

editContext
editContext getter 的步骤是返回 this 的内部 [[EditContext]] 槽的值。
editContext setter 必须遵循以下步骤:
输入
editContext
输出
  1. 如果 thislocal name 既不是 valid shadow host name,也不是 "canvas",则 抛出 一个 "NotSupportedError" DOMException
  2. 如果 editContext 不为 null,则:
    1. 如果 editContextassociated element 等于 this, 则终止这些步骤。
    2. 如果 editContextassociated element 不为 null, 则 抛出 一个 "NotSupportedError" DOMException
  3. oldEditContextthis 的内部 [[EditContext]] 槽的值。
  4. 如果 oldEditContext 不为 null 且 oldEditContextthisnode documentactive EditContext,则:
    1. oldEditContext 运行 Deactivate an EditContext 的步骤。
    2. 如果 oldEditContextassociated element 不等于 this, 则终止这些步骤。
    3. 如果 editContext 不为 null,且 editContextassociated element 不为 null, 并且 editContextassociated element 不等于 this, 则 抛出 一个 "NotSupportedError" DOMException
  5. 如果 oldEditContext 不为 null,将 oldEditContextassociated element 设为 null。
  6. 如果 editContext 不为 null,则将 editContextassociated element 设为 this
  7. this 的内部 [[EditContext]] 槽设置为 editContext

3.1.1 处理 EditContext 的输入

输入
element,接收输入的 HTMLElement
输出
  1. editContextelementnode documentactive EditContext
  2. 如果 editContext 为 null,则返回。
  3. 针对给定的 editContext,并使用 Text Edit Contexttext state 中的 texttext formatsselection startselection endis composingcomposition start、 以及 composition end, 运行 Update the EditContext 的步骤。

    Note

    由于 Text Edit Context 是对不同操作系统上文本输入共性方面的抽象, 因此本规范明确不会给出如何确定 Text Edit Context 中这些取值的方式。它们会因不同的操作系统和输入设备而异。

3.1.2 EditContext 处理的 inputType

如果某个 inputType 属于以下之一,则它是一个 EditContext-handled inputType
  • insertText
  • insertTranspose
  • deleteWordBackward
  • deleteWordForward
  • deleteContent
  • deleteContentBackward
  • deleteContentForward
Note
EditContext 处理的 inputType 是那些仅对原始文本进行操作的类型。其他依赖格式、剪贴板/拖放、撤销或浏览器 UI(如拼写检查)的 inputType 无法由 EditContext 处理,因为 EditContext 的状态不包含这些概念。如果作者希望其应用处理这些 inputType, 则需要在 beforeinput 事件处理程序中手动处理它们。

3.1.3 更新 EditContext

输入
editContext,一个 EditContext
text,一个字符串
textFormats,来自 Text Input Servicetext format 数组
selectionStart,选区起点的新位置
selectionEnd,选区终点的新位置
isComposing,一个布尔值,指示在更新结束时合成是否应处于激活状态
replacementRangeStart,当前合成的起始位置(若无合成则为 0)
replacementRangeEnd,当前合成的结束位置(若无合成则为 0)
输出
  1. 如果 isComposing 为 true、text 非空,并且 editContextis composing 为 false,则:
    1. 触发事件,其名称为 compositionstart, 目标为 editContext,并使用 CompositionEvent
    2. editContextis composing 设为 true。
  2. 如果 text 为空:
    1. 如果 editContextis composing 为 false,则返回。
    2. 如果 editContextis composing 为 true 且 isComposing 为 false,则:
      1. editContextis composing 设为 false。
      2. 触发事件, 其名称为 compositionend, 目标为 editContext,并使用 CompositionEvent
      3. 返回。
  3. 如果 editContextis composing 为 true,则:
    1. insertionStartreplacementRangeStart
    2. insertionEndreplacementRangeEnd
  4. 否则:
    1. insertionStartselectionStart
    2. insertionEndselectionEnd
  5. editContexttextinsertionStartinsertionEnd 范围内的子串替换为 text
  6. editContextselection start 设为 selectionStart
  7. editContextselection end 设为 selectionEnd
  8. editContextcomposition start 设为 insertionStart
  9. editContextcomposition end 设为 editContextcomposition start 加上 text 的长度。
  10. 针对给定的 editContexttext,执行 Dispatch text update event
  11. 如果 editContextis composing 为 true,则:
    1. 针对给定的 editContexttextFormats,执行 Dispatch text format update event
    2. 针对给定的 editContext,执行 Dispatch character bounds update event
    3. 如果 isComposing 为 false,则:
      1. editContextis composing 设为 false。
      2. 触发事件, 其名称为 compositionend, 目标为 editContext,并使用 CompositionEvent

3.1.4 更新文本编辑上下文

输入
document,一个 Document
输出
  1. oldActiveEditContextdocumentactive EditContext
  2. newActiveEditContext 为对 document 运行 Determine the active EditContext 步骤的结果。
  3. 如果 oldActiveEditContext 不为 null,则对 oldActiveEditContext 运行 Deactivate an EditContext 的步骤。
  4. 如果 newActiveEditContext 不为 null,则:
    1. 更新 Text Edit Contexttext state,使其与 editContexttext state 中的取值一致。
  5. documentactive EditContext 设为 newActiveEditContext
Note

注意:更新 Text Edit Contexttext state 的步骤取决于对特定平台 Text Input Service 所创建抽象的性质。 这些细节不属于本规范的一部分。

3.1.5 分发文本更新事件

输入
editContext,一个 EditContext
text,一个字符串
输出
  1. 触发事件,其名称为 "textupdate",目标为 editContext,并使用 TextUpdateEvent,其中 text 初始化为 textselectionStart 初始化为 editContextselection start,以及 selectionEnd 初始化为 editContextselection end

3.1.6 分发文本格式更新事件

输入
editContext,一个 EditContext
textFormats,来自 Text Input Servicetext format 数组
输出
  1. formats 为一个 TextFormat 数组,初始为空。
  2. 对于 textFormats 中的每个 text format format
    1. textFormat 为一个新的 TextFormat,其包含 rangeStartrangeEndunderlineStyleunderlineThickness
    2. textFormatrangeStart 设为 formatrange start
    3. textFormatrangeEnd 设为 formatrange end
    4. textFormatunderlineStyle 设为 formatunderline style
    5. textFormatunderlineThickness 设为 formatunderline thickness
    6. textFormat 追加到 formats
  3. 触发事件,其名称为 "textformatupdate",目标为 editContext,并使用 TextFormatUpdateEvent,且将该 TextFormatUpdateEventtext format list 初始化为 formats

3.1.7 分发字符边界更新事件

输入
editContext,一个 EditContext
输出
  1. 触发事件,其名称为 "characterboundsupdate",目标为 editContext,并使用 CharacterBoundsUpdateEvent,其中 rangeStart 初始化为 editContextcomposition start,并将 rangeEnd 初始化为 editContextcomposition end

3.1.8 停用 EditContext

输入
editContext,一个 EditContext
输出
  1. editContextis composing 设为 false。
  2. 触发事件,其名称为 compositionend, 目标为 editContext,并使用 CompositionEvent

3.1.9 确定活动的 EditContext

输入
document,一个 Document
输出
一个 EditContext,或 null。
  1. traversabledocumentnode navigabletop-level traversable
  2. 如果 traversable 为 null,则返回 null。
  3. focused 为在给定 traversable 的情况下, top-level traversable 当前聚焦区域DOM anchor
  4. 如果 focused 为 null,或者 focusedshadow-including root 不等于 document,则返回 null。

    Note

    通过 top-level traversable 获取 focusable 的目的,是希望每个 top-level traversable 在任一时刻只有一个 active EditContext。 因此,如果系统焦点在另一个文档中,则该文档不能拥有 active EditContext

  5. editContext 为 null。
  6. focused 不为 null 且 focusededitable 时:
    1. editContext 设为 focused 的内部 [[EditContext]] 槽的值。
    2. parentfocusedparent
    3. 如果 parent 为 null 且 focusedroot 是一个 shadow root,则令 parentfocusedroothost
    4. focused 设为 parent
  7. 返回 editContext
Note

如果某个 EditContextassociated element 的父节点是 editable,那么该 EditContext 不能成为 active EditContext。 无论该父节点是因为另一个 EditContext 还是因为 contenteditable 而变为 editable,都是如此。

3.2 EditContext 接口

WebIDLdictionary EditContextInit {
    DOMString text;
    unsigned long selectionStart;
    unsigned long selectionEnd;
};

[Exposed=Window]
interface EditContext : EventTarget {
    constructor(optional EditContextInit options = {});

    undefined updateText(unsigned long rangeStart, unsigned long rangeEnd,
        DOMString text);
    undefined updateSelection(unsigned long start, unsigned long end);
    undefined updateControlBounds(DOMRect controlBounds);
    undefined updateSelectionBounds(DOMRect selectionBounds);
    undefined updateCharacterBounds(unsigned long rangeStart, sequence<DOMRect> characterBounds);

    sequence<HTMLElement> attachedElements();

    readonly attribute DOMString text;
    readonly attribute unsigned long selectionStart;
    readonly attribute unsigned long selectionEnd;
    readonly attribute unsigned long characterBoundsRangeStart;
    sequence<DOMRect> characterBounds();

    attribute EventHandler ontextupdate;
    attribute EventHandler ontextformatupdate;
    attribute EventHandler oncharacterboundsupdate;
    attribute EventHandler oncompositionstart;
    attribute EventHandler oncompositionend;
};
text
text getter 的步骤是返回 thistext
selectionStart
selectionStart getter 的步骤是返回 thisselection start
selectionEnd
selectionEnd getter 的步骤是返回 thisselection end
characterBounds
characterBounds getter 的步骤是返回 thiscodepoint rects
characterBoundsRangeStart
characterBoundsRangeStart getter 的步骤是返回 thiscodepoint rects start index
updateText() method

该方法必须遵循以下步骤:

输入
rangeStart,一个 unsigned long
rangeEnd,一个 unsigned long
newText,一个 DOMString
输出
  1. textrangeStartrangeEnd 范围内的子串替换为 newText
    Note
    允许 rangeStart > rangeEnd。 位于这两个索引之间的子串应当以与 rangeStart <= rangeEnd 时相同的方式被替换。
updateSelection() method

该方法必须遵循以下步骤:

输入
start,一个 unsigned long
end,一个 unsigned long
输出
  1. selection start 设为 start
  2. selection end 设为 end
updateSelectionBounds() method

该方法必须遵循以下步骤:

输入
selectionBounds,一个 DOMRect
输出
  1. selection bounds 设为 selectionBounds
updateControlBounds() method

该方法必须遵循以下步骤:

输入
controlBounds,一个 DOMRect
输出
  1. control bounds 设为 controlBounds
updateCharacterBounds() method

该方法必须遵循以下步骤:

输入
rangeStart,一个 unsigned long
characterBounds,一个由 DOMRect 组成的数组
输出
  1. codepoint rects start index 设为 rangeStart
  2. codepoint rects 设为 characterBounds
attachedElements() method

该方法返回一个只有一项的列表,该项为该 EditContextassociated element;如果该 EditContextassociated element 为 null,则返回空列表。

Note

该方法返回列表而非单个元素,是为了前向兼容:如果将来 EditContext 被赋予拥有多个 associated elements 的能力。

ontextupdate

TextUpdateEvent 的事件处理程序。

oncharacterboundsupdate

CharacterBoundsUpdateEvent 的事件处理程序。

ontextformatupdate

TextFormatUpdateEvent 的事件处理程序。

oncompositionstart

compositionstart 事件的事件处理程序。

oncompositionend

compositionend 事件的事件处理程序。

4. EditContext 事件

4.1 TextUpdateEvent

WebIDLdictionary TextUpdateEventInit : EventInit {
    unsigned long updateRangeStart;
    unsigned long updateRangeEnd;
    DOMString text;
    unsigned long selectionStart;
    unsigned long selectionEnd;
    unsigned long compositionStart;
    unsigned long compositionEnd;
};

[Exposed=Window]
interface TextUpdateEvent : Event {
    constructor(DOMString type, optional TextUpdateEventInit options = {});
    readonly attribute unsigned long updateRangeStart;
    readonly attribute unsigned long updateRangeEnd;
    readonly attribute DOMString text;
    readonly attribute unsigned long selectionStart;
    readonly attribute unsigned long selectionEnd;
};
updateRangeStart, of type unsigned long, readonly
要被替换的范围的起始位置。
updateRangeEnd, of type unsigned long, readonly
要被替换的范围的结束位置。
text, of type DOMString, readonly
用于替换该范围内旧字符串的新字符串。
selectionStart, of type unsigned long, readonly
文本替换后选区的起始位置。
selectionEnd, of type unsigned long, readonly
文本替换后选区的结束位置。

4.2 TextFormatUpdateEvent

WebIDLenum UnderlineStyle { "none", "solid", "dotted", "dashed", "wavy" };
enum UnderlineThickness { "none", "thin", "thick" };

dictionary TextFormatInit {
    unsigned long rangeStart;
    unsigned long rangeEnd;
    UnderlineStyle underlineStyle;
    UnderlineThickness underlineThickness;
};

[Exposed=Window]
interface TextFormat {
    constructor(optional TextFormatInit options = {});
    readonly attribute unsigned long rangeStart;
    readonly attribute unsigned long rangeEnd;
    readonly attribute UnderlineStyle underlineStyle;
    readonly attribute UnderlineThickness underlineThickness;
};

dictionary TextFormatUpdateEventInit : EventInit {
    sequence<TextFormat> textFormats;
};

[Exposed=Window]
interface TextFormatUpdateEvent : Event {
    constructor(DOMString type, optional TextFormatUpdateEventInit options = {});
    sequence<TextFormat> getTextFormats();
};
rangeStart, of type unsigned long, readonly
表示应当被装饰的第一个码点之前位置的偏移量。
rangeEnd, of type unsigned long, readonly
表示应当被装饰的最后一个码点之后位置的偏移量。
underlineStyle, of type UnderlineStyle, readonly
被装饰文本范围的首选下划线样式。
underlineThickness, of type UnderlineThickness, readonly
被装饰文本范围的首选下划线粗细。
getTextFormats method
返回 thistext format list

TextFormatUpdateEvent 具有一个关联的 text format list,它是一个包含零个或多个 text format 的列表。

4.3 CharacterBoundsUpdateEvent

WebIDLdictionary CharacterBoundsUpdateEventInit : EventInit {
    unsigned long rangeStart;
    unsigned long rangeEnd;
};

[Exposed=Window]
interface CharacterBoundsUpdateEvent : Event {
    constructor(DOMString type, optional CharacterBoundsUpdateEventInit options = {});
    readonly attribute unsigned long rangeStart;
    readonly attribute unsigned long rangeEnd;
};
rangeStart, of type unsigned long, readonly
Text Input Service 所需字符边界信息范围的起始位置
rangeEnd, of type unsigned long, readonly
Text Input Service 所需字符边界信息范围的结束位置

A. IDL 索引

WebIDLpartial interface HTMLElement {
     attribute EditContext? editContext;
};

dictionary EditContextInit {
    DOMString text;
    unsigned long selectionStart;
    unsigned long selectionEnd;
};

[Exposed=Window]
interface EditContext : EventTarget {
    constructor(optional EditContextInit options = {});

    undefined updateText(unsigned long rangeStart, unsigned long rangeEnd,
        DOMString text);
    undefined updateSelection(unsigned long start, unsigned long end);
    undefined updateControlBounds(DOMRect controlBounds);
    undefined updateSelectionBounds(DOMRect selectionBounds);
    undefined updateCharacterBounds(unsigned long rangeStart, sequence<DOMRect> characterBounds);

    sequence<HTMLElement> attachedElements();

    readonly attribute DOMString text;
    readonly attribute unsigned long selectionStart;
    readonly attribute unsigned long selectionEnd;
    readonly attribute unsigned long characterBoundsRangeStart;
    sequence<DOMRect> characterBounds();

    attribute EventHandler ontextupdate;
    attribute EventHandler ontextformatupdate;
    attribute EventHandler oncharacterboundsupdate;
    attribute EventHandler oncompositionstart;
    attribute EventHandler oncompositionend;
};

dictionary TextUpdateEventInit : EventInit {
    unsigned long updateRangeStart;
    unsigned long updateRangeEnd;
    DOMString text;
    unsigned long selectionStart;
    unsigned long selectionEnd;
    unsigned long compositionStart;
    unsigned long compositionEnd;
};

[Exposed=Window]
interface TextUpdateEvent : Event {
    constructor(DOMString type, optional TextUpdateEventInit options = {});
    readonly attribute unsigned long updateRangeStart;
    readonly attribute unsigned long updateRangeEnd;
    readonly attribute DOMString text;
    readonly attribute unsigned long selectionStart;
    readonly attribute unsigned long selectionEnd;
};

enum UnderlineStyle { "none", "solid", "dotted", "dashed", "wavy" };
enum UnderlineThickness { "none", "thin", "thick" };

dictionary TextFormatInit {
    unsigned long rangeStart;
    unsigned long rangeEnd;
    UnderlineStyle underlineStyle;
    UnderlineThickness underlineThickness;
};

[Exposed=Window]
interface TextFormat {
    constructor(optional TextFormatInit options = {});
    readonly attribute unsigned long rangeStart;
    readonly attribute unsigned long rangeEnd;
    readonly attribute UnderlineStyle underlineStyle;
    readonly attribute UnderlineThickness underlineThickness;
};

dictionary TextFormatUpdateEventInit : EventInit {
    sequence<TextFormat> textFormats;
};

[Exposed=Window]
interface TextFormatUpdateEvent : Event {
    constructor(DOMString type, optional TextFormatUpdateEventInit options = {});
    sequence<TextFormat> getTextFormats();
};

dictionary CharacterBoundsUpdateEventInit : EventInit {
    unsigned long rangeStart;
    unsigned long rangeEnd;
};

[Exposed=Window]
interface CharacterBoundsUpdateEvent : Event {
    constructor(DOMString type, optional CharacterBoundsUpdateEventInit options = {});
    readonly attribute unsigned long rangeStart;
    readonly attribute unsigned long rangeEnd;
};

B. 贡献者

编辑者注

添加贡献者

C. 参考文献

C.1 规范性引用

[dom]
DOM 标准。Anne van Kesteren。WHATWG。 现行标准。URL:https://dom.spec.whatwg.org/
[geometry-1]
几何接口模块 第 1 级。 Simon Pieters;Chris Harrelson。W3C。2018 年 12 月 4 日。W3C 候选推荐标准。URL:https://www.w3.org/TR/geometry-1/
[html]
HTML 标准。Anne van Kesteren; Domenic Denicola;Dominic Farolino;Ian Hickson;Philip Jägenstedt;Simon Pieters。WHATWG。现行 标准。URL:https://html.spec.whatwg.org/multipage/
[uievents]
UI 事件。Gary Kacmarcik;Travis Leithead。W3C。2024 年 9 月 7 日。W3C 工作草案。URL:https://www.w3.org/TR/uievents/
[webidl]
Web IDL 标准。Edgar Chen;Timothy Gu。 WHATWG。现行标准。URL:https://webidl.spec.whatwg.org/

C.2 参考性引用

[input-events]
输入事件 第 1 级。Johannes Wilm。W3C。2023 年 9 月 28 日。W3C 工作草案。URL:https://www.w3.org/TR/input-events-1/