Implementation

实现一个类似语雀的Markdown+富文本编辑器,基于slate.js

基于Commmark的自定义

只有两种Container Blocks:

  • blockquote里面只能有paragraph, list
  • list里面只能有listItem, 每个list有属性type, indent, numbered-list有start

Leaf Blocks:

  • 无setext heading, indented code block, html block, link reference definition, list
  • 剩下的是: paragraph, thematic break, ATX heading, fenced code block, listItem
  • listItem 增加checkbok类型
  • 增加 display math

Inlines:

  • 增加inline math

List

设计一:
有需要的话,将ListNode,或ListItemNode 加入 DirtyPath, 在 editor.normalize(node) 中:

  • 计算ol的start
  • merge相邻的listItem
  • 删除空的ListNode (待定)

需要添加的功能:

  • insertBreak: in list
  • toggle list: in or out list
  • deleteBackward: in or out list
  • insertText(‘ ‘): out list
  • deleteFragment
  • insertFragment

    1. dsjdj
  1. jdsldj

sdkdjsldjsljkd

  1. ol 2-3
    • ul 3-1
    • ul 3-2
  2. ol 2-3
    • ul 3-1
    • ul 3-2
    1. ul 1-1
  3. oddss
    • dsdss
  4. ol 2-2sdjksdkks
  5. ol 2-3
    • ul 3-1
    • ul 3-2
  6. ol 2-4
    1. ul 4-1

    2. ul 4-2
    3. ul 4-3
  1. dddd
  • kdsjldj
  • jkkd
  • dsjlds
  • dsdds
  1. ddsds
  2. dsjldskj

List 操作

Action Source Action Possible result 处理
beforeInput insertSpace p 变成 ul, ol 1
insertBreak 增加一个list-item 2
一个list-item变成p 3
deleteBackword indent - 1 4
一个list-Item 变成 p
删掉一个p 7
insertFromPaste 插入(或将p变成)一个Fragment 5
onPaste onPaste
onCut 删除一个Fragment 6
toggleList p和ul,ol 切换
OnKeyDown Tab indent + 1 4
  1. 需与左、右 merge, 修正右边的 start (一条DirtyPath: 该p所在Path),需左右扫描
  2. 如果是在ol中,需修正右边的start (一条DirtyPath: 该ol右边节点所在Path),只需向右扫描
  3. 需修正右边的start (一条DirtyPath, 该p 右边节点的Path),需左、右扫描
  4. 需与左、右merge, 修正右边的start(一条DirthPath, 该li lift之后的节点Path), 需左右扫描
  5. 需与左、右merge, 修正fragment中以及右边的start, 需左、右扫描
  6. 需与左merge, 修正右边的start, 需左右扫描
  7. DirtyPath 是 p的下一个ListNode, 需merge, 修正右边的start

API 设计
getListStart = (path: Path): number[] => {}
input: path为一个Node,如果不是ListNode则返回 []
output: path及其左边所有连续listnode造成的右边每级ol的start值

fixList = (path:Path): void => {}
input: path为一个node

  • 如果node不是ListNode则直接return
  • merge左右
  • 调用getListPath
  • 修正node及其右边连续listNode的start

fixFragment(paths: Path[]):void => {}

  • 先看左边,merge左边,求listStart
  • 扫描fragment
  • 再看右边,merge右边,往右扫描