feat:add register shortcut key method

pr675
Hufe921 3 years ago
parent 19bb68253c
commit adf64865bd

@ -183,35 +183,137 @@ export class CommandAdapt {
}
public sizeAdd() {
this.canvasEvent.sizeAdd()
const isReadonly = this.draw.isReadonly()
if (isReadonly) return
const selection = this.range.getSelection()
if (!selection) return
const lessThanMaxSizeIndex = selection.findIndex(s => !s.size || s.size + 2 <= 72)
const { defaultSize } = this.options
if (!~lessThanMaxSizeIndex) return
selection.forEach(el => {
if (!el.size) {
el.size = defaultSize
}
if (el.size + 2 > 72) return
el.size += 2
})
this.draw.render({ isSetCursor: false })
}
public sizeMinus() {
this.canvasEvent.sizeMinus()
const isReadonly = this.draw.isReadonly()
if (isReadonly) return
const selection = this.range.getSelection()
if (!selection) return
const greaterThanMaxSizeIndex = selection.findIndex(s => !s.size || s.size - 2 >= 8)
if (!~greaterThanMaxSizeIndex) return
const { defaultSize } = this.options
selection.forEach(el => {
if (!el.size) {
el.size = defaultSize
}
if (el.size - 2 < 8) return
el.size -= 2
})
this.draw.render({ isSetCursor: false })
}
public bold() {
this.canvasEvent.bold()
const isReadonly = this.draw.isReadonly()
if (isReadonly) return
const selection = this.range.getSelection()
if (!selection) return
const noBoldIndex = selection.findIndex(s => !s.bold)
selection.forEach(el => {
el.bold = !!~noBoldIndex
})
this.draw.render({ isSetCursor: false })
}
public italic() {
this.canvasEvent.italic()
const isReadonly = this.draw.isReadonly()
if (isReadonly) return
const selection = this.range.getSelection()
if (!selection) return
const noItalicIndex = selection.findIndex(s => !s.italic)
selection.forEach(el => {
el.italic = !!~noItalicIndex
})
this.draw.render({ isSetCursor: false })
}
public underline() {
this.canvasEvent.underline()
const isReadonly = this.draw.isReadonly()
if (isReadonly) return
const selection = this.range.getSelection()
if (!selection) return
const noUnderlineIndex = selection.findIndex(s => !s.underline)
selection.forEach(el => {
el.underline = !!~noUnderlineIndex
})
this.draw.render({ isSetCursor: false })
}
public strikeout() {
this.canvasEvent.strikeout()
const isReadonly = this.draw.isReadonly()
if (isReadonly) return
const selection = this.range.getSelection()
if (!selection) return
const noStrikeoutIndex = selection.findIndex(s => !s.strikeout)
selection.forEach(el => {
el.strikeout = !!~noStrikeoutIndex
})
this.draw.render({ isSetCursor: false })
}
public superscript() {
this.canvasEvent.superscript()
const isReadonly = this.draw.isReadonly()
if (isReadonly) return
const activeControl = this.control.getActiveControl()
if (activeControl) return
const selection = this.range.getSelection()
if (!selection) return
const superscriptIndex = selection.findIndex(s => s.type === ElementType.SUPERSCRIPT)
selection.forEach(el => {
// 取消上标
if (~superscriptIndex) {
if (el.type === ElementType.SUPERSCRIPT) {
el.type = ElementType.TEXT
delete el.actualSize
}
} else {
// 设置上标
if (!el.type || el.type === ElementType.TEXT || el.type === ElementType.SUBSCRIPT) {
el.type = ElementType.SUPERSCRIPT
}
}
})
this.draw.render({ isSetCursor: false })
}
public subscript() {
this.canvasEvent.subscript()
const isReadonly = this.draw.isReadonly()
if (isReadonly) return
const activeControl = this.control.getActiveControl()
if (activeControl) return
const selection = this.range.getSelection()
if (!selection) return
const subscriptIndex = selection.findIndex(s => s.type === ElementType.SUBSCRIPT)
selection.forEach(el => {
// 取消下标
if (~subscriptIndex) {
if (el.type === ElementType.SUBSCRIPT) {
el.type = ElementType.TEXT
delete el.actualSize
}
} else {
// 设置下标
if (!el.type || el.type === ElementType.TEXT || el.type === ElementType.SUPERSCRIPT) {
el.type = ElementType.SUBSCRIPT
}
}
})
this.draw.render({ isSetCursor: false })
}
public color(payload: string) {
@ -237,7 +339,29 @@ export class CommandAdapt {
}
public rowFlex(payload: RowFlex) {
this.canvasEvent.rowFlex(payload)
const isReadonly = this.draw.isReadonly()
if (isReadonly) return
const { startIndex, endIndex } = this.range.getRange()
if (!~startIndex && !~endIndex) return
const pageNo = this.draw.getPageNo()
const positionList = this.position.getPositionList()
// 开始/结束行号
const startRowNo = positionList[startIndex].rowNo
const endRowNo = positionList[endIndex].rowNo
const elementList = this.draw.getElementList()
// 当前选区所在行
for (let p = 0; p < positionList.length; p++) {
const position = positionList[p]
if (position.pageNo !== pageNo) continue
if (position.rowNo > endRowNo) break
if (position.rowNo >= startRowNo && position.rowNo <= endRowNo) {
elementList[p].rowFlex = payload
}
}
// 光标定位
const isSetCursor = startIndex === endIndex
const curIndex = isSetCursor ? endIndex : startIndex
this.draw.render({ curIndex, isSetCursor })
}
public rowMargin(payload: number) {

@ -1,4 +1,4 @@
import { ElementType, IEditorOption, RowFlex } from '../..'
import { ElementType, IEditorOption } from '../..'
import { ZERO } from '../../dataset/constant/Common'
import { EDITOR_ELEMENT_COPY_ATTR } from '../../dataset/constant/Element'
import { ElementStyleKey } from '../../dataset/enum/ElementStyle'
@ -454,13 +454,8 @@ export class CanvasEvent {
} else if (evt.ctrlKey && evt.key === KeyMap.C) {
this.copy()
evt.preventDefault()
} else if (evt.ctrlKey && evt.key.toLocaleLowerCase() === KeyMap.X) {
if (isReadonly) return
if (evt.shiftKey) {
this.strikeout()
} else {
this.cut()
}
} else if (evt.ctrlKey && evt.key === KeyMap.X) {
this.cut()
evt.preventDefault()
} else if (evt.ctrlKey && evt.key === KeyMap.A) {
this.selectAll()
@ -471,39 +466,6 @@ export class CanvasEvent {
this.listener.saved(this.draw.getValue())
}
evt.preventDefault()
} else if (evt.ctrlKey && evt.key === KeyMap.LEFT_BRACKET) {
this.sizeAdd()
evt.preventDefault()
} else if (evt.ctrlKey && evt.key === KeyMap.RIGHT_BRACKET) {
this.sizeMinus()
evt.preventDefault()
} else if (evt.ctrlKey && evt.key === KeyMap.B) {
this.bold()
evt.preventDefault()
} else if (evt.ctrlKey && evt.key === KeyMap.I) {
this.italic()
evt.preventDefault()
} else if (evt.ctrlKey && evt.key === KeyMap.U) {
this.underline()
evt.preventDefault()
} else if (evt.ctrlKey && evt.shiftKey && evt.key === KeyMap.RIGHT_ANGLE_BRACKET) {
this.superscript()
evt.preventDefault()
} else if (evt.ctrlKey && evt.shiftKey && evt.key === KeyMap.LEFT_ANGLE_BRACKET) {
this.subscript()
evt.preventDefault()
} else if (evt.ctrlKey && evt.key === KeyMap.L) {
this.rowFlex(RowFlex.LEFT)
evt.preventDefault()
} else if (evt.ctrlKey && evt.key === KeyMap.E) {
this.rowFlex(RowFlex.CENTER)
evt.preventDefault()
} else if (evt.ctrlKey && evt.key === KeyMap.R) {
this.rowFlex(RowFlex.RIGHT)
evt.preventDefault()
} else if (evt.ctrlKey && evt.key === KeyMap.J) {
this.rowFlex(RowFlex.ALIGNMENT)
evt.preventDefault()
} else if (evt.key === KeyMap.ESC) {
this.clearPainterStyle()
evt.preventDefault()
@ -711,166 +673,6 @@ export class CanvasEvent {
})
}
public sizeAdd() {
const isReadonly = this.draw.isReadonly()
if (isReadonly) return
const selection = this.range.getSelection()
if (!selection) return
const lessThanMaxSizeIndex = selection.findIndex(s => !s.size || s.size + 2 <= 72)
const { defaultSize } = this.options
if (!~lessThanMaxSizeIndex) return
selection.forEach(el => {
if (!el.size) {
el.size = defaultSize
}
if (el.size + 2 > 72) return
el.size += 2
})
this.draw.render({ isSetCursor: false })
}
public sizeMinus() {
const isReadonly = this.draw.isReadonly()
if (isReadonly) return
const selection = this.range.getSelection()
if (!selection) return
const greaterThanMaxSizeIndex = selection.findIndex(s => !s.size || s.size - 2 >= 8)
if (!~greaterThanMaxSizeIndex) return
const { defaultSize } = this.options
selection.forEach(el => {
if (!el.size) {
el.size = defaultSize
}
if (el.size - 2 < 8) return
el.size -= 2
})
this.draw.render({ isSetCursor: false })
}
public bold() {
const isReadonly = this.draw.isReadonly()
if (isReadonly) return
const selection = this.range.getSelection()
if (!selection) return
const noBoldIndex = selection.findIndex(s => !s.bold)
selection.forEach(el => {
el.bold = !!~noBoldIndex
})
this.draw.render({ isSetCursor: false })
}
public italic() {
const isReadonly = this.draw.isReadonly()
if (isReadonly) return
const selection = this.range.getSelection()
if (!selection) return
const noItalicIndex = selection.findIndex(s => !s.italic)
selection.forEach(el => {
el.italic = !!~noItalicIndex
})
this.draw.render({ isSetCursor: false })
}
public underline() {
const isReadonly = this.draw.isReadonly()
if (isReadonly) return
const selection = this.range.getSelection()
if (!selection) return
const noUnderlineIndex = selection.findIndex(s => !s.underline)
selection.forEach(el => {
el.underline = !!~noUnderlineIndex
})
this.draw.render({ isSetCursor: false })
}
public strikeout() {
const isReadonly = this.draw.isReadonly()
if (isReadonly) return
const selection = this.range.getSelection()
if (!selection) return
const noStrikeoutIndex = selection.findIndex(s => !s.strikeout)
selection.forEach(el => {
el.strikeout = !!~noStrikeoutIndex
})
this.draw.render({ isSetCursor: false })
}
public superscript() {
const isReadonly = this.draw.isReadonly()
if (isReadonly) return
const activeControl = this.control.getActiveControl()
if (activeControl) return
const selection = this.range.getSelection()
if (!selection) return
const superscriptIndex = selection.findIndex(s => s.type === ElementType.SUPERSCRIPT)
selection.forEach(el => {
// 取消上标
if (~superscriptIndex) {
if (el.type === ElementType.SUPERSCRIPT) {
el.type = ElementType.TEXT
delete el.actualSize
}
} else {
// 设置上标
if (!el.type || el.type === ElementType.TEXT || el.type === ElementType.SUBSCRIPT) {
el.type = ElementType.SUPERSCRIPT
}
}
})
this.draw.render({ isSetCursor: false })
}
public subscript() {
const isReadonly = this.draw.isReadonly()
if (isReadonly) return
const activeControl = this.control.getActiveControl()
if (activeControl) return
const selection = this.range.getSelection()
if (!selection) return
const subscriptIndex = selection.findIndex(s => s.type === ElementType.SUBSCRIPT)
selection.forEach(el => {
// 取消下标
if (~subscriptIndex) {
if (el.type === ElementType.SUBSCRIPT) {
el.type = ElementType.TEXT
delete el.actualSize
}
} else {
// 设置下标
if (!el.type || el.type === ElementType.TEXT || el.type === ElementType.SUPERSCRIPT) {
el.type = ElementType.SUBSCRIPT
}
}
})
this.draw.render({ isSetCursor: false })
}
public rowFlex(payload: RowFlex) {
const isReadonly = this.draw.isReadonly()
if (isReadonly) return
const { startIndex, endIndex } = this.range.getRange()
if (!~startIndex && !~endIndex) return
const pageNo = this.draw.getPageNo()
const positionList = this.position.getPositionList()
// 开始/结束行号
const startRowNo = positionList[startIndex].rowNo
const endRowNo = positionList[endIndex].rowNo
const elementList = this.draw.getElementList()
// 当前选区所在行
for (let p = 0; p < positionList.length; p++) {
const position = positionList[p]
if (position.pageNo !== pageNo) continue
if (position.rowNo > endRowNo) break
if (position.rowNo >= startRowNo && position.rowNo <= endRowNo) {
elementList[p].rowFlex = payload
}
}
// 光标定位
const isSetCursor = startIndex === endIndex
const curIndex = isSetCursor ? endIndex : startIndex
this.draw.render({ curIndex, isSetCursor })
}
public compositionstart() {
this.isCompositing = true
}

@ -1,17 +1,22 @@
import { IRegisterContextMenu } from '../../interface/contextmenu/ContextMenu'
import { IRegisterShortcut } from '../../interface/shortcut/Shortcut'
import { ContextMenu } from '../contextmenu/ContextMenu'
import { Shortcut } from '../shortcut/Shortcut'
interface IRegisterPayload {
contextMenu: ContextMenu
contextMenu: ContextMenu;
shortcut: Shortcut;
}
export class Register {
public contextMenuList: (payload: IRegisterContextMenu[]) => void
public shortcutList: (payload: IRegisterShortcut[]) => void
constructor(payload: IRegisterPayload) {
const { contextMenu } = payload
const { contextMenu, shortcut } = payload
this.contextMenuList = contextMenu.registerContextMenuList.bind(contextMenu)
this.shortcutList = shortcut.registerShortcutList.bind(shortcut)
}
}

@ -0,0 +1,68 @@
import { richtextKeys } from '../../interface/shortcut/keys/richtextKeys'
import { IRegisterShortcut } from '../../interface/shortcut/Shortcut'
import { Command } from '../command/Command'
import { Draw } from '../draw/Draw'
export class Shortcut {
private command: Command
private globalShortcutList: IRegisterShortcut[]
private agentShortcutList: IRegisterShortcut[]
constructor(draw: Draw, command: Command) {
this.command = command
this.globalShortcutList = []
this.agentShortcutList = []
// 内部快捷键
this._addShortcutList([
...richtextKeys
])
// 全局快捷键
document.addEventListener('keydown', this._globalKeydown.bind(this))
// 编辑器快捷键
const agentDom = draw.getCursor().getAgentDom()
agentDom.addEventListener('keydown', this._agentKeydown.bind(this))
}
private _addShortcutList(payload: IRegisterShortcut[]) {
for (let s = 0; s < payload.length; s++) {
const shortCut = payload[s]
if (shortCut.isGlobal) {
this.globalShortcutList.push(shortCut)
} else {
this.agentShortcutList.push(shortCut)
}
}
}
public registerShortcutList(payload: IRegisterShortcut[]) {
this._addShortcutList(payload)
}
private _globalKeydown(evt: KeyboardEvent) {
if (!this.globalShortcutList.length) return
this._execute(evt, this.globalShortcutList)
}
private _agentKeydown(evt: KeyboardEvent) {
if (!this.agentShortcutList.length) return
this._execute(evt, this.agentShortcutList)
}
private _execute(evt: KeyboardEvent, shortCutList: IRegisterShortcut[]) {
for (let s = 0; s < shortCutList.length; s++) {
const shortCut = shortCutList[s]
if (
evt.ctrlKey === !!shortCut.ctrl &&
evt.shiftKey === !!shortCut.shift &&
evt.altKey === !!shortCut.alt &&
evt.key === shortCut.key
) {
shortCut.callback(this.command)
evt.preventDefault()
break
}
}
}
}

@ -17,16 +17,53 @@ export enum KeyMap {
A = 'a',
B = 'b',
C = 'c',
D = 'd',
E = 'e',
F = 'f',
G = 'g',
H = 'h',
I = 'i',
J = 'j',
K = 'k',
L = 'l',
M = 'm',
N = 'n',
O = 'o',
P = 'p',
Q = 'q',
R = 'r',
S = 's',
T = 't',
U = 'u',
V = 'v',
W = 'w',
X = 'x',
Y = 'y',
Z = 'z'
Z = 'z',
A_UPPERCASE = 'A',
B_UPPERCASE = 'B',
C_UPPERCASE = 'C',
D_UPPERCASE = 'D',
E_UPPERCASE = 'E',
F_UPPERCASE = 'F',
G_UPPERCASE = 'G',
H_UPPERCASE = 'H',
I_UPPERCASE = 'I',
J_UPPERCASE = 'J',
K_UPPERCASE = 'K',
L_UPPERCASE = 'L',
M_UPPERCASE = 'M',
N_UPPERCASE = 'N',
O_UPPERCASE = 'O',
P_UPPERCASE = 'P',
Q_UPPERCASE = 'Q',
R_UPPERCASE = 'R',
S_UPPERCASE = 'S',
T_UPPERCASE = 'T',
U_UPPERCASE = 'U',
V_UPPERCASE = 'V',
W_UPPERCASE = 'W',
X_UPPERCASE = 'X',
Y_UPPERCASE = 'Y',
Z_UPPERCASE = 'Z',
}

@ -24,6 +24,8 @@ import { ICheckboxOption } from './interface/Checkbox'
import { defaultCheckboxOption } from './dataset/constant/Checkbox'
import { DeepRequired } from './interface/Common'
import { INavigateInfo } from './core/draw/interactive/Search'
import { Shortcut } from './core/shortcut/Shortcut'
import { KeyMap } from './dataset/enum/KeyMap'
export default class Editor {
@ -100,9 +102,12 @@ export default class Editor {
this.command = new Command(new CommandAdapt(draw))
// 菜单
const contextMenu = new ContextMenu(draw, this.command)
// 快捷键
const shortcut = new Shortcut(draw, this.command)
// 注册
this.register = new Register({
contextMenu
contextMenu,
shortcut
})
}
@ -119,7 +124,8 @@ export {
EDITOR_COMPONENT,
PageMode,
ImageDisplay,
Command
Command,
KeyMap
}
// 对外类型

@ -0,0 +1,11 @@
import { Command } from '../../core/command/Command'
import { KeyMap } from '../../dataset/enum/KeyMap'
export interface IRegisterShortcut {
key: KeyMap;
ctrl?: boolean;
shift?: boolean;
alt?: boolean;
isGlobal?: boolean;
callback: (command: Command) => any;
}

@ -0,0 +1,93 @@
import { Command } from '../../..'
import { KeyMap } from '../../../dataset/enum/KeyMap'
import { IRegisterShortcut } from '../Shortcut'
export const richtextKeys: IRegisterShortcut[] = [
{
key: KeyMap.X_UPPERCASE,
ctrl: true,
shift: true,
callback: (command: Command) => {
command.executeStrikeout()
}
},
{
key: KeyMap.LEFT_BRACKET,
ctrl: true,
callback: (command: Command) => {
command.executeSizeAdd()
}
},
{
key: KeyMap.RIGHT_BRACKET,
ctrl: true,
callback: (command: Command) => {
command.executeSizeMinus()
}
},
{
key: KeyMap.B,
ctrl: true,
callback: (command: Command) => {
command.executeBold()
}
},
{
key: KeyMap.I,
ctrl: true,
callback: (command: Command) => {
command.executeItalic()
}
},
{
key: KeyMap.U,
ctrl: true,
callback: (command: Command) => {
command.executeUnderline()
}
},
{
key: KeyMap.RIGHT_ANGLE_BRACKET,
ctrl: true,
shift: true,
callback: (command: Command) => {
command.executeSuperscript()
}
},
{
key: KeyMap.LEFT_ANGLE_BRACKET,
ctrl: true,
shift: true,
callback: (command: Command) => {
command.executeSubscript()
}
},
{
key: KeyMap.L,
ctrl: true,
callback: (command: Command) => {
command.executeLeft()
}
},
{
key: KeyMap.E,
ctrl: true,
callback: (command: Command) => {
command.executeCenter()
}
},
{
key: KeyMap.R,
ctrl: true,
callback: (command: Command) => {
command.executeRight()
}
},
{
key: KeyMap.J,
ctrl: true,
callback: (command: Command) => {
command.executeAlignment()
}
}
]

@ -1,7 +1,7 @@
import { data, options } from './mock'
import './style.css'
import prism from 'prismjs'
import Editor, { Command, ControlType, EditorMode, ElementType, IElement, PageMode } from './editor'
import Editor, { Command, ControlType, EditorMode, ElementType, IElement, KeyMap, PageMode } from './editor'
import { Dialog } from './components/dialog/Dialog'
import { formatPrismToken } from './utils/prism'
import { Signature } from './components/signature/Signature'
@ -972,4 +972,24 @@ window.onload = function () {
}
])
// 10. 快捷键注册
instance.register.shortcutList([
{
key: KeyMap.P,
ctrl: true,
isGlobal: true,
callback: (command: Command) => {
command.executePrint()
}
},
{
key: KeyMap.F,
ctrl: true,
isGlobal: true,
callback: () => {
searchDom.click()
}
}
])
}
Loading…
Cancel
Save