Keyboard.js 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. import {
  2. isFunction
  3. } from 'min-dash';
  4. import {
  5. event as domEvent,
  6. matches as domMatches
  7. } from 'min-dom';
  8. import {
  9. hasModifier,
  10. isCmd,
  11. isKey,
  12. isShift
  13. } from './KeyboardUtil';
  14. var KEYDOWN_EVENT = 'keyboard.keydown';
  15. var DEFAULT_PRIORITY = 1000;
  16. /**
  17. * A keyboard abstraction that may be activated and
  18. * deactivated by users at will, consuming key events
  19. * and triggering diagram actions.
  20. *
  21. * For keys pressed down, keyboard fires `keyboard.keydown` event.
  22. * The event context contains one field which is `KeyboardEvent` event.
  23. *
  24. * The implementation fires the following key events that allow
  25. * other components to hook into key handling:
  26. *
  27. * - keyboard.bind
  28. * - keyboard.unbind
  29. * - keyboard.init
  30. * - keyboard.destroy
  31. *
  32. * All events contain one field which is node.
  33. *
  34. * A default binding for the keyboard may be specified via the
  35. * `keyboard.bindTo` configuration option.
  36. *
  37. * @param {Config} config
  38. * @param {EventBus} eventBus
  39. */
  40. export default function Keyboard(config, eventBus) {
  41. var self = this;
  42. this._config = config || {};
  43. this._eventBus = eventBus;
  44. this._keyHandler = this._keyHandler.bind(this);
  45. // properly clean dom registrations
  46. eventBus.on('diagram.destroy', function() {
  47. self._fire('destroy');
  48. self.unbind();
  49. });
  50. eventBus.on('diagram.init', function() {
  51. self._fire('init');
  52. });
  53. eventBus.on('attach', function() {
  54. if (config && config.bindTo) {
  55. self.bind(config.bindTo);
  56. }
  57. });
  58. eventBus.on('detach', function() {
  59. self.unbind();
  60. });
  61. }
  62. Keyboard.$inject = [
  63. 'config.keyboard',
  64. 'eventBus'
  65. ];
  66. Keyboard.prototype._keyHandler = function(event) {
  67. var target = event.target,
  68. eventBusResult;
  69. if (isInput(target)) {
  70. return;
  71. }
  72. var context = {
  73. keyEvent: event
  74. };
  75. eventBusResult = this._eventBus.fire(KEYDOWN_EVENT, context);
  76. if (eventBusResult) {
  77. event.preventDefault();
  78. }
  79. };
  80. Keyboard.prototype.bind = function(node) {
  81. // make sure that the keyboard is only bound once to the DOM
  82. this.unbind();
  83. this._node = node;
  84. // bind key events
  85. domEvent.bind(node, 'keydown', this._keyHandler, true);
  86. this._fire('bind');
  87. };
  88. Keyboard.prototype.getBinding = function() {
  89. return this._node;
  90. };
  91. Keyboard.prototype.unbind = function() {
  92. var node = this._node;
  93. if (node) {
  94. this._fire('unbind');
  95. // unbind key events
  96. domEvent.unbind(node, 'keydown', this._keyHandler, true);
  97. }
  98. this._node = null;
  99. };
  100. Keyboard.prototype._fire = function(event) {
  101. this._eventBus.fire('keyboard.' + event, { node: this._node });
  102. };
  103. /**
  104. * Add a listener function that is notified with `KeyboardEvent` whenever
  105. * the keyboard is bound and the user presses a key. If no priority is
  106. * provided, the default value of 1000 is used.
  107. *
  108. * @param {Number} priority
  109. * @param {Function} listener
  110. */
  111. Keyboard.prototype.addListener = function(priority, listener) {
  112. if (isFunction(priority)) {
  113. listener = priority;
  114. priority = DEFAULT_PRIORITY;
  115. }
  116. this._eventBus.on(KEYDOWN_EVENT, priority, listener);
  117. };
  118. Keyboard.prototype.hasModifier = hasModifier;
  119. Keyboard.prototype.isCmd = isCmd;
  120. Keyboard.prototype.isShift = isShift;
  121. Keyboard.prototype.isKey = isKey;
  122. // helpers ///////
  123. function isInput(target) {
  124. return target && (domMatches(target, 'input, textarea') || target.contentEditable === 'true');
  125. }