leo-mind-map
Version:
一个简单的web在线思维导图
263 lines (242 loc) • 6.69 kB
JavaScript
import { keyMap } from './keyMap'
// 快捷按键、命令处理类
export default class KeyCommand {
// 构造函数
constructor(opt) {
this.opt = opt
this.mindMap = opt.mindMap
this.shortcutMap = {
//Enter: [fn]
}
this.shortcutMapCache = {}
this.isPause = false
this.pauseKeys = [
//"Del", "Backspace"
]
this.isInSvg = false
this.isStopCheckInSvg = false
this.defaultEnableCheck = this.defaultEnableCheck.bind(this)
this.bindEvent()
}
// 扩展按键映射
extendKeyMap(key, code) {
keyMap[key] = code
}
// 从按键映射中删除某个键
removeKeyMap(key) {
if (typeof keyMap[key] !== 'undefined') {
delete keyMap[key]
}
}
// 暂停快捷键响应
pause(keys) {
if (keys && keys.length > 0) {
// 把"Del|Backspace"或"Ctrl+c"转换成["Del","Backspace","Ctrl","c"]
const expandedKeys = keys.flatMap(k => k.split('|'))
this.pauseKeys.push(...keys)
} else {
this.isPause = true
}
}
// 恢复快捷键响应
recovery(keys) {
if (keys && keys.length > 0) {
this.pauseKeys = this.pauseKeys.filter(item => !keys.includes(item))
} else {
this.isPause = false
}
}
// 保存当前注册的快捷键数据,然后清空快捷键数据
save() {
// 当前已经存在缓存数据了,那么直接返回
if (Object.keys(this.shortcutMapCache).length > 0) {
return
}
this.shortcutMapCache = this.shortcutMap
this.shortcutMap = {}
}
// 恢复保存的快捷键数据,然后清空缓存数据
restore() {
// 当前不存在缓存数据,那么直接返回
if (Object.keys(this.shortcutMapCache).length <= 0) {
return
}
this.shortcutMap = this.shortcutMapCache
this.shortcutMapCache = {}
}
// 停止对鼠标是否在画布内的检查,前提是开启了enableShortcutOnlyWhenMouseInSvg选项
// 库内部节点文本编辑、关联线文本编辑、外框文本编辑前都会暂停检查,否则无法响应回车快捷键用于结束编辑
// 如果你新增了额外的文本编辑,也可以在编辑前调用此方法
stopCheckInSvg() {
const { enableShortcutOnlyWhenMouseInSvg } = this.mindMap.opt
if (!enableShortcutOnlyWhenMouseInSvg) return
this.isStopCheckInSvg = true
}
// 恢复对鼠标是否在画布内的检查
recoveryCheckInSvg() {
const { enableShortcutOnlyWhenMouseInSvg } = this.mindMap.opt
if (!enableShortcutOnlyWhenMouseInSvg) return
this.isStopCheckInSvg = true
}
// 绑定事件
bindEvent() {
this.onKeydown = this.onKeydown.bind(this)
// 只有当鼠标在画布内才响应快捷键
this.mindMap.on('svg_mouseenter', () => {
this.isInSvg = true
})
this.mindMap.on('svg_mouseleave', () => {
this.isInSvg = false
})
window.addEventListener('keydown', this.onKeydown)
this.mindMap.on('beforeDestroy', () => {
this.unBindEvent()
})
}
// 解绑事件
unBindEvent() {
window.removeEventListener('keydown', this.onKeydown)
}
// 根据事件目标判断是否响应快捷键事件
defaultEnableCheck(e) {
const target = e.target
if (target === document.body) return true
for (let i = 0; i < this.mindMap.editNodeClassList.length; i++) {
const cur = this.mindMap.editNodeClassList[i]
if (target.classList.contains(cur)) {
return true
}
}
return false
}
// 按键事件
onKeydown(e) {
const {
enableShortcutOnlyWhenMouseInSvg,
beforeShortcutRun,
customCheckEnableShortcut
} = this.mindMap.opt
const checkFn =
typeof customCheckEnableShortcut === 'function'
? customCheckEnableShortcut
: this.defaultEnableCheck
if (!checkFn(e)) return
if (
this.isPause ||
this.pauseKeys.includes(e.key) ||
(enableShortcutOnlyWhenMouseInSvg &&
!this.isStopCheckInSvg &&
!this.isInSvg)
) {
return
}
Object.keys(this.shortcutMap).forEach(key => {
if (this.checkKey(e, key)) {
// 粘贴事件不组织,因为要监听paste事件
if (!this.checkKey(e, 'Control+v')) {
e.stopPropagation()
e.preventDefault()
}
if (typeof beforeShortcutRun === 'function') {
const isStop = beforeShortcutRun(key, [
...this.mindMap.renderer.activeNodeList
])
if (isStop) return
}
this.shortcutMap[key].forEach(fn => {
fn()
})
}
})
}
// 检查键值是否符合
checkKey(e, key) {
let o = this.getOriginEventCodeArr(e)
let k = this.getKeyCodeArr(key)
if (o.length !== k.length) {
return false
}
for (let i = 0; i < o.length; i++) {
let index = k.findIndex(item => {
return item === o[i]
})
if (index === -1) {
return false
} else {
k.splice(index, 1)
}
}
return true
}
// 获取事件对象里的键值数组
getOriginEventCodeArr(e) {
let arr = []
if (e.ctrlKey || e.metaKey) {
arr.push(keyMap['Control'])
}
if (e.altKey) {
arr.push(keyMap['Alt'])
}
if (e.shiftKey) {
arr.push(keyMap['Shift'])
}
if (!arr.includes(e.keyCode)) {
arr.push(e.keyCode)
}
return arr
}
// 判断是否按下了组合键
hasCombinationKey(e) {
return e.ctrlKey || e.metaKey || e.altKey || e.shiftKey
}
// 获取快捷键对应的键值数组
getKeyCodeArr(key) {
let keyArr = key.split(/\s*\+\s*/)
let arr = []
keyArr.forEach(item => {
arr.push(keyMap[item])
})
return arr
}
// 添加快捷键命令
/**
* Enter
* Tab | Insert
* Shift + a
*/
addShortcut(key, fn) {
key.split(/\s*\|\s*/).forEach(item => {
if (this.shortcutMap[item]) {
this.shortcutMap[item].push(fn)
} else {
this.shortcutMap[item] = [fn]
}
})
}
// 移除快捷键命令
removeShortcut(key, fn) {
key.split(/\s*\|\s*/).forEach(item => {
if (this.shortcutMap[item]) {
if (fn) {
let index = this.shortcutMap[item].findIndex(f => {
return f === fn
})
if (index !== -1) {
this.shortcutMap[item].splice(index, 1)
}
} else {
this.shortcutMap[item] = []
delete this.shortcutMap[item]
}
}
})
}
// 获取指定快捷键的处理函数
getShortcutFn(key) {
let res = []
key.split(/\s*\|\s*/).forEach(item => {
res = this.shortcutMap[item] || []
})
return res
}
}