编辑器模块结构

本文档解释了编辑器模块的结构和类的概述。

简介

此模块实现了可编辑元素或文档的内置编辑器,并且**不**实现与 DOM API 和编辑 UI 的视觉反馈的接口。换句话说,此模块实现了 DOM 树编辑器。

目录

composer

以前,此目录包含“Composer” UI 相关的代码。但是,目前,此目录包含nsEditingSessionComposerCommandsUpdater

libeditor

这是包含编辑器“核心”实现的主要目录。

spellchecker

尽管目录名称如此,拼写检查器的实现**不在**此处。此目录仅包含编辑器类和拼写检查器之间的桥梁,以及用于拼写检查的可编辑内容的序列化文本。

txmgr

此目录包含事务项和事务类。它们被设计用于通用用例,例如管理浏览器的书签/历史记录的撤消/重做等,但它们仅被编辑器使用。

主要类

EditorBase

EditorBase类是编辑器的抽象类。它继承了nsIEditor XPCOM 接口,实现了与类实例一起工作的通用功能,并通过mozilla/EditorBase.h公开。

TextEditor

TextEditor类是纯文本编辑器的实现,它与<input><textarea>一起工作。它的公开根是宿主 HTML 元素,但是,可编辑根是在公开根元素下的原生匿名子树中创建的匿名<div>。这会在匿名<div>中将Text节点作为第一个子节点,并修改其数据。如果文本数据以换行符结尾,即最后一行为空,则附加<br>元素以使空行可见。

它还实现了密码编辑器。它的工作方式与普通文本编辑器几乎相同,但每个字符都可能被布局模块使用“●”或“*”等掩码字符掩盖,以保护隐私。因此,它管理密码的掩码/未掩码范围,并且可能在一段时间后自动为移动设备输入键入的字符。

它通过mozilla/TextEditor.h公开。

TextEditor 中的选择

每个<input><textarea>都有独立的SelectionnsFrameSelection

TextEditor 的生命周期

在创建可编辑的<textarea>或文本可编辑的<input>元素获得焦点时创建。请注意,如果在不安全运行脚本时请求初始化,则它可能会异步运行。当元素变得不可见时销毁。请注意,TextEditor在宿主元素的每次重新渲染时都会重新创建。这意味着,例如,当<input><textarea>的大小发生更改时,TextEditor会重新创建并忘记撤消/重做事务,但会接管上一个实例的值、选择范围和 IME 的组合。

HTMLEditor

HTMLEditor类是富文本编辑器的实现,它与contenteditableDocument.designMode和 XUL <editor>一起工作。即使文档具有多个具有contenteditable属性的元素,每个文档也会创建一个实例。因此,撤消/重做事务在所有可编辑区域中共享。

它通过mozilla/HTMLEditor.h公开。

HTMLEditor 中的选择

用于DocumentWindow的实例。当可编辑元素获得焦点时,HTMLEditorSelection的祖先限制设置为聚焦的元素或Document<body>。然后,Selection不能跨越限制元素的边界。

HTMLEditor 的生命周期

Document中创建第一个可编辑区域时创建。当最后一个可编辑区域变为不可编辑时销毁。

目前,即使HTMLEditor正在处理编辑命令/操作(在编辑器类中称为编辑操作),每个 DOM 变异都可以与旧的 DOM 变异事件同步跟踪。因此,在从HTMLEditor更改 DOM 树之后,可能会发生任何状态,例如,编辑器本身可能已被销毁,DOM 树可能已被修改,Selection可能已被修改等。此问题在bug 1710784中跟踪。

EditorUtils

此类仅具有EditorBaseTextEditor使用的静态实用程序方法,并且也可能被HTMLEditor使用。即,**不仅**由HTMLEditor使用的实用程序方法应在此类中实现。

通常,无状态方法应作为实用程序类的static方法实现,因为编辑器类具有过多的方法和字段。

此类未公开。

HTMLEditUtils

此类仅具有仅由HTMLEditor使用的静态实用程序方法。

此类未公开。

AutoRangeArray

此类是仅栈类,旨在复制正常的选择范围。在新代码中,不应直接引用Selection,而应改为让方法引用此实例并对其进行修改。最后,根调用者应将范围应用于Selection。然后,HTMLEditor无需处理旧的 DOM 变异事件侦听器带来的意外Selection更新。

此类未公开。

EditorDOMPoint、EditorRawDOMPoint、EditorDOMPointInText、EditorRawDOMPointInText

它表示 DOM 树中的一个点,具有以下之一

  • 容器节点及其中的偏移量

  • 容器节点及其中的子节点

  • 容器节点及其中的偏移量和子节点

在大多数情况下,实例使用容器以及仅偏移量或子节点进行初始化。然后,当调用Offset()GetChild()时,最后一个是“固定的”。在偏移量和/或子节点之前插入新的子节点后,IsSetAndValid()将返回false,因为子节点不是偏移量处的子节点。

如果要在修改 DOM 树后继续使用,可以使用AutoEditorDOMPointChildInvalidatorAutoEditorDOMRangeChildrenInvalidator使实例忘记偏移量或子节点。忘记方法没有简单公开的原因是,即使在修改 DOM 树后,Offset()GetChild()仍然可用以获取缓存的偏移量和子节点,此外,哪些方法可能会修改 DOM 树对于开发人员来说可能不清楚。因此,仅为这些辅助类创建块使更新点更加清晰。

这些类通过mozilla/EditorDOMPoint.h公开。

EditorDOMRange、EditorRawDOMRange、EditorDOMRangeInTexts、EditorRawDOMRangeInTexts

它使用 2 个Editor*DOMPoint(InText)表示 DOM 树中的 2 个点。与nsRange不同,实例不跟踪 DOM 树更改。因此,初始化比nsRange快得多,并且可以在栈中。

这些类通过mozilla/EditorDOMPoint.h公开。

AutoTrackDOMPoint、AutoTrackDOMRange

这些方法通过应用编辑器实例引起的更改来更新销毁时的Editor*DOMPoint(InText)Editor*DOMRange(InTexts)。换句话说,它们不会跟踪 Web 应用(如旧的 DOM 变异事件侦听器)带来的 DOM 树更改。

这些类目前通过mozilla/SelectionState.h公开,但我们应该停止公开它们。

WSRunScanner

HTMLEditor的辅助类。此类从 DOM 点或 DOM 节点扫描之前或(包含)下一个可见内容。这通常用于考虑<br>由于靠近块元素边界而是否可见或不可见,从光标位置查找最近的可编辑字符等。但是,运行成本**不**便宜,因此,如果您找到另一种更简单的方法来考虑它,请使用它,并且它也不检查节点的实际样式(可见与不可见、块与内联),因此在棘手的情况下您可能会得到意外的结果。

此类未公开。

WhiteSpaceVisibilityKeeper

HTMLEditor的辅助类,用于处理可折叠空白字符,如同用户预期的那样。此类目前处理空白字符规范化(例如,当用户输入多个可折叠空白字符时,它会将其中一些替换为 NBSP),但行为与其他浏览器不同。我们应该尽可能地重新实现此功能,模拟其他浏览器的行为,但目前由于不影响 UX 而被推迟(在bug 1658699中跟踪)。

此类未公开。

*Transaction

*Transaction 类表示一个更新 DOM 树的小型事务,并实现了更新的“执行”、“撤销”和“重做”。

请注意,每个类的实例创建过多(一个编辑操作可能会导致多个事务)。因此,每个实例必须尽可能小,如果您有将多个实例折叠成一个实例的想法,则应修复它。然后,用户可以使用内存更小的设备运行 Firefox,尤其是在TextEditor中使用事务时。