feat: add onselectionchange api
This commit is contained in:
parent
0de9eb6f6a
commit
afa36a833e
|
@ -1,133 +0,0 @@
|
||||||
import { ListType } from '.'
|
|
||||||
import Editor from '../../editor/index'
|
|
||||||
import $, { DomElement } from '../../utils/dom-core'
|
|
||||||
import { ContainerFragment } from './ListHandle'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 过滤 选择的 node 节点
|
|
||||||
* @returns { DomElement[] } DomElement[]
|
|
||||||
*/
|
|
||||||
export function filterSelectionNodes($nodes: DomElement[]): DomElement[] {
|
|
||||||
const $listHtml: DomElement[] = []
|
|
||||||
$nodes.forEach(($node: DomElement) => {
|
|
||||||
const targerName = $node.getNodeName()
|
|
||||||
if (targerName !== ListType.OrderedList && targerName !== ListType.UnorderedList) {
|
|
||||||
// 非序列
|
|
||||||
$listHtml.push($node)
|
|
||||||
} else {
|
|
||||||
// 序列
|
|
||||||
if ($node.prior) {
|
|
||||||
$listHtml.push($node.prior)
|
|
||||||
} else {
|
|
||||||
const $children = $node.children()
|
|
||||||
$children?.forEach(($li: HTMLElement) => {
|
|
||||||
$listHtml.push($($li))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
return $listHtml
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新选区
|
|
||||||
* @param $node
|
|
||||||
*/
|
|
||||||
|
|
||||||
export function updateRange(editor: Editor, $node: DomElement, collapsed: boolean) {
|
|
||||||
const selection = editor.selection
|
|
||||||
const range = document.createRange()
|
|
||||||
|
|
||||||
// ===============================
|
|
||||||
// length 大于 1
|
|
||||||
// 代表着转换是一个文档节点多段落
|
|
||||||
// ===============================
|
|
||||||
if ($node.length > 1) {
|
|
||||||
range.setStart($node.elems[0], 0)
|
|
||||||
range.setEnd($node.elems[$node.length - 1], $node.elems[$node.length - 1].childNodes.length)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===============================
|
|
||||||
// 序列节点 或 单段落
|
|
||||||
// ===============================
|
|
||||||
else {
|
|
||||||
range.selectNodeContents($node.elems[0])
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===============================
|
|
||||||
// collapsed 为 true 代表是光标
|
|
||||||
// ===============================
|
|
||||||
collapsed && range.collapse(false)
|
|
||||||
selection.saveRange(range)
|
|
||||||
selection.restoreSelection()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取起点元素
|
|
||||||
* @param $startElem 开始序列节点
|
|
||||||
*/
|
|
||||||
export function getStartPoint($startElem: DomElement): DomElement {
|
|
||||||
return $startElem.prior
|
|
||||||
? $startElem.prior // 有 prior 代表不是全选序列
|
|
||||||
: $($startElem.children()?.elems[0]) // 没有则代表全选序列
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取结束元素
|
|
||||||
* @param $endElem 结束序列节点
|
|
||||||
*/
|
|
||||||
export function getEndPoint($endElem: DomElement): DomElement {
|
|
||||||
return $endElem.prior
|
|
||||||
? $endElem.prior // 有 prior 代表不是全选序列
|
|
||||||
: $($endElem.children()?.last().elems[0]) // 没有则代表全选序列
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 在您指定节点的已有子节点之前插入新的子节点。
|
|
||||||
* @param { DomElement } $node 指定节点
|
|
||||||
* @param { ContainerFragment } newNode 插入的新子节点
|
|
||||||
* @param { Node | null } existingNode 指定子节点
|
|
||||||
*/
|
|
||||||
export function insertBefore(
|
|
||||||
$node: DomElement,
|
|
||||||
newNode: ContainerFragment,
|
|
||||||
existingNode: Node | null = null
|
|
||||||
) {
|
|
||||||
$node.parent().elems[0].insertBefore(newNode, existingNode)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建指定的 element 对象
|
|
||||||
*/
|
|
||||||
export function createElement(target: string): HTMLElement {
|
|
||||||
return document.createElement(target)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建文档片段
|
|
||||||
*/
|
|
||||||
export function createDocumentFragment(): DocumentFragment {
|
|
||||||
return document.createDocumentFragment()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 生成 li 标签的元素,并返回 $fragment 文档片段
|
|
||||||
* @param { DomElement[] } $nodes 需要转换成 li 的 dom 元素数组
|
|
||||||
* @param { ContainerFragment } $fragment 用于存储生成后 li 元素的文档片段
|
|
||||||
*/
|
|
||||||
export function createElementFragment(
|
|
||||||
$nodes: DomElement[],
|
|
||||||
$fragment: ContainerFragment,
|
|
||||||
tag: string = 'li'
|
|
||||||
): ContainerFragment {
|
|
||||||
$nodes.forEach(($node: DomElement) => {
|
|
||||||
const $list = createElement(tag)
|
|
||||||
$list.innerHTML = $node.html()
|
|
||||||
console.log('$list', $list)
|
|
||||||
console.log('$fragment', $fragment)
|
|
||||||
$fragment.appendChild($list)
|
|
||||||
$node.remove()
|
|
||||||
})
|
|
||||||
return $fragment
|
|
||||||
}
|
|
|
@ -1,131 +0,0 @@
|
||||||
import { ListType } from '.'
|
|
||||||
import Editor from '../../editor/index'
|
|
||||||
import $, { DomElement } from '../../utils/dom-core'
|
|
||||||
import { ContainerFragment } from './ListHandle'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 过滤 选择的 node 节点
|
|
||||||
* @returns { DomElement[] } DomElement[]
|
|
||||||
*/
|
|
||||||
export function filterSelectionNodes($nodes: DomElement[]): DomElement[] {
|
|
||||||
const $listHtml: DomElement[] = []
|
|
||||||
$nodes.forEach(($node: DomElement) => {
|
|
||||||
const targerName = $node.getNodeName()
|
|
||||||
if (targerName !== ListType.OrderedList && targerName !== ListType.UnorderedList) {
|
|
||||||
// 非序列
|
|
||||||
$listHtml.push($node)
|
|
||||||
} else {
|
|
||||||
// 序列
|
|
||||||
if ($node.prior) {
|
|
||||||
$listHtml.push($node.prior)
|
|
||||||
} else {
|
|
||||||
const $children = $node.children()
|
|
||||||
$children?.forEach(($li: HTMLElement) => {
|
|
||||||
$listHtml.push($($li))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
return $listHtml
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新选区
|
|
||||||
* @param $node
|
|
||||||
*/
|
|
||||||
|
|
||||||
export function updateRange(editor: Editor, $node: DomElement, collapsed: boolean) {
|
|
||||||
const selection = editor.selection
|
|
||||||
const range = document.createRange()
|
|
||||||
|
|
||||||
// ===============================
|
|
||||||
// length 大于 1
|
|
||||||
// 代表着转换是一个文档节点多段落
|
|
||||||
// ===============================
|
|
||||||
if ($node.length > 1) {
|
|
||||||
range.setStart($node.elems[0], 0)
|
|
||||||
range.setEnd($node.elems[$node.length - 1], $node.elems[$node.length - 1].childNodes.length)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===============================
|
|
||||||
// 序列节点 或 单段落
|
|
||||||
// ===============================
|
|
||||||
else {
|
|
||||||
range.selectNodeContents($node.elems[0])
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===============================
|
|
||||||
// collapsed 为 true 代表是光标
|
|
||||||
// ===============================
|
|
||||||
collapsed && range.collapse(false)
|
|
||||||
selection.saveRange(range)
|
|
||||||
selection.restoreSelection()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取起点元素
|
|
||||||
* @param $startElem 开始序列节点
|
|
||||||
*/
|
|
||||||
export function getStartPoint($startElem: DomElement): DomElement {
|
|
||||||
return $startElem.prior
|
|
||||||
? $startElem.prior // 有 prior 代表不是全选序列
|
|
||||||
: $($startElem.children()?.elems[0]) // 没有则代表全选序列
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取结束元素
|
|
||||||
* @param $endElem 结束序列节点
|
|
||||||
*/
|
|
||||||
export function getEndPoint($endElem: DomElement): DomElement {
|
|
||||||
return $endElem.prior
|
|
||||||
? $endElem.prior // 有 prior 代表不是全选序列
|
|
||||||
: $($endElem.children()?.last().elems[0]) // 没有则代表全选序列
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 在您指定节点的已有子节点之前插入新的子节点。
|
|
||||||
* @param { DomElement } $node 指定节点
|
|
||||||
* @param { ContainerFragment } newNode 插入的新子节点
|
|
||||||
* @param { Node | null } existingNode 指定子节点
|
|
||||||
*/
|
|
||||||
export function insertBefore(
|
|
||||||
$node: DomElement,
|
|
||||||
newNode: ContainerFragment,
|
|
||||||
existingNode: Node | null = null
|
|
||||||
) {
|
|
||||||
$node.parent().elems[0].insertBefore(newNode, existingNode)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建指定的 element 对象
|
|
||||||
*/
|
|
||||||
export function createElement(target: string): HTMLElement {
|
|
||||||
return document.createElement(target)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建文档片段
|
|
||||||
*/
|
|
||||||
export function createDocumentFragment(): DocumentFragment {
|
|
||||||
return document.createDocumentFragment()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 生成 li 标签的元素,并返回 $fragment 文档片段
|
|
||||||
* @param { DomElement[] } $nodes 需要转换成 li 的 dom 元素数组
|
|
||||||
* @param { ContainerFragment } $fragment 用于存储生成后 li 元素的文档片段
|
|
||||||
*/
|
|
||||||
export function createElementFragment(
|
|
||||||
$nodes: DomElement[],
|
|
||||||
$fragment: ContainerFragment,
|
|
||||||
tag: string = 'li'
|
|
||||||
): ContainerFragment {
|
|
||||||
$nodes.forEach(($node: DomElement) => {
|
|
||||||
const $list = createElement(tag)
|
|
||||||
$list.innerHTML = $node.html()
|
|
||||||
$fragment.appendChild($list)
|
|
||||||
$node.remove()
|
|
||||||
})
|
|
||||||
return $fragment
|
|
||||||
}
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>wangEditor example</title>
|
||||||
|
<style>
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<p>
|
||||||
|
wangEditor demo
|
||||||
|
</p>
|
||||||
|
<div id="div1">
|
||||||
|
<p>欢迎使用 <b>wangEditor</b> 富文本编辑器</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="div2">
|
||||||
|
<p>欢迎使用 <b>wangEditor</b> 富文本编辑器</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="../dist/wangEditor.js"></script>
|
||||||
|
<script>
|
||||||
|
// 改为使用var声明,才能在window对象上获取到编辑器实例,方便e2e测试
|
||||||
|
var E = window.wangEditor
|
||||||
|
var editor = new E('#div1')
|
||||||
|
editor.config.onSelectionChange = function (newHtml) {
|
||||||
|
console.log('editor', newHtml)
|
||||||
|
}
|
||||||
|
editor.create()
|
||||||
|
|
||||||
|
// setTimeout(() => {
|
||||||
|
// console.log("摧毁了")
|
||||||
|
// editor.destroy()
|
||||||
|
// }, 3000)
|
||||||
|
|
||||||
|
// var editor2 = new E('#div2')
|
||||||
|
// editor2.config.onSelectionChange = function (newHtml) {
|
||||||
|
// console.log('editor2', newHtml)
|
||||||
|
// }
|
||||||
|
// editor2.create()
|
||||||
|
|
||||||
|
// setTimeout(() => {
|
||||||
|
// console.log("摧毁了")
|
||||||
|
// editor2.destroy()
|
||||||
|
// }, 3000)
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
|
@ -49,6 +49,7 @@ export type ConfigType = {
|
||||||
pasteTextHandle: Function
|
pasteTextHandle: Function
|
||||||
styleWithCSS: boolean
|
styleWithCSS: boolean
|
||||||
linkImgCallback: Function
|
linkImgCallback: Function
|
||||||
|
onSelectionChange: Function
|
||||||
|
|
||||||
placeholder: string
|
placeholder: string
|
||||||
zIndexFullScreen: number
|
zIndexFullScreen: number
|
||||||
|
|
|
@ -20,6 +20,7 @@ import ZIndex from './z-index'
|
||||||
import Change from './change/index'
|
import Change from './change/index'
|
||||||
import History from './history/index'
|
import History from './history/index'
|
||||||
import disableInit from './disable'
|
import disableInit from './disable'
|
||||||
|
import SelectionChange from './selection-change'
|
||||||
|
|
||||||
import initPlugins, { RegisterOptions, pluginsListType, registerPlugin } from '../plugins'
|
import initPlugins, { RegisterOptions, pluginsListType, registerPlugin } from '../plugins'
|
||||||
|
|
||||||
|
@ -70,6 +71,7 @@ class Editor {
|
||||||
public change: Change
|
public change: Change
|
||||||
public history: History
|
public history: History
|
||||||
public isEnable: Boolean
|
public isEnable: Boolean
|
||||||
|
public onSelectionChange: SelectionChange
|
||||||
|
|
||||||
// 实例销毁前需要执行的钩子集合
|
// 实例销毁前需要执行的钩子集合
|
||||||
private beforeDestroyHooks: Function[] = []
|
private beforeDestroyHooks: Function[] = []
|
||||||
|
@ -113,6 +115,7 @@ class Editor {
|
||||||
this.zIndex = new ZIndex()
|
this.zIndex = new ZIndex()
|
||||||
this.change = new Change(this)
|
this.change = new Change(this)
|
||||||
this.history = new History(this)
|
this.history = new History(this)
|
||||||
|
this.onSelectionChange = new SelectionChange(this)
|
||||||
|
|
||||||
const { disable, enable } = disableInit(this)
|
const { disable, enable } = disableInit(this)
|
||||||
this.disable = disable
|
this.disable = disable
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
/**
|
||||||
|
* @description range变化
|
||||||
|
* @author liuwei
|
||||||
|
*/
|
||||||
|
import Editor from '../index'
|
||||||
|
export default class SelectionChange {
|
||||||
|
constructor(public editor: Editor) {
|
||||||
|
// 绑定的事件
|
||||||
|
const init = () => {
|
||||||
|
const activeElement = document.activeElement
|
||||||
|
if (activeElement === editor.$textElem.elems[0]) {
|
||||||
|
this.emit()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 选取变化事件监听
|
||||||
|
window.document.addEventListener('selectionchange', init)
|
||||||
|
|
||||||
|
// 摧毁时移除监听
|
||||||
|
this.editor.beforeDestroy(() => {
|
||||||
|
window.document.removeEventListener('selectionchange', init)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
public emit(): void {
|
||||||
|
// 执行rangeChange函数
|
||||||
|
const { onSelectionChange } = this.editor.config
|
||||||
|
if (onSelectionChange) {
|
||||||
|
const selection = this.editor.selection
|
||||||
|
selection.saveRange()
|
||||||
|
if (!selection.isSelectionEmpty())
|
||||||
|
onSelectionChange({
|
||||||
|
// 当前文本
|
||||||
|
text: selection.getSelectionText(),
|
||||||
|
// 当前的html
|
||||||
|
html: selection.getSelectionContainerElem()?.elems[0].innerHTML,
|
||||||
|
// select对象
|
||||||
|
selection: selection,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue