Bootstrap

canvas-editor首行缩进

canvas-editor中渲染部分的源码都在Draw.ts里,能找到computeRowList方法中并没有实现首行缩进相关的逻辑,但是实现了element.type === ElementType.TAB的缩进,如图:canvas-editor源码-Tab缩进
因此我们可以基于tab进行首行缩进的逻辑编写,在main.ts末尾(初始化脚本内部)添加如下内容:

  // 段落首行缩进按钮
  const indentParagraphsDom = document.querySelector<HTMLDivElement>(
    '.menu-item__indent-paragraphs'
  )!
  indentParagraphsDom.onclick = function () {
    console.log('indent paragraphs')
    const data = instance.command.getValue()
    console.log('data: ', data)
    // 插入tab符
    const tabElement: IElement = {
      type: ElementType.TAB,
      value: ''
    }
    if (data && data.data && Array.isArray(data.data.main)) {
      const newMain = data.data.main.flatMap(item => {
        // 检查是否为段落(不是标题或换行符)
        if (
          typeof item === 'object' &&
          !item.type &&
          typeof item.value === 'string' &&
          item.value.trim() !== '' &&
          item.value !== '\n'
        ) {
          // 如果是段落,在前面插入制表符对象
          return [tabElement,
            item
          ]
        }
        return [item]
      })
      const fixedData = { ...data.data, main: newMain }
      console.log('fixedData: ', fixedData)
      // 更新编辑器内容
      instance.command.executeSetValue(fixedData)
    }
    const newdata = instance.command.getValue()
    console.log('newdata: ', newdata)
  }

我们就可以用一个按钮来直接控制全文正文部分进行首行缩进
在这里插入图片描述
更进一步的,如果想要一键切换缩进/不缩进可以这样写:

// 段落首行缩进按钮
const indentParagraphsDom = document.querySelector<HTMLDivElement>(
  '.menu-item__indent-paragraphs'
)!
indentParagraphsDom.onclick = function () {
  console.log('indent paragraphs')
  const data = instance.command.getValue()
  console.log('data: ', data)
  
  if (data && data.data && Array.isArray(data.data.main)) {
    let shouldRemoveTabs = false
    const newMain: IElement[] = []
    
    // 检查是否存在制表符
    shouldRemoveTabs = data.data.main.some((item, index) => 
      item.type === ElementType.TAB && 
      index + 1 < data.data.main.length && 
      typeof data.data.main[index + 1] === 'object' &&
      !data.data.main[index + 1].type &&
      typeof data.data.main[index + 1].value === 'string' &&
      data.data.main[index + 1].value.trim() !== '' &&
      data.data.main[index + 1].value !== '\n'
    )
    
    console.log('shouldRemoveTabs:', shouldRemoveTabs)

    for (let i = 0; i < data.data.main.length; i++) {
      const item = data.data.main[i]
      if (shouldRemoveTabs) {
        // 移除制表符
        if (item.type !== ElementType.TAB) {
          newMain.push(item)
        }
      } else {
        // 添加制表符
        if (typeof item === 'object' &&
            !item.type &&
            typeof item.value === 'string' &&
            item.value.trim() !== '' &&
            item.value !== '\n') {
          // 如果是段落,在前面添加制表符
          if (i === 0 || data.data.main[i-1].type !== ElementType.TAB) {
            newMain.push({ type: ElementType.TAB, value: '' })
          }
        }
        newMain.push(item)
      }
    }
    
    const fixedData = { ...data.data, main: newMain }
    console.log('fixedData: ', fixedData)
    // 更新编辑器内容
    instance.command.executeSetValue(fixedData)
  }
  const newdata = instance.command.getValue()
  console.log('newdata: ', newdata)
}
;