| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208 |
- import {
- isFunction
- } from 'min-dash';
- import {
- closest as domClosest,
- event as domEvent,
- matches as domMatches
- } from 'min-dom';
- import {
- hasModifier,
- isCmd,
- isKey,
- isShift
- } from './KeyboardUtil';
- var KEYDOWN_EVENT = 'keyboard.keydown',
- KEYUP_EVENT = 'keyboard.keyup';
- var HANDLE_MODIFIER_ATTRIBUTE = 'input-handle-modified-keys';
- var DEFAULT_PRIORITY = 1000;
- /**
- * A keyboard abstraction that may be activated and
- * deactivated by users at will, consuming global key events
- * and triggering diagram actions.
- *
- * For keys pressed down, keyboard fires `keyboard.keydown` event.
- * The event context contains one field which is `KeyboardEvent` event.
- *
- * The implementation fires the following key events that allow
- * other components to hook into key handling:
- *
- * - keyboard.bind
- * - keyboard.unbind
- * - keyboard.init
- * - keyboard.destroy
- *
- * All events contain one field which is node.
- *
- * A default binding for the keyboard may be specified via the
- * `keyboard.bindTo` configuration option.
- *
- * @param {Config} config
- * @param {EventBus} eventBus
- */
- export default function Keyboard(config, eventBus) {
- var self = this;
- this._config = config || {};
- this._eventBus = eventBus;
- this._keydownHandler = this._keydownHandler.bind(this);
- this._keyupHandler = this._keyupHandler.bind(this);
- // properly clean dom registrations
- eventBus.on('diagram.destroy', function() {
- self._fire('destroy');
- self.unbind();
- });
- eventBus.on('diagram.init', function() {
- self._fire('init');
- });
- eventBus.on('attach', function() {
- if (config && config.bindTo) {
- self.bind(config.bindTo);
- }
- });
- eventBus.on('detach', function() {
- self.unbind();
- });
- }
- Keyboard.$inject = [
- 'config.keyboard',
- 'eventBus'
- ];
- Keyboard.prototype._keydownHandler = function(event) {
- this._keyHandler(event, KEYDOWN_EVENT);
- };
- Keyboard.prototype._keyupHandler = function(event) {
- this._keyHandler(event, KEYUP_EVENT);
- };
- Keyboard.prototype._keyHandler = function(event, type) {
- var eventBusResult;
- if (this._isEventIgnored(event)) {
- return;
- }
- var context = {
- keyEvent: event
- };
- eventBusResult = this._eventBus.fire(type || KEYDOWN_EVENT, context);
- if (eventBusResult) {
- event.preventDefault();
- }
- };
- Keyboard.prototype._isEventIgnored = function(event) {
- if (event.defaultPrevented) {
- return true;
- }
- return isInput(event.target) && this._isModifiedKeyIgnored(event);
- };
- Keyboard.prototype._isModifiedKeyIgnored = function(event) {
- if (!isCmd(event)) {
- return true;
- }
- var allowedModifiers = this._getAllowedModifiers(event.target);
- return allowedModifiers.indexOf(event.key) === -1;
- };
- Keyboard.prototype._getAllowedModifiers = function(element) {
- var modifierContainer = domClosest(element, '[' + HANDLE_MODIFIER_ATTRIBUTE + ']', true);
- if (!modifierContainer || (this._node && !this._node.contains(modifierContainer))) {
- return [];
- }
- return modifierContainer.getAttribute(HANDLE_MODIFIER_ATTRIBUTE).split(',');
- };
- Keyboard.prototype.bind = function(node) {
- // make sure that the keyboard is only bound once to the DOM
- this.unbind();
- this._node = node;
- // bind key events
- domEvent.bind(node, 'keydown', this._keydownHandler);
- domEvent.bind(node, 'keyup', this._keyupHandler);
- this._fire('bind');
- };
- Keyboard.prototype.getBinding = function() {
- return this._node;
- };
- Keyboard.prototype.unbind = function() {
- var node = this._node;
- if (node) {
- this._fire('unbind');
- // unbind key events
- domEvent.unbind(node, 'keydown', this._keydownHandler);
- domEvent.unbind(node, 'keyup', this._keyupHandler);
- }
- this._node = null;
- };
- Keyboard.prototype._fire = function(event) {
- this._eventBus.fire('keyboard.' + event, { node: this._node });
- };
- /**
- * Add a listener function that is notified with `KeyboardEvent` whenever
- * the keyboard is bound and the user presses a key. If no priority is
- * provided, the default value of 1000 is used.
- *
- * @param {number} [priority]
- * @param {Function} listener
- * @param {string} type
- */
- Keyboard.prototype.addListener = function(priority, listener, type) {
- if (isFunction(priority)) {
- type = listener;
- listener = priority;
- priority = DEFAULT_PRIORITY;
- }
- this._eventBus.on(type || KEYDOWN_EVENT, priority, listener);
- };
- Keyboard.prototype.removeListener = function(listener, type) {
- this._eventBus.off(type || KEYDOWN_EVENT, listener);
- };
- Keyboard.prototype.hasModifier = hasModifier;
- Keyboard.prototype.isCmd = isCmd;
- Keyboard.prototype.isShift = isShift;
- Keyboard.prototype.isKey = isKey;
- // helpers ///////
- function isInput(target) {
- return target && (domMatches(target, 'input, textarea') || target.contentEditable === 'true');
- }
|