diff --git a/src/editor/index.js b/src/editor/index.js index b7c8dc865..c366abab0 100644 --- a/src/editor/index.js +++ b/src/editor/index.js @@ -172,6 +172,12 @@ module.exports = config => { */ Commands: em.get('Commands'), + /** + * @property {Keymaps} + * @private + */ + Keymaps: em.get('Keymaps'), + /** * @property {Modal} * @private diff --git a/src/editor/model/Editor.js b/src/editor/model/Editor.js index 7ed65e548..4ba4bf7d7 100644 --- a/src/editor/model/Editor.js +++ b/src/editor/model/Editor.js @@ -2,6 +2,7 @@ import { isUndefined, defaults } from 'underscore'; const deps = [ require('utils'), + require('keymaps'), require('storage_manager'), require('device_manager'), require('parser'), @@ -180,6 +181,12 @@ module.exports = Backbone.Model.extend({ this.set('Editor', editor); }, + + getEditor() { + return this.get('Editor'); + }, + + /** * Listen for new rules * @param {Object} collection diff --git a/src/keymaps/index.js b/src/keymaps/index.js new file mode 100644 index 000000000..79f4a8431 --- /dev/null +++ b/src/keymaps/index.js @@ -0,0 +1,116 @@ +import { defaults, isString } from 'underscore'; + +const keymaster = require('keymaster').noConflict(); + +module.exports = () => { + let config; + const configDef = {}; + const keymaps = {}; + + return { + + keymaster, + + + name: 'Keymaps', + + + /** + * Get module configurations + * @return {Object} Configuration object + */ + getConfig() { + return config; + }, + + + /** + * Initialize module + * @param {Object} config Configurations + * @private + */ + init(opts = {}) { + config = opts; + defaults(config, configDef); + this.em = config.em; + return this; + }, + + /** + * Add new keymap + * @param {string} id Keymap id + * @param {string} keys Keymap keys, eg. '⌘+z, ctrl+z' + * @param {Function|string} handler Keymap handler, might be a function + * or just a command id as a string + * @example + * keymaps.add('ns:my-keymap', '⌘+s, ctrl+s', () => { + * console.log('do stuff'); + * }); + * // or + * keymaps.add('ns:my-keymap', '⌘+s, ctrl+s', 'some-gjs-command'); + */ + add(id, keys, handler) { + const em = this.em; + const cmd = em.get('Commands'); + const editor = em.getEditor(); + const keymap = { id, keys, handler }; + const pk = keymaps[id]; + pk && this.remove(id); + keymaps[id] = keymap; + keymaster(keys, (e, h) => { + // It's safer putting handlers resolution inside the callback + handler = isString(handler) ? cmd.get(handler) : handler; + typeof handler == 'object' ? handler.run(editor) : handler(editor); + const args = [id, h.shortcut, e]; + em.trigger('keymap:emit', ...args); + em.trigger(`keymap:emit:${id}`, ...args); + }); + em.trigger('keymap:add', 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) { + return keymaps[id]; + }, + + + /** + * Get all keymaps + * @return {Object} + */ + getAll() { + return 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) { + const em = this.em; + const keymap = this.get(id); + + if (keymap) { + delete keymaps[id]; + keymaster.unbind(keymap.keys); + em && em.trigger('keymap:remove', keymap); + return keymap; + } + }, + + + }; +};