wangeditor
Version:
wangEditor - 轻量级 web 富文本编辑器,配置方便,使用简单,开源免费
260 lines (224 loc) • 11.3 kB
text/typescript
import { ContainerFragment } from '.'
import $, { DomElement } from '../../../utils/dom-core'
import { Exec, HandlerListOptions, ListHandle } from './ListHandle'
import {
filterSelectionNodes,
getStartPoint,
getEndPoint,
insertBefore,
createElement,
createDocumentFragment,
createElementFragment,
} from '../utils'
export default class JoinListHandle extends ListHandle implements Exec {
constructor(options: HandlerListOptions) {
super(options)
}
exec(): void {
const { editor, listType, listTarget, $startElem, $endElem } = this.options
// 容器 - HTML 文档片段
let $containerFragment: ContainerFragment
// 获取选中的段落
const $nodes: DomElement[] = editor.selection.getSelectionRangeTopNodes()
// 获取开始段落和结束段落 标签名
const startNodeName = $startElem?.getNodeName()
const endNodeName = $endElem?.getNodeName()
// =====================================
// 开头结尾都是序列的情况下
// 开头序列 和 结尾序列的标签名一致的时候
// =====================================
if (startNodeName === endNodeName) {
// =====================================
// 开头序列 和 结尾序列 中间还有其他的段落的时候
// =====================================
if ($nodes.length > 2) {
// 弹出 开头 和 结尾
$nodes.shift()
$nodes.pop()
// 把中间部分的节点元素转换成 li 元素并添加到文档片段后删除
$containerFragment = createElementFragment(
filterSelectionNodes($nodes), // 过滤 $nodes 获取到符合要求的选中元素节点
createDocumentFragment() // 创建 文档片段
)
// =====================================
// 由于开头序列 和 结尾序列的标签名一样,所以只判断了开头序列的
// 当开头序列的标签名和按钮类型 一致 的时候
// 代表着当前是一个 设置序列 的操作
// =====================================
if (startNodeName === listType) {
// 把结束序列的 li 元素添加到 文档片段中
$endElem.children()?.forEach(($list: HTMLElement) => {
$containerFragment.append($list)
})
// 下序列全选被掏空了,就卸磨杀驴吧
$endElem.remove()
// 在开始序列中添加 文档片段
this.selectionRangeElem.set($containerFragment)
$startElem.elems[0].append($containerFragment)
}
// =====================================
// 由于开头序列 和 结尾序列的标签名一样,所以只判断了开头序列的
// 当开头序列的标签名和按钮类型 不一致 的时候
// 代表着当前是一个 转换序列 的操作
// =====================================
else {
// 创建 开始序列和结束序列的文档片段
const $startFragment = document.createDocumentFragment()
const $endFragment = document.createDocumentFragment()
// 获取起点元素
let $startDom: DomElement = getStartPoint($startElem)
// 获取上半序列中的选中内容,并添加到文档片段中
while ($startDom.length) {
const _element = $startDom.elems[0]
$startDom = $startDom.next()
$startFragment.append(_element)
}
// 获取结束元素
let $endDom: DomElement = getEndPoint($endElem)
// 获取下半序列中选中的内容
const domArr: Element[] = []
while ($endDom.length) {
domArr.unshift($endDom.elems[0])
$endDom = $endDom.prev()
}
// 添加到文档片段中
domArr.forEach(($node: Element) => {
$endFragment.append($node)
})
// 合并文档片段
const $orderFragment = createElement(listTarget)
$orderFragment.append($startFragment)
$orderFragment.append($containerFragment)
$orderFragment.append($endFragment)
$containerFragment = $orderFragment
// 插入
this.selectionRangeElem.set($containerFragment)
$($orderFragment).insertAfter($startElem)
// 序列全选被掏空了后,就卸磨杀驴吧
!$startElem.children()?.length && $startElem.remove()
!$endElem.children()?.length && $endElem.remove()
}
}
// =====================================
// 开头序列 和 结尾序列 中间没有其他的段落
// =====================================
else {
$nodes.length = 0
// 获取起点元素
let $startDom: DomElement = getStartPoint($startElem)
// 获取上半序列中的选中内容
while ($startDom.length) {
$nodes.push($startDom)
$startDom = $startDom.next()
}
// 获取结束元素
let $endDom: DomElement = getEndPoint($endElem)
// 获取下半序列中选中的内容
const domArr: DomElement[] = []
// 获取下半序列中的选中内容
while ($endDom.length) {
domArr.unshift($endDom)
$endDom = $endDom.prev()
}
// 融合内容
$nodes.push(...domArr)
// =====================================
// 由于开头序列 和 结尾序列的标签名一样,所以只判断了开头序列的
// 当开头序列的标签名和按钮类型 一致 的时候
// 代表着当前是一个 取消序列 的操作
// =====================================
if (startNodeName === listType) {
// 创建 文档片段
// 把 li 转换为 p 标签
$containerFragment = createElementFragment(
$nodes,
createDocumentFragment(),
'p'
)
// 插入到 endElem 前
this.selectionRangeElem.set($containerFragment)
insertBefore($startElem, $containerFragment, $endElem.elems[0])
}
// =====================================
// 由于开头序列 和 结尾序列的标签名一样,所以只判断了开头序列的
// 当开头序列的标签名和按钮类型 不一致 的时候
// 代表着当前是一个 设置序列 的操作
// =====================================
else {
// 创建 序列元素
$containerFragment = createElement(listTarget)
// li 元素添加到 序列元素 中
$nodes.forEach(($list: DomElement) => {
$containerFragment.append($list.elems[0])
})
// 插入到 startElem 之后
this.selectionRangeElem.set($containerFragment)
$($containerFragment).insertAfter($startElem)
}
// 序列全选被掏空了后,就卸磨杀驴吧
!$startElem.children()?.length && $endElem.remove()
!$endElem.children()?.length && $endElem.remove()
}
}
// =====================================
// 由于开头序列 和 结尾序列的标签名不一样
// =====================================
else {
// 下序列元素数组
const lowerListElems: DomElement[] = []
// 获取结束元素
let $endDom: DomElement = getEndPoint($endElem)
// 获取下半序列中选中的内容
while ($endDom.length) {
lowerListElems.unshift($endDom)
$endDom = $endDom.prev()
}
// 上序列元素数组
const upperListElems: DomElement[] = []
// 获取起点元素
let $startDom: DomElement = getStartPoint($startElem)
// 获取上半序列中的选中内容,并添加到文档片段中
while ($startDom.length) {
upperListElems.push($startDom)
$startDom = $startDom.next()
}
// 创建 文档片段
$containerFragment = createDocumentFragment()
// 弹出开头和结尾的序列
$nodes.shift()
$nodes.pop()
// 把头部序列的内容添加到文档片段当中
upperListElems.forEach($list => $containerFragment.append($list.elems[0]))
// 生成 li 标签,并且添加到 文档片段中,删除无用节点
$containerFragment = createElementFragment(
filterSelectionNodes($nodes), // 序列中间的数据 - 进行数据过滤
$containerFragment
)
// 把尾部序列的内容添加到文档片段当中
lowerListElems.forEach($list => $containerFragment.append($list.elems[0]))
// 记录
this.selectionRangeElem.set($containerFragment)
// =====================================
// 开头序列 和 设置序列类型相同
// =====================================
if (startNodeName === listType) {
// 插入到 开始序列的尾部(作为子元素)
$startElem.elems[0].append($containerFragment)
// 序列全选被掏空了后,就卸磨杀驴吧
!$endElem.children()?.length && $endElem.remove()
}
// =====================================
// 结尾序列 和 设置序列类型相同
// =====================================
else {
// 插入到结束序列的顶部(作为子元素)
if ($endElem.children()?.length) {
const $endElemChild = $endElem.children() as DomElement
insertBefore($endElemChild, $containerFragment, $endElemChild.elems[0])
} else {
$endElem.elems[0].append($containerFragment)
}
}
}
}
}