Skip to content

Commit

Permalink
feat(hand-tool): activate on space
Browse files Browse the repository at this point in the history
  • Loading branch information
philippfromme committed Jun 7, 2019
1 parent 9668e84 commit 81210fb
Show file tree
Hide file tree
Showing 5 changed files with 148 additions and 13 deletions.
38 changes: 37 additions & 1 deletion lib/features/hand-tool/HandTool.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
import { hasPrimaryModifier } from '../../util/Mouse';

import { isKey } from '../../features/keyboard/KeyboardUtil';

import { isNil } from 'min-dash';

var HIGH_PRIORITY = 1500;
var HAND_CURSOR = 'grab';


export default function HandTool(eventBus, canvas, dragging, toolManager) {
this._dragging = dragging;

var self = this;

toolManager.registerTool('hand', {
tool: 'hand',
Expand All @@ -21,6 +26,31 @@ export default function HandTool(eventBus, canvas, dragging, toolManager) {
}
}, this);

eventBus.on('keyboard.keydown', HIGH_PRIORITY, function(e) {
if (!isSpace(e.keyEvent)) {
return;
}

if (this.isActive()) {
return;
}

function activateMove(event) {
self.activateMove(event);

window.removeEventListener('mousemove', activateMove);
}

window.addEventListener('mousemove', activateMove);

eventBus.once('keyboard.keyup', function(e) {
if (!isSpace(e.keyEvent)) {
return;
}

dragging.cancel();
});
}, this);

eventBus.on('hand.end', function(event) {
var target = event.originalEvent.target;
Expand Down Expand Up @@ -112,5 +142,11 @@ HandTool.prototype.toggle = function() {
HandTool.prototype.isActive = function() {
var context = this._dragging.context();

return context && /^hand/.test(context.prefix);
return !isNil(context) && /^hand/.test(context.prefix);
};

// helpers //////////

function isSpace(keyEvent) {
return isKey(' ', keyEvent);
}
31 changes: 22 additions & 9 deletions lib/features/keyboard/Keyboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ import {
isShift
} from './KeyboardUtil';

var KEYDOWN_EVENT = 'keyboard.keydown';
var KEYDOWN_EVENT = 'keyboard.keydown',
KEYUP_EVENT = 'keyboard.keyup';

var DEFAULT_PRIORITY = 1000;

Expand Down Expand Up @@ -49,7 +50,8 @@ export default function Keyboard(config, eventBus) {
this._config = config || {};
this._eventBus = eventBus;

this._keyHandler = this._keyHandler.bind(this);
this._keydownHandler = this._keydownHandler.bind(this);
this._keyupHandler = this._keyupHandler.bind(this);

// properly clean dom registrations
eventBus.on('diagram.destroy', function() {
Expand Down Expand Up @@ -78,8 +80,15 @@ Keyboard.$inject = [
'eventBus'
];

Keyboard.prototype._keyHandler = function(event) {
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 target = event.target,
eventBusResult;

Expand All @@ -91,7 +100,7 @@ Keyboard.prototype._keyHandler = function(event) {
keyEvent: event
};

eventBusResult = this._eventBus.fire(KEYDOWN_EVENT, context);
eventBusResult = this._eventBus.fire(type || KEYDOWN_EVENT, context);

if (eventBusResult) {
event.preventDefault();
Expand All @@ -106,7 +115,8 @@ Keyboard.prototype.bind = function(node) {
this._node = node;

// bind key events
domEvent.bind(node, 'keydown', this._keyHandler, true);
domEvent.bind(node, 'keydown', this._keydownHandler, true);
domEvent.bind(node, 'keyup', this._keyupHandler, true);

this._fire('bind');
};
Expand All @@ -122,7 +132,8 @@ Keyboard.prototype.unbind = function() {
this._fire('unbind');

// unbind key events
domEvent.unbind(node, 'keydown', this._keyHandler, true);
domEvent.unbind(node, 'keydown', this._keydownHandler, true);
domEvent.unbind(node, 'keyup', this._keyupHandler, true);
}

this._node = null;
Expand All @@ -137,16 +148,18 @@ Keyboard.prototype._fire = function(event) {
* 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 {Number} [priority]
* @param {Function} listener
* @param {string} type
*/
Keyboard.prototype.addListener = function(priority, listener) {
Keyboard.prototype.addListener = function(priority, listener, type) {
if (isFunction(priority)) {
type = listener;
listener = priority;
priority = DEFAULT_PRIORITY;
}

this._eventBus.on(KEYDOWN_EVENT, priority, listener);
this._eventBus.on(type || KEYDOWN_EVENT, priority, listener);
};

Keyboard.prototype.hasModifier = hasModifier;
Expand Down
47 changes: 46 additions & 1 deletion test/spec/features/hand-tool/HandToolSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import { createCanvasEvent as canvasEvent } from '../../../util/MockEvents';
import handToolModule from 'lib/features/hand-tool';
import draggingModule from 'lib/features/dragging';

import { createKeyEvent } from 'test/util/KeyEvents';


describe('features/hand-tool', function() {

Expand Down Expand Up @@ -36,7 +38,7 @@ describe('features/hand-tool', function() {

describe('general', function() {

it('should not move element', inject(function(canvas, handTool, dragging) {
it('should not move element', inject(function(handTool, dragging) {
// given
var position = {
x: childShape.x,
Expand All @@ -54,6 +56,49 @@ describe('features/hand-tool', function() {
expect(childShape.x).to.equal(position.x);
expect(childShape.y).to.equal(position.y);
}));

});


describe('activate on space', function() {

beforeEach(inject(function(eventBus) {
eventBus.fire('keyboard.keydown', {
keyEvent: createKeyEvent(' ')
});

triggerMouseEvent('mousemove', window);
}));


it('should activate on space key down', inject(function(handTool) {

// then
expect(handTool.isActive()).to.be.true;
}));


it('should deactiavte on space key up', inject(function(eventBus, handTool) {

// when
eventBus.fire('keyboard.keyup', {
keyEvent: createKeyEvent(' ')
});

// then
expect(handTool.isActive()).to.be.false;
}));

});

});

// helpers //////////

function triggerMouseEvent(type, node) {
var event = document.createEvent('MouseEvent');

event.initMouseEvent(type, true, true, window, 0, 0, 0, 100, 100, false, false, false, false, 0, null);

return node.dispatchEvent(event);
}
34 changes: 34 additions & 0 deletions test/spec/features/keyboard/KeyboardSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,40 @@ describe('features/keyboard', function() {

describe('add listener', function() {

it('should add keydown listener by default', inject(function(keyboard) {

// given
var keydownSpy = spy();

// when
keyboard.addListener(keydownSpy);

var event = createKeyEvent(TEST_KEY);

keyboard._keydownHandler(event);

// then
expect(keydownSpy).to.have.been.called;
}));


it('should add keyup listener', inject(function(keyboard) {

// given
var keyupSpy = spy();

// when
keyboard.addListener(keyupSpy, 'keyboard.keyup');

var event = createKeyEvent(TEST_KEY, { type: 'keyup' });

keyboard._keyupHandler(event);

// then
expect(keyupSpy).to.have.been.called;
}));


it('should handle listeners by priority', inject(function(keyboard) {

// given
Expand Down
11 changes: 9 additions & 2 deletions test/util/KeyEvents.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,23 @@ import {
*
* @param {String|Number} key the key or keyCode/charCode
* @param {Object} [attrs]
* @param {string} [attrs.type]
*
* @return {Event}
*/
export function createKeyEvent(key, attrs) {
if (!attrs) {
attrs = {};
}

var event = document.createEvent('Events') || new document.defaultView.CustomEvent('keyEvent');

// init and mark as bubbles / cancelable
event.initEvent('keydown', false, true);
event.initEvent(attrs.type || 'keydown', false, true);

var keyAttrs = isString(key) ? { key: key } : { keyCode: key, which: key };

return assign(event, keyAttrs, attrs || {});
delete attrs.type;

return assign(event, keyAttrs, attrs);
}

0 comments on commit 81210fb

Please sign in to comment.