我们的模型映射到DOM树后,看起来像下面这样:
1 2 3 4 5 6 | < div > <!-- root -->
< section > <!-- section -->
<!-- section-inner -->
< div class = "section-inner layout-column" >
< p > <!-- paragraph -->
< strong >< em >Baggins</ em ></ strong > <!-- text -->
|
这个区域(section)节点是从区域模型中产生的,并且会将背景图片和颜色应用到一连串的段落中。
这个区域内(section-inner)节点是根据段落排版属性而产生的,并且决定了主列的宽度。对于大部分段落来说,它是狭窄并且居中的。对于全宽的图片段落来说,它是100%宽的。对于上面的网格来说,它是原始的一般。
下一个节点是段落的语义类别: P, H2, H3, PRE, FIGURE, BLOCKQUOTE, OL-LI (有序列表项), 和 UL-LI (无序列表项).
当我们把标签类别转换到DOM节点的时候,我们会按照类别排序它们:A,然后 STRONG,再然后 EM。我们永远不会打印一个包含锚定的STRONG标签。我们会拆散它而让锚定包含STRONG标签。
编辑操作
编辑器主要包括6个编辑操作:插入段落,移除段落,更新段落,插入区域,移除区域,以及更新区域。
这些操作表现的会和描述的那样。段落操作会接受一个段落模型和一个索引。区域操作会接受一个区域模型和一个索引。
所有可能的编辑器内容都能够被一系列的这些操作所表述,并且构造这样一个序列通常是比较简单的。
显而易见,内容在这些编辑操作下能够表现的很好。这些操作是直接应用于我们的模型上面的,而不是DOM上面,并且这个模型能够更容易地区分两件东西在视觉上是否是相等的。
捕获编辑操作
当你和编辑器交互的时候,我们必须将你的按键操作和鼠标点击操作转换成那6个操作的一个序列。
这是最复杂的部分。我们不会对那么多的每种可能按键的序列履行职责。这对于一个以英语为语言的用户来说是一个非常巨大的列表,永远不考虑非拉丁字符和键盘。
通过观察,我们能够用常规的ContentEditable键盘操作枚举所有对段落插入和移除的操作方式。他们是:回车(enter,ctrl-m,等。),删除(delete,backspace,等。),悬浮输入(type-over)(在一段选择的文本上输入),以及拷贝。所以我们能够捕获,取消,以及手动将这些键盘事件转换到我们的编辑器内部操作上来。
对于所有其他键盘事件,我们让原有的ContentEditable 行为生效。在键盘事件结束之后,我们把段落的DOM映射回到段落的模型中来,并且和我们之前的模型进行比较。如果DOM改变了,我们会创建一个新的更新段落操作并且通过编辑器管线应用它,保持DOM和模型同步。
快速捕获编辑操作
如果我们有无限计算的能力,那么直接应用这些编辑操作就可以了。我们应用这些操作到模型上,重新渲染的整个页面,最后结束操作。
但是在现实生活中,对每个按键操作都重新渲染整个页面是非常慢的。并且你会看到许多丑陋的闪烁现象,因为内嵌框架(iframes)和图片会一直处于加载中。相反,我们会对模型的改变事件进行监听,并且尽最大可能减少对DOM的改变。
当我在写篇文章时,我可以看到Chrome拼写检查程序在“keypress”单词下面所加的红色下划线在闪烁。这是因为编辑器正在同时对整个段落进行改变,而不是仅仅改变这个段落的一小块。如果我们仅仅对DOM进行相对很小的改变,那么闪烁就会消失,但是这样的代码会相对的更复杂。
期待将来有一个更智能的文本编辑操作
最近有一些来自Chromium贡献者 (Levi Weintraub, Julie Parent, and Jelte Liebrand) 的流言说这些贡献者想去基于聚合元素(Polymer Elements)和Shadow DOM特性重做ContentEditable。这个方案也会像编辑器一样去尝试解决许多同样高级架构方面的问题。
-
创建一个由自定义 聚合元素(Polymer elements)构成的编辑器模型
-
定义编辑器模型与真实的具有 Shadow DOM特性的DOM之间的映射
-
所有在ContentEditable中的按键操作和鼠标点击操作都会被转换成一种抽象的编辑含义,被表示成像{editIntent: ‘delete’}这样的JSON对象。
-
聚合元素(Polymer Elements)对这样的编辑含义操作定义相应的处理方法
如果编辑器能够获取某种编辑含义的API,那么我们就能够抛弃许多转换按键操作到抽象编辑操作的自定义代码了。将我们的段落模型当作聚合(Polymer)/ ShadowDOM元素是一件很有趣的尝试。
ContentEditable是什么
不管我什么时候向那些从事于文本编辑器工作的人解释的时候,他们都认为我在玩花招。
“当然编辑器要比ContentEditable更棒一些。你错了。ContentEditable努力的去成为一个通用的所见即所得HTML编辑器。而一般的编辑器放弃了'通用目的'的需求,所以你能够挑选你想去处理的任何HTML结构。”
这是事实。但是确是误导的。
一个好的所见即所得编辑器和一个好的具有通用目的HTML编辑器在理论上是不一致的。不可能把ContentEditable 构建成那样的,因为它们在需求上是冲突的。