简体中文

开发者工具 · HTML WYSIWYG 编辑器

为编辑者解释 DOM:为什么 HTML 是树,而不是文本文件

· 背景

html dom 内容可编辑

分为标题段落重点和列表节点的文档片段
原始 ToolAcre 矢量图

为非程序员介绍了文档对象模型,涵盖嵌套规则、父元素和子元素以及浏览器如何修复无效嵌套,以解释看似任意的编辑器行为。

为什么你的 <p> 会自行关闭 - 打开时标记在粘贴后发生了变化

在片段通过编辑器后,段落可能会看起来关闭或移动,因为最终重要的是生成的树(而不是作者的原始字符序列)。 ToolAcre 添加了另一个转换:它在自己的白名单下标记并重写浏览器派生的源。

当源更改时,询问哪个阶段更改了它。浏览器可能已经改变了内容可编辑的 DOM,或者清理程序可能已经映射了别名、解开节点或平衡了接受的标签。将每个差异称为“浏览器修复了它”隐藏了这个重要的边界。

盒子里面的盒子 — 通过一个简短的例子介绍树模型

将元素视为通过父子关系连接的盒子。在`<p>Read <strong>carefully</strong>.</p>`中,p是text的parent,strong和more text;坚强是仔细这个词的母体。源代码缩进可以说明树,但不能创建关系。

ToolAcre 漂亮的格式化程序将块容器放在行上,并将内联元素与周围的文本保持在一起。列表接收缩进的 li 行。此格式用于读取已清理的输出。无论源是紧凑的还是跨行分布的,实际模型仍然保留嵌套元素和文本节点。

允许的嵌套由 ToolAcre 的重写器平衡;浏览器内容模型更广泛

HTML 定义的内容模型比该编辑器的策略更广泛、更详细。 ToolAcre 允许特定的集合,但不验证每个语义嵌套规则。它的堆栈确保允许的标签之间形成良好的闭合;这并不能证明每个生成的关系都是目标的理想 HTML。

例如,列表应包含适当的列表项,但通用堆栈可以保留不寻常的允许组合,因为它不是模式验证器。作者应通过工具栏或审阅来源构建合理的标题、段落和列表,然后在正确性至关重要时根据目标要求进行验证。

ToolAcre 使用堆栈修复接受的标签,而不是完整的 HTML 解析算法

浏览器应用具有错误恢复功能的完整 HTML 解析算法。 ToolAcre 不会重新实现它。它的标记生成器可以识别允许列表所需的结构,并且当交叉结束标记出现时,它的编写器会关闭接受的内部元素。它会丢弃杂散的关闭并在最后关闭剩余的打开。

源代码明确命名解析器差异作为不将该模块视为一般恶意输入 XSS 过滤器的原因。浏览器可以以不同的方式解释故意格式错误的字符串。预览沙箱对 ToolAcre 内部的执行提供了独立的限制,而服务器仍然需要适当的 HTML5 感知卫生。

文本节点和空格 — 涵盖了树中标签之间存在空格和换行符的原因

元素之间的文本成为文本标记,包括空白字符。漂亮的格式化程序会折叠 pre 之外的普通空白,而 pre 内容则被准确保留。纯文本转换会在块结尾和 br 之后插入换行符,然后减少过多空白行的运行。

空白在每个阶段的参与程度不同。视觉间距可以来自文本、br、块边界或 CSS。检查节点和字符,而不是将每个可见间隙视为边距。清理程序可以标准化格式化空白,而不改变读者看到的单词。

工作示例:用列表跟踪两段注释 - 将生成的标记读取为树,识别父母和孩子

构建 `<h2>Checklist</h2><p>Read <strong>carefully</strong>.</p><ul><li>Source</li><li>Preview</li></ul>`。该片段具有三个根级元素子级。段落文字内容丰富有力;该列表包含两个 li 子项,每个子项都有文本。

在源和视觉之间切换。允许的树应该保持平衡,漂亮模式会将标题和段落放在行上,同时缩进列表项。这个练习是有控制的;它不会演示每个格式错误的输入或浏览器修复路径。

这不包括什么 - JavaScript DOM 编程或 CSS 框模型

本文不教授 JavaScript DOM 编程、突变观察器、选择 API 或 CSS 框模型。元素树和布局盒树相关但不完全相同。它也没有声称手写的令牌列表是浏览器 DOM。

整洁的树无法得出通用的安全结论。攻击者可以针对解析差异和 URL,这就是输出过滤、沙盒预览和服务器卫生仍然不同的原因。使用树模型来推理结构,而不是放弃接收系统的安全审查。

要点:用树来思考 — 总结了心智模型以及 ToolAcre 的 HTML WYSIWYG 编辑器的标记输出如何显示您正在构建的树

当视觉行为看起来任意时,在树上思考。识别您想要的父节点、子节点和文本节点,然后将它们与过滤后的源进行比较。 ToolAcre 通过将内容可编辑的草稿与可读的重写片段配对,使这种检查变得实用。

强大的心智模型也暴露出局限性:展开的 div 失去父级,删除的脚本失去其子树,并且 b 变得强大。一旦这些转换变得明确,修正就变成了结构性决策,而不是标记仍然未知的重复视觉推动。