all files / lib/features/keyboard/ Keyboard.js

100% Statements 50/50
94.12% Branches 16/17
100% Functions 12/12
100% Lines 50/50
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164                                                                                        103×   103× 103×   103×     103× 103×   103×     103× 103×     103×       103×                 90×     90×     89×       89×   89× 69×                           110×   110×         110×     214×                     227× 200× 200×     227×                 90×    
import {
  isFunction
} from 'min-dash';
 
import {
  event as domEvent,
  matches as domMatches
} from 'min-dom';
 
import {
  hasModifier,
  isCmd,
  isKey,
  isShift
} from './KeyboardUtil';
 
var KEYDOWN_EVENT = 'keyboard.keydown';
 
var DEFAULT_PRIORITY = 1000;
 
 
/**
 * A keyboard abstraction that may be activated and
 * deactivated by users at will, consuming 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._keyHandler = this._keyHandler.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() {
    Eif (config && config.bindTo) {
      self.bind(config.bindTo);
    }
  });
 
  eventBus.on('detach', function() {
    self.unbind();
  });
}
 
Keyboard.$inject = [
  'config.keyboard',
  'eventBus'
];
 
Keyboard.prototype._keyHandler = function(event) {
 
  var target = event.target,
      eventBusResult;
 
  if (isInput(target)) {
    return;
  }
 
  var context = {
    keyEvent: event
  };
 
  eventBusResult = this._eventBus.fire(KEYDOWN_EVENT, context);
 
  if (eventBusResult) {
    event.preventDefault();
  }
};
 
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._keyHandler, true);
 
  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._keyHandler, true);
  }
 
  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
 */
Keyboard.prototype.addListener = function(priority, listener) {
  if (isFunction(priority)) {
    listener = priority;
    priority = DEFAULT_PRIORITY;
  }
 
  this._eventBus.on(KEYDOWN_EVENT, priority, 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');
}