UNPKG

@print-one/grapesjs

Version:

Free and Open Source Web Builder Framework

198 lines (182 loc) 5.43 kB
/** * You can customize the initial state of the module from the editor initialization * ```js * const editor = grapesjs.init({ * keymaps: { * // Object of keymaps * defaults: { * 'your-namespace:keymap-name' { * keys: '⌘+z, ctrl+z', * handler: 'some-command-id' * }, * ... * } * } * }) * ``` * * Once the editor is instantiated you can use its API and listen to its events. Before using these methods, you should get the module from the instance. * * ```js * // Listen to events * editor.on('keymap:add', () => { ... }); * * // Use the API * const keymaps = editor.Keymaps; * keymaps.add(...); * ``` * * ## Available Events * * `keymap:add` - New keymap added. The new keyamp object is passed as an argument * * `keymap:remove` - Keymap removed. The removed keyamp object is passed as an argument * * `keymap:emit` - Some keymap emitted, in arguments you get keymapId, shortcutUsed, Event * * `keymap:emit:{keymapId}` - `keymapId` emitted, in arguments you get keymapId, shortcutUsed, Event * * ## Methods * * [getConfig](#getconfig) * * [add](#add) * * [get](#get) * * [getAll](#getAll) * * [remove](#remove) * * [removeAll](#removeall) * * @module Keymaps */ import { isFunction, isString } from 'underscore'; import { hasWin } from '../utils/mixins'; import keymaster from '../utils/keymaster'; import { Module } from '../abstract'; import EditorModel from '../editor/model/Editor'; import defaults, { Keymap, KeymapOptions, KeymapsConfig } from './config'; export type KeymapEvent = 'keymap:add' | 'keymap:remove' | 'keymap:emit' | `keymap:emit:${string}`; hasWin() && keymaster.init(window); export default class KeymapsModule extends Module<KeymapsConfig & { name?: string }> { keymaster: any = keymaster; keymaps: Record<string, Keymap>; constructor(em: EditorModel) { super(em, 'Keymaps', defaults); this.keymaps = {}; } onLoad() { const defKeys = this.config.defaults; for (let id in defKeys) { const value = defKeys[id]; this.add(id, value.keys, value.handler, value.opts || {}); } } /** * Get configuration object * @name getConfig * @function * @return {Object} */ /** * Add new keymap * @param {string} id Keymap id * @param {string} keys Keymap keys, eg. `ctrl+a`, `⌘+z, ctrl+z` * @param {Function|string} handler Keymap handler, might be a function * @param {Object} [opts={}] Options * @param {Boolean} [opts.force=false] Force the handler to be executed. * @param {Boolean} [opts.prevent=false] Prevent default of the original triggered event. * @returns {Object} Added keymap * @example * // 'ns' is just a custom namespace * keymaps.add('ns:my-keymap', '⌘+j, ⌘+u, ctrl+j, alt+u', editor => { * console.log('do stuff'); * }); * // or * keymaps.add('ns:my-keymap', '⌘+s, ctrl+s', 'some-gjs-command', { * // Prevent the default browser action * prevent: true, * }); * * // listen to events * editor.on('keymap:emit', (id, shortcut, event) => { * // ... * }) */ add(id: Keymap['id'], keys: Keymap['keys'], handler: Keymap['handler'], opts: KeymapOptions = {}) { const { em } = this; const cmd = em.Commands; const editor = em.getEditor(); const canvas = em.Canvas; const keymap: Keymap = { id, keys, handler }; const pk = this.keymaps[id]; pk && this.remove(id); this.keymaps[id] = keymap; keymaster( keys, (e: any, h: any) => { // It's safer putting handlers resolution inside the callback const opt = { event: e, h }; const handlerRes = isString(handler) ? cmd.get(handler) : handler; const ableTorun = !em.isEditing() && !editor.Canvas.isInputFocused(); if (ableTorun || opts.force) { opts.prevent && canvas.getCanvasView().preventDefault(e); isFunction(handlerRes) ? handlerRes(editor, 0, opt) : cmd.runCommand(handlerRes, opt); const args = [id, h.shortcut, e]; em.trigger('keymap:emit', ...args); em.trigger(`keymap:emit:${id}`, ...args); } }, undefined ); em.trigger('keymap:add', keymap); return keymap; } /** * Get the keymap by id * @param {string} id Keymap id * @return {Object} Keymap object * @example * keymaps.get('ns:my-keymap'); * // -> {keys, handler}; */ get(id: string) { return this.keymaps[id]; } /** * Get all keymaps * @return {Object} * @example * keymaps.getAll(); * // -> {id1: {}, id2: {}}; */ getAll() { return this.keymaps; } /** * Remove the keymap by id * @param {string} id Keymap id * @return {Object} Removed keymap * @example * keymaps.remove('ns:my-keymap'); * // -> {keys, handler}; */ remove(id: string) { const { em } = this; const keymap = this.get(id); if (keymap) { delete this.keymaps[id]; keymap.keys.split(', ').forEach(k => { // @ts-ignore keymaster.unbind(k.trim()); }); em?.trigger('keymap:remove', keymap); return keymap; } } /** * Remove all binded keymaps * @return {this} */ removeAll() { Object.keys(this.keymaps).forEach(keymap => this.remove(keymap)); keymaster.handlers = {}; return this; } destroy() { this.removeAll(); this.keymaps = {}; } }