From 068cb1efc8829d26c527ced538a210dd4780383b Mon Sep 17 00:00:00 2001 From: ericdrowell Date: Fri, 20 Sep 2013 16:17:32 -0700 Subject: [PATCH] added new content events to clean up stage events. added first mocha functional test --- src/Stage.js | 137 ++++++++++++++++++++++----------- test/functional/Events-test.js | 133 ++++++++++++++++++++++++++++++++ test/runner.html | 6 ++ 3 files changed, 229 insertions(+), 47 deletions(-) create mode 100644 test/functional/Events-test.js diff --git a/src/Stage.js b/src/Stage.js index 93e91fc1..a55eef74 100644 --- a/src/Stage.js +++ b/src/Stage.js @@ -3,6 +3,7 @@ var STAGE = 'Stage', STRING = 'string', PX = 'px', + MOUSEOUT = 'mouseout', MOUSELEAVE = 'mouseleave', MOUSEOVER = 'mouseover', @@ -17,6 +18,22 @@ TAP = 'tap', DBL_TAP = 'dbltap', TOUCHMOVE = 'touchmove', + + CONTENT_MOUSEOUT = 'contentMouseout', + CONTENT_MOUSELEAVE = 'contentMouseleave', + CONTENT_MOUSEOVER = 'contentMouseover', + CONTENT_MOUSEENTER = 'contentMouseenter', + CONTENT_MOUSEMOVE = 'contentMousemove', + CONTENT_MOUSEDOWN = 'contentMousedown', + CONTENT_MOUSEUP = 'contentMouseup', + CONTENT_CLICK = 'contentClick', + CONTENT_DBL_CLICK = 'contentDblclick', + CONTENT_TOUCHSTART = 'contentTouchstart', + CONTENT_TOUCHEND = 'contentTouchend', + CONTENT_TAP = 'contentTap', + CONTENT_DBL_TAP = 'contentDbltap', + CONTENT_TOUCHMOVE = 'contentTouchmove', + DIV = 'div', RELATIVE = 'relative', INLINE_BLOCK = 'inline-block', @@ -343,7 +360,7 @@ } }, _mouseover: function(evt) { - this._fire(MOUSEOVER, evt); + this._fire(CONTENT_MOUSEOVER, evt); }, _mouseout: function(evt) { this._setPointerPosition(evt); @@ -356,29 +373,26 @@ } this.mousePos = undefined; - this._fire(MOUSEOUT, evt); + this._fire(CONTENT_MOUSEOUT, evt); }, _mousemove: function(evt) { this._setPointerPosition(evt); var dd = Kinetic.DD, obj = this.getIntersection(this.getPointerPosition()), - shape; + shape = obj && obj.shape ? obj.shape : undefined; - if(obj) { - shape = obj.shape; - if(shape) { - if(!Kinetic.isDragging() && obj.pixel[3] === 255 && (!this.targetShape || this.targetShape._id !== shape._id)) { - if(this.targetShape) { - this.targetShape._fireAndBubble(MOUSEOUT, evt, shape); - this.targetShape._fireAndBubble(MOUSELEAVE, evt, shape); - } - shape._fireAndBubble(MOUSEOVER, evt, this.targetShape); - shape._fireAndBubble(MOUSEENTER, evt, this.targetShape); - this.targetShape = shape; - } - else { - shape._fireAndBubble(MOUSEMOVE, evt); + if(shape) { + if(!Kinetic.isDragging() && obj.pixel[3] === 255 && (!this.targetShape || this.targetShape._id !== shape._id)) { + if(this.targetShape) { + this.targetShape._fireAndBubble(MOUSEOUT, evt, shape); + this.targetShape._fireAndBubble(MOUSELEAVE, evt, shape); } + shape._fireAndBubble(MOUSEOVER, evt, this.targetShape); + shape._fireAndBubble(MOUSEENTER, evt, this.targetShape); + this.targetShape = shape; + } + else { + shape._fireAndBubble(MOUSEMOVE, evt); } } /* @@ -386,12 +400,12 @@ * to run mouseout from previous target shape */ else { - this._fire(MOUSEMOVE, evt); if(this.targetShape && !Kinetic.isDragging()) { this.targetShape._fireAndBubble(MOUSEOUT, evt); this.targetShape._fireAndBubble(MOUSELEAVE, evt); this.targetShape = null; } + this._fire(CONTENT_MOUSEMOVE, evt); } if(dd) { @@ -407,11 +421,16 @@ _mousedown: function(evt) { this._setPointerPosition(evt); var obj = this.getIntersection(this.getPointerPosition()), - shape = obj && obj.shape ? obj.shape : this; + shape = obj && obj.shape ? obj.shape : undefined; Kinetic.listenClickTap = true; - this.clickStartShape = shape; - shape._fireAndBubble(MOUSEDOWN, evt); + + if (shape) { + this.clickStartShape = shape; + shape._fireAndBubble(MOUSEDOWN, evt); + } + + this._fire(CONTENT_MOUSEDOWN); // always call preventDefault for desktop events because some browsers // try to drag and drop the canvas element @@ -423,25 +442,39 @@ this._setPointerPosition(evt); var that = this, obj = this.getIntersection(this.getPointerPosition()), - shape = obj && obj.shape ? obj.shape : this; + shape = obj && obj.shape ? obj.shape : undefined, + fireDblClick = false; - shape._fireAndBubble(MOUSEUP, evt); + if(Kinetic.inDblClickWindow) { + fireDblClick = true; + Kinetic.inDblClickWindow = false; + } + else { + Kinetic.inDblClickWindow = true; + } - // detect if click or double click occurred - if(Kinetic.listenClickTap && shape._id === this.clickStartShape._id) { - shape._fireAndBubble(CLICK, evt); + setTimeout(function() { + Kinetic.inDblClickWindow = false; + }, Kinetic.dblClickWindow); - if(Kinetic.inDblClickWindow) { - shape._fireAndBubble(DBL_CLICK, evt); - Kinetic.inDblClickWindow = false; + if (shape) { + shape._fireAndBubble(MOUSEUP, evt); + + // detect if click or double click occurred + if(Kinetic.listenClickTap && shape._id === this.clickStartShape._id) { + shape._fireAndBubble(CLICK, evt); + + if(fireDblClick) { + shape._fireAndBubble(DBL_CLICK, evt); + } } - else { - Kinetic.inDblClickWindow = true; + } + this._fire(CONTENT_MOUSEUP); + if (Kinetic.listenClickTap) { + this._fire(CONTENT_CLICK, evt); + if(fireDblClick) { + this._fire(CONTENT_DBL_CLICK, evt); } - - setTimeout(function() { - Kinetic.inDblClickWindow = false; - }, Kinetic.dblClickWindow); } Kinetic.listenClickTap = false; @@ -455,11 +488,14 @@ _touchstart: function(evt) { this._setPointerPosition(evt); var obj = this.getIntersection(this.getPointerPosition()), - shape = obj && obj.shape ? obj.shape : this; + shape = obj && obj.shape ? obj.shape : undefined; Kinetic.listenClickTap = true; - this.tapStartShape = shape; - shape._fireAndBubble(TOUCHSTART, evt); + + if (shape) { + this.tapStartShape = shape; + shape._fireAndBubble(TOUCHSTART, evt); + } // only call preventDefault if the shape is listening for events if (shape.isListening() && evt.preventDefault) { @@ -470,16 +506,11 @@ this._setPointerPosition(evt); var that = this, obj = this.getIntersection(this.getPointerPosition()), - shape = obj && obj.shape ? obj.shape : this; - - shape._fireAndBubble(TOUCHEND, evt); - - // detect if tap or double tap occurred - if(Kinetic.listenClickTap && shape._id === this.tapStartShape._id) { - shape._fireAndBubble(TAP, evt); + shape = obj && obj.shape ? obj.shape : undefined, + fireDblClick = false; if(Kinetic.inDblClickWindow) { - shape._fireAndBubble(DBL_TAP, evt); + fireDblClick = true; Kinetic.inDblClickWindow = false; } else { @@ -489,6 +520,18 @@ setTimeout(function() { Kinetic.inDblClickWindow = false; }, Kinetic.dblClickWindow); + + if (shape) { + shape._fireAndBubble(TOUCHEND, evt); + + // detect if tap or double tap occurred + if(Kinetic.listenClickTap && shape._id === this.tapStartShape._id) { + shape._fireAndBubble(TAP, evt); + + if(fireDblClick) { + shape._fireAndBubble(DBL_TAP, evt); + } + } } Kinetic.listenClickTap = false; @@ -520,7 +563,7 @@ var mouseX = evt.offsetX !== undefined ? evt.offsetX : evt.layerX || (evt.clientX - this._getContentPosition().left), mouseY = evt.offsetY !== undefined ? evt.offsetY : evt.layerY || (evt.clientY - this._getContentPosition().top); - + this.mousePos = { x: mouseX, y: mouseY diff --git a/test/functional/Events-test.js b/test/functional/Events-test.js new file mode 100644 index 00000000..a6b18229 --- /dev/null +++ b/test/functional/Events-test.js @@ -0,0 +1,133 @@ +suite('Events', function() { + test('stage content mouse events', function() { + var stage = addStage(); + var layer = new Kinetic.Layer(); + var circle = new Kinetic.Circle({ + x: 100, + y: 100, + radius: 70, + fill: 'green', + stroke: 'black', + strokeWidth: 4, + name: 'myCircle' + }); + + layer.add(circle); + stage.add(layer); + + var circleMousedown = + circleMouseup = + stageContentMousedown = + stageContentMouseup = + stageContentMousemove = + stageContentMouseout = + stageContentMouseover = + stageContentClick = + stageContentDblClick = + 0; + + var top = stage.content.getBoundingClientRect().top; + + + circle.on('mousedown', function() { + circleMousedown++; + }); + + circle.on('mouseup', function() { + circleMouseup++; + }); + + stage.on('contentMousedown', function() { + stageContentMousedown++; + }); + + stage.on('contentMouseup', function() { + stageContentMouseup++; + }); + + stage.on('contentMousemove', function() { + stageContentMousemove++; + }); + + stage.on('contentMouseout', function() { + stageContentMouseout++; + }); + + stage.on('contentMouseover', function() { + stageContentMouseover++; + }); + + stage.on('contentClick', function() { + //console.log('click'); + stageContentClick++; + }); + + stage.on('contentDblclick', function() { + //console.log('dbl click'); + stageContentDblClick++; + }); + + stage._mousedown({ + clientX: 100, + clientY: 100 + top + }); + + stage._mouseup({ + clientX: 100, + clientY: 100 + top + }); + + assert.equal(circleMousedown, 1); + assert.equal(circleMouseup, 1); + assert.equal(stageContentMousedown, 1); + assert.equal(stageContentMouseup, 1); + assert.equal(stageContentClick, 1); + + stage._mousedown({ + clientX: 1, + clientY: 1 + top + }); + stage._mouseup({ + clientX: 1, + clientY: 1 + top + }); + + assert.equal(stageContentMousedown, 2); + assert.equal(stageContentMouseup, 2); + + // trigger double click + stage._mousedown({ + clientX: 1, + clientY: 1 + top + }); + stage._mouseup({ + clientX: 1, + clientY: 1 + top + }); + + assert.equal(stageContentMousedown, 3); + assert.equal(stageContentMouseup, 3); + //assert.equal(stageContentDblClick, 1); + + stage._mousemove({ + clientX: 200, + clientY: 1 + top + }); + + assert.equal(stageContentMousemove, 1); + + stage._mouseout({ + clientX: 0, + clientY: 0 + }); + + assert.equal(stageContentMouseout, 1); + + stage._mouseover({ + clientX: 0, + clientY: 0 + }); + + assert.equal(stageContentMouseover, 1); + }); +}); \ No newline at end of file diff --git a/test/runner.html b/test/runner.html index c210d8ab..8dd52977 100644 --- a/test/runner.html +++ b/test/runner.html @@ -37,6 +37,8 @@ + + @@ -72,6 +74,10 @@ + + + +