编辑器模块结构¶
本文档解释了编辑器模块的结构和类的概述。
简介¶
此模块实现了可编辑元素或文档的内置编辑器,并且**不**实现与 DOM API 和编辑 UI 的视觉反馈的接口。换句话说,此模块实现了 DOM 树编辑器。
目录¶
composer¶
以前,此目录包含“Composer” UI 相关的代码。但是,目前,此目录包含nsEditingSession
和ComposerCommandsUpdater
。
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>
都有独立的Selection
和nsFrameSelection
。
TextEditor 的生命周期¶
在创建可编辑的<textarea>
或文本可编辑的<input>
元素获得焦点时创建。请注意,如果在不安全运行脚本时请求初始化,则它可能会异步运行。当元素变得不可见时销毁。请注意,TextEditor
在宿主元素的每次重新渲染时都会重新创建。这意味着,例如,当<input>
或<textarea>
的大小发生更改时,TextEditor
会重新创建并忘记撤消/重做事务,但会接管上一个实例的值、选择范围和 IME 的组合。
HTMLEditor¶
HTMLEditor
类是富文本编辑器的实现,它与contenteditable
、Document.designMode
和 XUL <editor>
一起工作。即使文档具有多个具有contenteditable
属性的元素,每个文档也会创建一个实例。因此,撤消/重做事务在所有可编辑区域中共享。
它通过mozilla/HTMLEditor.h
公开。
HTMLEditor 中的选择¶
用于Document
和Window
的实例。当可编辑元素获得焦点时,HTMLEditor
将Selection
的祖先限制设置为聚焦的元素或Document
的<body>
。然后,Selection
不能跨越限制元素的边界。
HTMLEditor 的生命周期¶
在Document
中创建第一个可编辑区域时创建。当最后一个可编辑区域变为不可编辑时销毁。
目前,即使HTMLEditor
正在处理编辑命令/操作(在编辑器类中称为编辑操作),每个 DOM 变异都可以与旧的 DOM 变异事件同步跟踪。因此,在从HTMLEditor
更改 DOM 树之后,可能会发生任何状态,例如,编辑器本身可能已被销毁,DOM 树可能已被修改,Selection
可能已被修改等。此问题在bug 1710784中跟踪。
EditorUtils¶
此类仅具有EditorBase
或TextEditor
使用的静态实用程序方法,并且也可能被HTMLEditor
使用。即,**不仅**由HTMLEditor
使用的实用程序方法应在此类中实现。
通常,无状态方法应作为实用程序类的static
方法实现,因为编辑器类具有过多的方法和字段。
此类未公开。
HTMLEditUtils¶
此类仅具有仅由HTMLEditor
使用的静态实用程序方法。
此类未公开。
AutoRangeArray¶
此类是仅栈类,旨在复制正常的选择范围。在新代码中,不应直接引用Selection,而应改为让方法引用此实例并对其进行修改。最后,根调用者应将范围应用于Selection。然后,HTMLEditor无需处理旧的 DOM 变异事件侦听器带来的意外Selection更新。
此类未公开。
EditorDOMPoint、EditorRawDOMPoint、EditorDOMPointInText、EditorRawDOMPointInText¶
它表示 DOM 树中的一个点,具有以下之一
容器节点及其中的偏移量
容器节点及其中的子节点
容器节点及其中的偏移量和子节点
在大多数情况下,实例使用容器以及仅偏移量或子节点进行初始化。然后,当调用Offset()
或GetChild()
时,最后一个是“固定的”。在偏移量和/或子节点之前插入新的子节点后,IsSetAndValid()
将返回false
,因为子节点不是偏移量处的子节点。
如果要在修改 DOM 树后继续使用,可以使用AutoEditorDOMPointChildInvalidator
和AutoEditorDOMRangeChildrenInvalidator
使实例忘记偏移量或子节点。忘记方法没有简单公开的原因是,即使在修改 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
中使用事务时。