Skip to content

Commit

Permalink
fix: generalize fix for swallowed hover events
Browse files Browse the repository at this point in the history
Replaces the old drag hover fix (which fixed kindof the same thing)
with one that works in a general fashion only on element.* level.

Closes bpmn-io/bpmn-js#1366
  • Loading branch information
nikku authored and azeghers committed Nov 29, 2020
1 parent fbce7d1 commit 776afcf
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 44 deletions.
8 changes: 2 additions & 6 deletions lib/features/dragging/index.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
import SelectionModule from '../selection';

import Dragging from './Dragging';
import HoverFix from './HoverFix';


export default {
__init__: [
'hoverFix'
],
__depends__: [
SelectionModule
SelectionModule,
],
dragging: [ 'type', Dragging ],
hoverFix: [ 'type', HoverFix ]
};
Original file line number Diff line number Diff line change
Expand Up @@ -79,59 +79,48 @@ export default function HoverFix(eventBus, dragging, elementRegistry) {


/**
* We make sure that drag.out is always fired, even if the
* We make sure that element.out is always fired, even if the
* browser swallows an element.out event.
*
* Event sequence:
*
* drag.hover
* element.hover
* (element.out >> sometimes swallowed)
* element.hover >> ensure we fired drag.out
* element.hover >> ensure we fired element.out
*/
eventBus.on('drag.init', function() {
(function() {
var hoverGfx;
var hover;

var hover, hoverGfx;
eventBus.on('element.hover', function(event) {

function setDragHover(event) {
hover = event.hover;
hoverGfx = event.hoverGfx;
}
// (1) remember current hover element
hoverGfx = event.gfx;
hover = event.element;
});

function unsetHover() {
hover = null;
hoverGfx = null;
}
eventBus.on('element.hover', HIGH_PRIORITY, function(event) {

function ensureOut() {
// (3) am I on an element still?
if (hover) {

if (!hover) {
return;
// (4) that is a problem, gotta "simulate the out"
eventBus.fire('element.out', {
element: hover,
gfx: hoverGfx
});
}

var element = hover,
gfx = hoverGfx;

hover = null;
hoverGfx = null;

// emit synthetic out event
dragging.out({
element: element,
gfx: gfx
});
}
});

eventBus.on('drag.hover', setDragHover);
eventBus.on('element.out', unsetHover);
eventBus.on('element.hover', HIGH_PRIORITY, ensureOut);
eventBus.on('element.out', function() {

eventBus.once('drag.cleanup', function() {
eventBus.off('drag.hover', setDragHover);
eventBus.off('element.out', unsetHover);
eventBus.off('element.hover', ensureOut);
// (2) unset hover state if we correctly outed us *GG*
hoverGfx = null;
hover = null;
});

});
})();

this._findTargetGfx = function(event) {
var position,
Expand Down
14 changes: 14 additions & 0 deletions lib/features/hover-fix/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import DraggingModule from '../dragging';

import HoverFix from './HoverFix';


export default {
__init__: [
'hoverFix'
],
__depends__: [
DraggingModule
],
hoverFix: [ 'type', HoverFix ],
};
4 changes: 3 additions & 1 deletion test/spec/features/create/CreateSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
import modelingModule from 'lib/features/modeling';
import moveModule from 'lib/features/move';
import dragModule from 'lib/features/dragging';
import hoverFixModule from 'lib/features/hover-fix';
import createModule from 'lib/features/create';
import attachSupportModule from 'lib/features/attach-support';
import connectionPreviewModule from 'lib/features/connection-preview';
Expand All @@ -27,7 +28,8 @@ var testModules = [
attachSupportModule,
modelingModule,
moveModule,
dragModule
dragModule,
hoverFixModule
];

var LOW_PRIORITY = 500;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@ import { assign } from 'min-dash';
import { createCanvasEvent as canvasEvent } from '../../../util/MockEvents';

import dragModule from 'lib/features/dragging';
import hoverFixModule from 'lib/features/hover-fix';


describe('features/dragging - HoverFix', function() {

beforeEach(bootstrapDiagram({ modules: [ dragModule ] }));
beforeEach(bootstrapDiagram({ modules: [ dragModule, hoverFixModule ] }));

var shape1,
shape2;
Expand Down Expand Up @@ -44,6 +45,63 @@ describe('features/dragging - HoverFix', function() {

describe('hover fix', function() {

it('should ensure the correct events are fired in sequence', inject(function(canvas, eventBus) {

// given
var events = [];

eventBus.on(['element.hover', 'element.out'], function(event) {
events.push({ type: event.type, element: event.element });
});

eventBus.fire('element.hover', { element: shape1, gfx: canvas.getGraphics(shape1) });

// assume
expect(events).to.eql([{ type: 'element.hover', element: shape1 }]);

// when
eventBus.fire('element.hover', { element: shape2, gfx: canvas.getGraphics(shape2) });

// then
expect(events).to.eql([
{ type: 'element.hover', element: shape1 },
{ type: 'element.out', element: shape1 },
{ type: 'element.hover', element: shape2 }
]);
}));


it('should not interfere with the normal hovering process', inject(function(canvas, eventBus) {

// given
var events = [];

eventBus.on(['element.hover', 'element.out'], function(event) {
events.push({ type: event.type, element: event.element });
});

eventBus.fire('element.hover', { element: shape1, gfx: canvas.getGraphics(shape1) });

// assume
expect(events).to.eql([{ type: 'element.hover', element: shape1 }]);

// when
eventBus.fire('element.out', { element: shape1, gfx: canvas.getGraphics(shape2) });
eventBus.fire('element.hover', { element: shape2, gfx: canvas.getGraphics(shape2) });

// then
expect(events).to.eql([
{ type: 'element.hover', element: shape1 },
{ type: 'element.out', element: shape1 },
{ type: 'element.hover', element: shape2 }
]);
}));

});


describe('dragging fix', function() {

beforeEach(inject(function(dragging) {
dragging.setOptions({ manual: true });
}));
Expand Down

0 comments on commit 776afcf

Please sign in to comment.