wangeditor
Version:
wangEditor - 轻量级 web 富文本编辑器,配置方便,使用简单,开源免费
248 lines (208 loc) • 7.2 kB
text/typescript
/**
* @description 编辑器 class
* @author wangfupeng
*/
import $, { DomElement, DomElementSelector } from '../utils/dom-core'
import { deepClone } from '../utils/util'
import defaultConfig, { ConfigType } from '../config'
import SelectionAndRangeAPI from './selection'
import CommandAPI from './command'
import Text from '../text/index'
import Menus from '../menus/index'
import initDom, { selectorValidator } from './init-fns/init-dom'
import initSelection from './init-fns/init-selection'
import bindEvent from './init-fns/bind-event'
import i18nextInit from './init-fns/i18next-init'
import initFullScreen, { setUnFullScreen, setFullScreen } from './init-fns/set-full-screen'
import scrollToHead from './init-fns/scroll-to-head'
import ZIndex from './z-index'
import Change from './change/index'
import History from './history/index'
import disableInit from './disable'
import initPlugins, { RegisterOptions, pluginsListType, registerPlugin } from '../plugins'
// 创建菜单的 class
import { MenuListType } from '../menus/menu-list'
import BtnMenu from '../menus/menu-constructors/BtnMenu'
import DropList from '../menus/menu-constructors/DropList'
import DropListMenu from '../menus/menu-constructors/DropListMenu'
import Panel from '../menus/menu-constructors/Panel'
import PanelMenu from '../menus/menu-constructors/PanelMenu'
import Tooltip from '../menus/menu-constructors/Tooltip'
let EDITOR_ID = 1
class Editor {
// 暴露 $
static $ = $
static BtnMenu = BtnMenu
static DropList = DropList
static DropListMenu = DropListMenu
static Panel = Panel
static PanelMenu = PanelMenu
static Tooltip = Tooltip
static globalCustomMenuConstructorList: MenuListType = {}
static globalPluginsFunctionList: pluginsListType = {}
public pluginsFunctionList: pluginsListType = {}
public id: string
public toolbarSelector: DomElementSelector
public textSelector?: DomElementSelector
public config: ConfigType
public $toolbarElem: DomElement
public $textContainerElem: DomElement
public $textElem: DomElement
public toolbarElemId: string
public textElemId: string
public isFocus: boolean
public isComposing: boolean
public isCompatibleMode: boolean
public selection: SelectionAndRangeAPI
public cmd: CommandAPI
public txt: Text
public menus: Menus
public i18next: any
public highlight: any
public zIndex: ZIndex
public change: Change
public history: History
public isEnable: Boolean
// 实例销毁前需要执行的钩子集合
private beforeDestroyHooks: Function[] = []
/** 禁用api */
public disable: Function
/** 启用api */
public enable: Function
/**
* 构造函数
* @param toolbarSelector 工具栏 DOM selector
* @param textSelector 文本区域 DOM selector
*/
constructor(toolbarSelector: DomElementSelector, textSelector?: DomElementSelector) {
// id,用以区分单个页面不同的编辑器对象
this.id = `wangEditor-${EDITOR_ID++}`
this.toolbarSelector = toolbarSelector
this.textSelector = textSelector
selectorValidator(this)
// 属性的默认值,后面可能会再修改
// 默认配置 - 当一个页面有多个编辑器的时候,因为 JS 的特性(引用类型)会导致多个编辑器的 config 引用是同一个,所以需要 深度克隆 断掉引用
this.config = deepClone(defaultConfig)
this.$toolbarElem = $('<div></div>')
this.$textContainerElem = $('<div></div>')
this.$textElem = $('<div></div>')
this.toolbarElemId = ''
this.textElemId = ''
this.isFocus = false
this.isComposing = false
this.isCompatibleMode = false
this.selection = new SelectionAndRangeAPI(this)
this.cmd = new CommandAPI(this)
this.txt = new Text(this)
this.menus = new Menus(this)
this.zIndex = new ZIndex()
this.change = new Change(this)
this.history = new History(this)
const { disable, enable } = disableInit(this)
this.disable = disable
this.enable = enable
this.isEnable = true
}
/**
* 初始化选区
* @param newLine 新建一行
*/
public initSelection(newLine?: boolean): void {
initSelection(this, newLine)
}
/**
* 创建编辑器实例
*/
public create(): void {
// 初始化 ZIndex
this.zIndex.init(this)
// 确定当前的历史记录模式
this.isCompatibleMode = this.config.compatibleMode()
// 标准模式下,重置延迟时间
if (!this.isCompatibleMode) {
this.config.onchangeTimeout = 30
}
// 国际化 因为要在创建菜单前使用 所以要最先 初始化
i18nextInit(this)
// 初始化 DOM
initDom(this)
// 初始化 text
this.txt.init()
// 初始化菜单
this.menus.init()
// 初始化全屏功能
initFullScreen(this)
// 初始化选区,将光标定位到内容尾部
this.initSelection(true)
// 绑定事件
bindEvent(this)
// 绑定监听的目标节点
this.change.observe()
this.history.observe()
// 初始化插件
initPlugins(this)
}
/**
* 提供给用户添加销毁前的钩子函数
* @param fn 钩子函数
*/
public beforeDestroy(fn: Function): Editor {
this.beforeDestroyHooks.push(fn)
return this
}
/**
* 销毁当前编辑器实例
*/
public destroy(): void {
// 调用钩子函数
this.beforeDestroyHooks.forEach(fn => fn.call(this))
// 销毁 DOM 节点
this.$toolbarElem.remove()
this.$textContainerElem.remove()
}
/**
* 将编辑器设置为全屏
*/
public fullScreen(): void {
setFullScreen(this)
}
/**
* 将编辑器退出全屏
*/
public unFullScreen(): void {
setUnFullScreen(this)
}
/**
* 滚动到指定标题锚点
* @param id 标题锚点id
*/
public scrollToHead(id: string): void {
scrollToHead(this, id)
}
/**
* 自定义添加菜单
* @param key 菜单 key
* @param Menu 菜单构造函数
*/
static registerMenu(key: string, Menu: any) {
if (!Menu || typeof Menu !== 'function') return
Editor.globalCustomMenuConstructorList[key] = Menu
}
/**
* 自定义添加插件
* @param { string } name 插件的名称
* @param { RegisterOptions } options 插件的选项
*/
public registerPlugin(name: string, options: RegisterOptions) {
registerPlugin(name, options, this.pluginsFunctionList)
}
/**
* 自定义添加插件
* @param { string } name 插件的名称
* @param { RegisterOptions } options 插件的选项
*/
static registerPlugin(name: string, options: RegisterOptions) {
registerPlugin(name, options, Editor.globalPluginsFunctionList)
}
}
export default Editor