-
-
Notifications
You must be signed in to change notification settings - Fork 3.3k
/
index.ts
220 lines (185 loc) · 6.15 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
/**
* @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'
// 创建菜单的 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 = {}
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
// 实例销毁前需要执行的钩子集合
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
}
/**
* 初始化选区
* @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()
}
/**
* 提供给用户添加销毁前的钩子函数
* @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
}
}
export default Editor