From ed983333eb1c6a0574136682c57ddf276c70e328 Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Fri, 23 Sep 2016 13:46:11 -0700 Subject: [PATCH] bindEventWithChecks_ for internal use, and bindEvent_ with old behaviour but deprecated --- core/block_svg.js | 10 ++++---- core/bubble.js | 12 ++++----- core/comment.js | 6 ++--- core/contextmenu.js | 2 +- core/field.js | 3 ++- core/field_angle.js | 7 +++--- core/field_textinput.js | 9 ++++--- core/flyout.js | 38 +++++++++++++++------------- core/icon.js | 3 ++- core/inject.js | 41 +++++++++++++++++------------- core/scrollbar.js | 10 ++++---- core/toolbox.js | 4 +-- core/tooltip.js | 6 +++-- core/trashcan.js | 2 +- core/utils.js | 56 +++++++++++++++++++++++++++++++++++++++-- core/workspace_svg.js | 16 +++++++----- core/zoom_controls.js | 6 ++--- 17 files changed, 151 insertions(+), 80 deletions(-) diff --git a/core/block_svg.js b/core/block_svg.js index 9a7f87596..db6e70ac6 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -127,10 +127,10 @@ Blockly.BlockSvg.prototype.initSvg = function() { this.updateColour(); this.updateMovable(); if (!this.workspace.options.readOnly && !this.eventsInit_) { - Blockly.bindEvent_(this.getSvgRoot(), 'mousedown', this, + Blockly.bindEventWithChecks_(this.getSvgRoot(), 'mousedown', this, this.onMouseDown_); var thisBlock = this; - Blockly.bindEvent_(this.getSvgRoot(), 'touchstart', null, + Blockly.bindEventWithChecks_(this.getSvgRoot(), 'touchstart', null, function(e) {Blockly.longStart_(e, thisBlock);}); } this.eventsInit_ = true; @@ -577,10 +577,10 @@ Blockly.BlockSvg.prototype.onMouseDown_ = function(e) { this.workspace.startDrag(e, this.dragStartXY_); Blockly.dragMode_ = Blockly.DRAG_STICKY; - Blockly.BlockSvg.onMouseUpWrapper_ = Blockly.bindEvent_(document, + Blockly.BlockSvg.onMouseUpWrapper_ = Blockly.bindEventWithChecks_(document, 'mouseup', this, this.onMouseUp_); - Blockly.BlockSvg.onMouseMoveWrapper_ = Blockly.bindEvent_(document, - 'mousemove', this, this.onMouseMove_); + Blockly.BlockSvg.onMouseMoveWrapper_ = Blockly.bindEventWithChecks_( + document, 'mousemove', this, this.onMouseMove_); // Build a list of bubbles that need to be moved and where they started. this.draggedBubbles_ = []; var descendants = this.getDescendants(); diff --git a/core/bubble.js b/core/bubble.js index 243ec31e2..28274d9c5 100644 --- a/core/bubble.js +++ b/core/bubble.js @@ -75,10 +75,10 @@ Blockly.Bubble = function(workspace, content, shape, anchorXY, this.rendered_ = true; if (!workspace.options.readOnly) { - Blockly.bindEvent_(this.bubbleBack_, 'mousedown', this, + Blockly.bindEventWithChecks_(this.bubbleBack_, 'mousedown', this, this.bubbleMouseDown_); if (this.resizeGroup_) { - Blockly.bindEvent_(this.resizeGroup_, 'mousedown', this, + Blockly.bindEventWithChecks_(this.resizeGroup_, 'mousedown', this, this.resizeMouseDown_); } } @@ -286,9 +286,9 @@ Blockly.Bubble.prototype.bubbleMouseDown_ = function(e) { this.workspace_.RTL ? -this.relativeLeft_ : this.relativeLeft_, this.relativeTop_)); - Blockly.Bubble.onMouseUpWrapper_ = Blockly.bindEvent_(document, + Blockly.Bubble.onMouseUpWrapper_ = Blockly.bindEventWithChecks_(document, 'mouseup', this, Blockly.Bubble.bubbleMouseUp_); - Blockly.Bubble.onMouseMoveWrapper_ = Blockly.bindEvent_(document, + Blockly.Bubble.onMouseMoveWrapper_ = Blockly.bindEventWithChecks_(document, 'mousemove', this, this.bubbleMouseMove_); Blockly.hideChaff(); // This event has been handled. No need to bubble up to the document. @@ -328,9 +328,9 @@ Blockly.Bubble.prototype.resizeMouseDown_ = function(e) { this.workspace_.startDrag(e, new goog.math.Coordinate( this.workspace_.RTL ? -this.width_ : this.width_, this.height_)); - Blockly.Bubble.onMouseUpWrapper_ = Blockly.bindEvent_(document, + Blockly.Bubble.onMouseUpWrapper_ = Blockly.bindEventWithChecks_(document, 'mouseup', this, Blockly.Bubble.bubbleMouseUp_); - Blockly.Bubble.onMouseMoveWrapper_ = Blockly.bindEvent_(document, + Blockly.Bubble.onMouseMoveWrapper_ = Blockly.bindEventWithChecks_(document, 'mousemove', this, this.resizeMouseMove_); Blockly.hideChaff(); // This event has been handled. No need to bubble up to the document. diff --git a/core/comment.js b/core/comment.js index 2121530c0..a87a9ce24 100644 --- a/core/comment.js +++ b/core/comment.js @@ -112,12 +112,12 @@ Blockly.Comment.prototype.createEditor_ = function() { body.appendChild(textarea); this.textarea_ = textarea; this.foreignObject_.appendChild(body); - Blockly.bindEvent_(textarea, 'mouseup', this, this.textareaFocus_); + Blockly.bindEventWithChecks_(textarea, 'mouseup', this, this.textareaFocus_); // Don't zoom with mousewheel. - Blockly.bindEvent_(textarea, 'wheel', this, function(e) { + Blockly.bindEventWithChecks_(textarea, 'wheel', this, function(e) { e.stopPropagation(); }); - Blockly.bindEvent_(textarea, 'change', this, function(e) { + Blockly.bindEventWithChecks_(textarea, 'change', this, function(e) { if (this.text_ != textarea.value) { Blockly.Events.fire(new Blockly.Events.Change( this.block_, 'comment', null, this.text_, textarea.value)); diff --git a/core/contextmenu.js b/core/contextmenu.js index 462ad0b2c..6a8505636 100644 --- a/core/contextmenu.js +++ b/core/contextmenu.js @@ -78,7 +78,7 @@ Blockly.ContextMenu.show = function(e, options, rtl) { var menuDom = menu.getElement(); Blockly.addClass_(menuDom, 'blocklyContextMenu'); // Prevent system context menu when right-clicking a Blockly context menu. - Blockly.bindEvent_(menuDom, 'contextmenu', null, Blockly.noEvent); + Blockly.bindEventWithChecks_(menuDom, 'contextmenu', null, Blockly.noEvent); // Record menuSize after adding menu. var menuSize = goog.style.getSize(menuDom); diff --git a/core/field.js b/core/field.js index 72070a588..73f0bc45c 100644 --- a/core/field.js +++ b/core/field.js @@ -153,7 +153,8 @@ Blockly.Field.prototype.init = function() { this.updateEditable(); this.sourceBlock_.getSvgRoot().appendChild(this.fieldGroup_); this.mouseUpWrapper_ = - Blockly.bindEvent_(this.fieldGroup_, 'mouseup', this, this.onMouseUp_); + Blockly.bindEventWithChecks_(this.fieldGroup_, 'mouseup', this, + this.onMouseUp_); // Force a render. this.updateTextNode_(); }; diff --git a/core/field_angle.js b/core/field_angle.js index a294948e9..74e767f90 100644 --- a/core/field_angle.js +++ b/core/field_angle.js @@ -168,11 +168,12 @@ Blockly.FieldAngle.prototype.showEditor_ = function() { } svg.style.marginLeft = (15 - Blockly.FieldAngle.RADIUS) + 'px'; this.clickWrapper_ = - Blockly.bindEvent_(svg, 'click', this, Blockly.WidgetDiv.hide); + Blockly.bindEventWithChecks_(svg, 'click', this, Blockly.WidgetDiv.hide); this.moveWrapper1_ = - Blockly.bindEvent_(circle, 'mousemove', this, this.onMouseMove); + Blockly.bindEventWithChecks_(circle, 'mousemove', this, this.onMouseMove); this.moveWrapper2_ = - Blockly.bindEvent_(this.gauge_, 'mousemove', this, this.onMouseMove); + Blockly.bindEventWithChecks_(this.gauge_, 'mousemove', this, + this.onMouseMove); this.updateGraph_(); }; diff --git a/core/field_textinput.js b/core/field_textinput.js index 5af8bf9a7..5c057513f 100644 --- a/core/field_textinput.js +++ b/core/field_textinput.js @@ -147,13 +147,16 @@ Blockly.FieldTextInput.prototype.showEditor_ = function(opt_quietInput) { // Bind to keydown -- trap Enter without IME and Esc to hide. htmlInput.onKeyDownWrapper_ = - Blockly.bindEvent_(htmlInput, 'keydown', this, this.onHtmlInputKeyDown_); + Blockly.bindEventWithChecks_(htmlInput, 'keydown', this, + this.onHtmlInputKeyDown_); // Bind to keyup -- trap Enter; resize after every keystroke. htmlInput.onKeyUpWrapper_ = - Blockly.bindEvent_(htmlInput, 'keyup', this, this.onHtmlInputChange_); + Blockly.bindEventWithChecks_(htmlInput, 'keyup', this, + this.onHtmlInputChange_); // Bind to keyPress -- repeatedly resize when holding down a key. htmlInput.onKeyPressWrapper_ = - Blockly.bindEvent_(htmlInput, 'keypress', this, this.onHtmlInputChange_); + Blockly.bindEventWithChecks_(htmlInput, 'keypress', this, + this.onHtmlInputChange_); htmlInput.onWorkspaceChangeWrapper_ = this.resizeEditor_.bind(this); this.workspace_.addChangeListener(htmlInput.onWorkspaceChangeWrapper_); }; diff --git a/core/flyout.js b/core/flyout.js index 10e7cf2fd..f2ed92312 100644 --- a/core/flyout.js +++ b/core/flyout.js @@ -285,14 +285,15 @@ Blockly.Flyout.prototype.init = function(targetWorkspace) { this.hide(); Array.prototype.push.apply(this.eventWrappers_, - Blockly.bindEvent_(this.svgGroup_, 'wheel', this, this.wheel_)); + Blockly.bindEventWithChecks_(this.svgGroup_, 'wheel', this, this.wheel_)); if (!this.autoClose) { this.filterWrapper_ = this.filterForCapacity_.bind(this); this.targetWorkspace_.addChangeListener(this.filterWrapper_); } // Dragging the flyout up and down. Array.prototype.push.apply(this.eventWrappers_, - Blockly.bindEvent_(this.svgGroup_, 'mousedown', this, this.onMouseDown_)); + Blockly.bindEventWithChecks_(this.svgGroup_, 'mousedown', this, + this.onMouseDown_)); }; /** @@ -710,8 +711,8 @@ Blockly.Flyout.prototype.show = function(xmlList) { } }; - this.listeners_.push(Blockly.bindEvent_(this.svgBackground_, 'mouseover', - this, deselectAll)); + this.listeners_.push(Blockly.bindEventWithChecks_(this.svgBackground_, + 'mouseover', this, deselectAll)); if (this.horizontalLayout_) { this.height_ = 0; @@ -786,7 +787,8 @@ Blockly.Flyout.prototype.layout_ = function(contents, gaps) { var buttonSvg = button.createDom(); button.moveTo(cursorX, cursorY); button.show(); - Blockly.bindEvent_(buttonSvg, 'mouseup', button, button.onMouseUp); + Blockly.bindEventWithChecks_(buttonSvg, 'mouseup', button, + button.onMouseUp); this.buttons_.push(button); if (this.horizontalLayout_) { @@ -831,17 +833,17 @@ Blockly.Flyout.prototype.clearOldBlocks_ = function() { * @private */ Blockly.Flyout.prototype.addBlockListeners_ = function(root, block, rect) { - this.listeners_.push(Blockly.bindEvent_(root, 'mousedown', null, + this.listeners_.push(Blockly.bindEventWithChecks_(root, 'mousedown', null, this.blockMouseDown_(block))); - this.listeners_.push(Blockly.bindEvent_(rect, 'mousedown', null, + this.listeners_.push(Blockly.bindEventWithChecks_(rect, 'mousedown', null, this.blockMouseDown_(block))); - this.listeners_.push(Blockly.bindEvent_(root, 'mouseover', block, + this.listeners_.push(Blockly.bindEventWithChecks_(root, 'mouseover', block, block.addSelect)); - this.listeners_.push(Blockly.bindEvent_(root, 'mouseout', block, + this.listeners_.push(Blockly.bindEventWithChecks_(root, 'mouseout', block, block.removeSelect)); - this.listeners_.push(Blockly.bindEvent_(rect, 'mouseover', block, + this.listeners_.push(Blockly.bindEventWithChecks_(rect, 'mouseover', block, block.addSelect)); - this.listeners_.push(Blockly.bindEvent_(rect, 'mouseout', block, + this.listeners_.push(Blockly.bindEventWithChecks_(rect, 'mouseout', block, block.removeSelect)); }; @@ -881,10 +883,10 @@ Blockly.Flyout.prototype.blockMouseDown_ = function(block) { Blockly.Flyout.startDownEvent_ = e; Blockly.Flyout.startBlock_ = block; Blockly.Flyout.startFlyout_ = flyout; - Blockly.Flyout.onMouseUpWrapper_ = Blockly.bindEvent_(document, + Blockly.Flyout.onMouseUpWrapper_ = Blockly.bindEventWithChecks_(document, 'mouseup', flyout, flyout.onMouseUp_); - Blockly.Flyout.onMouseMoveBlockWrapper_ = Blockly.bindEvent_(document, - 'mousemove', flyout, flyout.onMouseMoveBlock_); + Blockly.Flyout.onMouseMoveBlockWrapper_ = Blockly.bindEventWithChecks_( + document, 'mousemove', flyout, flyout.onMouseMoveBlock_); } // This event has been handled. No need to bubble up to the document. e.stopPropagation(); @@ -908,10 +910,10 @@ Blockly.Flyout.prototype.onMouseDown_ = function(e) { this.startDragMouseY_ = e.clientY; this.startDragMouseX_ = e.clientX; Blockly.Flyout.startFlyout_ = this; - Blockly.Flyout.onMouseMoveWrapper_ = Blockly.bindEvent_(document, 'mousemove', - this, this.onMouseMove_); - Blockly.Flyout.onMouseUpWrapper_ = Blockly.bindEvent_(document, 'mouseup', - this, Blockly.Flyout.terminateDrag_); + Blockly.Flyout.onMouseMoveWrapper_ = Blockly.bindEventWithChecks_(document, + 'mousemove', this, this.onMouseMove_); + Blockly.Flyout.onMouseUpWrapper_ = Blockly.bindEventWithChecks_(document, + 'mouseup', this, Blockly.Flyout.terminateDrag_); // This event has been handled. No need to bubble up to the document. e.preventDefault(); e.stopPropagation(); diff --git a/core/icon.js b/core/icon.js index b10e18148..2f5f09049 100644 --- a/core/icon.js +++ b/core/icon.js @@ -85,7 +85,8 @@ Blockly.Icon.prototype.createIcon = function() { this.drawIcon_(this.iconGroup_); this.block_.getSvgRoot().appendChild(this.iconGroup_); - Blockly.bindEvent_(this.iconGroup_, 'mouseup', this, this.iconClick_); + Blockly.bindEventWithChecks_(this.iconGroup_, 'mouseup', this, + this.iconClick_); this.updateEditable(); }; diff --git a/core/inject.js b/core/inject.js index 70f21e33b..1f64da49b 100644 --- a/core/inject.js +++ b/core/inject.js @@ -57,7 +57,7 @@ Blockly.inject = function(container, opt_options) { var workspace = Blockly.createMainWorkspace_(svg, options); Blockly.init_(workspace); workspace.markFocused(); - Blockly.bindEvent_(svg, 'focus', workspace, workspace.markFocused); + Blockly.bindEventWithChecks_(svg, 'focus', workspace, workspace.markFocused); Blockly.svgResize(workspace); return workspace; }; @@ -257,18 +257,19 @@ Blockly.init_ = function(mainWorkspace) { var svg = mainWorkspace.getParentSvg(); // Supress the browser's context menu. - Blockly.bindEvent_(svg, 'contextmenu', null, + Blockly.bindEventWithChecks_(svg, 'contextmenu', null, function(e) { if (!Blockly.isTargetInput_(e)) { e.preventDefault(); } }); - var workspaceResizeHandler = Blockly.bindEvent_(window, 'resize', null, - function() { - Blockly.hideChaff(true); - Blockly.svgResize(mainWorkspace); - }); + var workspaceResizeHandler = Blockly.bindEventWithChecks_(window, 'resize', + null, + function() { + Blockly.hideChaff(true); + Blockly.svgResize(mainWorkspace); + }); mainWorkspace.setResizeHandlerWrapper(workspaceResizeHandler); Blockly.inject.bindDocumentEvents_(); @@ -314,19 +315,21 @@ Blockly.init_ = function(mainWorkspace) { */ Blockly.inject.bindDocumentEvents_ = function() { if (!Blockly.documentEventsBound_) { - Blockly.bindEvent_(document, 'keydown', null, Blockly.onKeyDown_); - Blockly.bindEvent_(document, 'touchend', null, Blockly.longStop_); - Blockly.bindEvent_(document, 'touchcancel', null, Blockly.longStop_); + Blockly.bindEventWithChecks_(document, 'keydown', null, Blockly.onKeyDown_); + Blockly.bindEventWithChecks_(document, 'touchend', null, Blockly.longStop_); + Blockly.bindEventWithChecks_(document, 'touchcancel', null, + Blockly.longStop_); // Don't use bindEvent_ for document's mouseup since that would create a // corresponding touch handler that would squeltch the ability to interact // with non-Blockly elements. document.addEventListener('mouseup', Blockly.onMouseUp_, false); // Some iPad versions don't fire resize after portrait to landscape change. if (goog.userAgent.IPAD) { - Blockly.bindEvent_(window, 'orientationchange', document, function() { - // TODO(#397): Fix for multiple blockly workspaces. - Blockly.svgResize(Blockly.getMainWorkspace()); - }); + Blockly.bindEventWithChecks_(window, 'orientationchange', document, + function() { + // TODO(#397): Fix for multiple blockly workspaces. + Blockly.svgResize(Blockly.getMainWorkspace()); + }); } } Blockly.documentEventsBound_ = true; @@ -361,16 +364,18 @@ Blockly.inject.loadSounds_ = function(pathToMedia, workspace) { workspace.preloadAudio_(); }; - // These are bound on mouse/touch events with Blockly.bindEvent_, so they - // restrict the touch identifier that will be recognized. But this is + // These are bound on mouse/touch events with Blockly.bindEventWithChecks_, so + // they restrict the touch identifier that will be recognized. But this is // really something that happens on a click, not a drag, so that's not // necessary. // Android ignores any sound not loaded as a result of a user action. soundBinds.push( - Blockly.bindEvent_(document, 'mousemove', null, unbindSounds, true)); + Blockly.bindEventWithChecks_(document, 'mousemove', null, unbindSounds, + true)); soundBinds.push( - Blockly.bindEvent_(document, 'touchstart', null, unbindSounds, true)); + Blockly.bindEventWithChecks_(document, 'touchstart', null, unbindSounds, + true)); }; /** diff --git a/core/scrollbar.js b/core/scrollbar.js index dce873098..c30f45cd0 100644 --- a/core/scrollbar.js +++ b/core/scrollbar.js @@ -219,9 +219,9 @@ Blockly.Scrollbar = function(workspace, horizontal, opt_pair) { this.positionAttribute_ = 'y'; } var scrollbar = this; - this.onMouseDownBarWrapper_ = Blockly.bindEvent_(this.svgBackground_, - 'mousedown', scrollbar, scrollbar.onMouseDownBar_); - this.onMouseDownHandleWrapper_ = Blockly.bindEvent_(this.svgHandle_, + this.onMouseDownBarWrapper_ = Blockly.bindEventWithChecks_( + this.svgBackground_, 'mousedown', scrollbar, scrollbar.onMouseDownBar_); + this.onMouseDownHandleWrapper_ = Blockly.bindEventWithChecks_(this.svgHandle_, 'mousedown', scrollbar, scrollbar.onMouseDownHandle_); }; @@ -649,9 +649,9 @@ Blockly.Scrollbar.prototype.onMouseDownHandle_ = function(e) { this.startDragHandle = this.handlePosition_; // Record the current mouse position. this.startDragMouse = this.horizontal_ ? e.clientX : e.clientY; - Blockly.Scrollbar.onMouseUpWrapper_ = Blockly.bindEvent_(document, + Blockly.Scrollbar.onMouseUpWrapper_ = Blockly.bindEventWithChecks_(document, 'mouseup', this, this.onMouseUpHandle_); - Blockly.Scrollbar.onMouseMoveWrapper_ = Blockly.bindEvent_(document, + Blockly.Scrollbar.onMouseMoveWrapper_ = Blockly.bindEventWithChecks_(document, 'mousemove', this, this.onMouseMoveHandle_); e.stopPropagation(); e.preventDefault(); diff --git a/core/toolbox.js b/core/toolbox.js index caa03c54b..fd97c25c7 100644 --- a/core/toolbox.js +++ b/core/toolbox.js @@ -155,7 +155,7 @@ Blockly.Toolbox.prototype.init = function() { svg.parentNode.insertBefore(this.HtmlDiv, svg); // Clicking on toolbox closes popups. - Blockly.bindEvent_(this.HtmlDiv, 'mousedown', this, + Blockly.bindEventWithChecks_(this.HtmlDiv, 'mousedown', this, function(e) { if (Blockly.isRightButton(e) || e.target == this.HtmlDiv) { // Close flyout. @@ -473,7 +473,7 @@ Blockly.Toolbox.TreeControl.prototype.enterDocument = function() { var el = this.getElement(); // Add touch handler. if (goog.events.BrowserFeature.TOUCH_ENABLED) { - Blockly.bindEvent_(el, goog.events.EventType.TOUCHSTART, this, + Blockly.bindEventWithChecks_(el, goog.events.EventType.TOUCHSTART, this, this.handleTouchEvent_); } }; diff --git a/core/tooltip.js b/core/tooltip.js index 7ee2a7080..447907273 100644 --- a/core/tooltip.js +++ b/core/tooltip.js @@ -131,8 +131,10 @@ Blockly.Tooltip.createDom = function() { * @param {!Element} element SVG element onto which tooltip is to be bound. */ Blockly.Tooltip.bindMouseEvents = function(element) { - Blockly.bindEvent_(element, 'mouseover', null, Blockly.Tooltip.onMouseOver_); - Blockly.bindEvent_(element, 'mouseout', null, Blockly.Tooltip.onMouseOut_); + Blockly.bindEventWithChecks_(element, 'mouseover', null, + Blockly.Tooltip.onMouseOver_); + Blockly.bindEventWithChecks_(element, 'mouseout', null, + Blockly.Tooltip.onMouseOut_); // Don't use bindEvent_ for mousemove since that would create a // corresponding touch handler, even though this only makes sense in the diff --git a/core/trashcan.js b/core/trashcan.js index 28baa0f20..f95298805 100644 --- a/core/trashcan.js +++ b/core/trashcan.js @@ -195,7 +195,7 @@ Blockly.Trashcan.prototype.createDom = function() { this.svgLid_.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', this.workspace_.options.pathToMedia + Blockly.SPRITE.url); - Blockly.bindEvent_(this.svgGroup_, 'mouseup', this, this.click); + Blockly.bindEventWithChecks_(this.svgGroup_, 'mouseup', this, this.click); this.animateLid_(); return this.svgGroup_; }; diff --git a/core/utils.js b/core/utils.js index e3e392303..517143ddc 100644 --- a/core/utils.js +++ b/core/utils.js @@ -91,7 +91,9 @@ Blockly.hasClass_ = function(element, className) { }; /** - * Bind an event to a function call. + * Bind an event to a function call. When calling the function, verify that + * it belongs to the touch stream that is currently being processsed, and split + * multitouch events into multiple events as needed. * @param {!Node} node Node upon which to listen. * @param {string} name Event name to listen to (e.g. 'mousedown'). * @param {Object} thisObject The value of 'this' in the function. @@ -102,7 +104,7 @@ Blockly.hasClass_ = function(element, className) { * @return {!Array.} Opaque data that can be passed to unbindEvent_. * @private */ -Blockly.bindEvent_ = function(node, name, thisObject, func, +Blockly.bindEventWithChecks_ = function(node, name, thisObject, func, opt_noCaptureIdentifier) { var handled = false; var wrapFunc = function(e) { @@ -145,6 +147,56 @@ Blockly.bindEvent_ = function(node, name, thisObject, func, return bindData; }; + +/** + * Bind an event to a function call. Handle multitouch events by using the + * coordinates of the first changed touch, and don't do any safety checks for + * simultaneous event processing. + * @deprecated in favor of bindEventWithChecks_, but preserved for external + * users. + * @param {!Node} node Node upon which to listen. + * @param {string} name Event name to listen to (e.g. 'mousedown'). + * @param {Object} thisObject The value of 'this' in the function. + * @param {!Function} func Function to call when event is triggered. + * @return {!Array.} Opaque data that can be passed to unbindEvent_. + * @private + */ +Blockly.bindEvent_ = function(node, name, thisObject, func) { + var wrapFunc = function(e) { + if (thisObject) { + func.call(thisObject, e); + } else { + func(e); + } + }; + + node.addEventListener(name, wrapFunc, false); + var bindData = [[node, name, wrapFunc]]; + + // Add equivalent touch event. + if (name in Blockly.Touch.TOUCH_MAP) { + var touchWrapFunc = function(e) { + // Punt on multitouch events. + if (e.changedTouches.length == 1) { + // Map the touch event's properties to the event. + var touchPoint = e.changedTouches[0]; + e.clientX = touchPoint.clientX; + e.clientY = touchPoint.clientY; + } + wrapFunc(e); + + // Stop the browser from scrolling/zooming the page. + e.preventDefault(); + }; + for (var i = 0, eventName; + eventName = Blockly.Touch.TOUCH_MAP[name][i]; i++) { + node.addEventListener(eventName, touchWrapFunc, false); + bindData.push([node, eventName, touchWrapFunc]); + } + } + return bindData; +}; + /** * Unbind one or more events event from a function call. * @param {!Array.} bindData Opaque data from bindEvent_. This list is diff --git a/core/workspace_svg.js b/core/workspace_svg.js index 6c72c934e..24d130df3 100644 --- a/core/workspace_svg.js +++ b/core/workspace_svg.js @@ -241,13 +241,15 @@ Blockly.WorkspaceSvg.prototype.createDom = function(opt_backgroundClass) { } if (!this.isFlyout) { - Blockly.bindEvent_(this.svgGroup_, 'mousedown', this, this.onMouseDown_); + Blockly.bindEventWithChecks_(this.svgGroup_, 'mousedown', this, + this.onMouseDown_); var thisWorkspace = this; - Blockly.bindEvent_(this.svgGroup_, 'touchstart', null, + Blockly.bindEventWithChecks_(this.svgGroup_, 'touchstart', null, function(e) {Blockly.longStart_(e, thisWorkspace);}); if (this.options.zoomOptions && this.options.zoomOptions.wheel) { // Mouse-wheel. - Blockly.bindEvent_(this.svgGroup_, 'wheel', this, this.onMouseWheel_); + Blockly.bindEventWithChecks_(this.svgGroup_, 'wheel', this, + this.onMouseWheel_); } } @@ -536,7 +538,7 @@ Blockly.WorkspaceSvg.prototype.traceOn = function(armed) { this.traceWrapper_ = null; } if (armed) { - this.traceWrapper_ = Blockly.bindEvent_(this.svgBlockCanvas_, + this.traceWrapper_ = Blockly.bindEventWithChecks_(this.svgBlockCanvas_, 'blocklySelectChange', this, function() {this.traceOn_ = false;}); } }; @@ -739,11 +741,13 @@ Blockly.WorkspaceSvg.prototype.onMouseDown_ = function(e) { if ('mouseup' in Blockly.Touch.TOUCH_MAP) { Blockly.Touch.onTouchUpWrapper_ = Blockly.Touch.onTouchUpWrapper_ || []; Blockly.Touch.onTouchUpWrapper_ = Blockly.Touch.onTouchUpWrapper_.concat( - Blockly.bindEvent_(document, 'mouseup', null, Blockly.onMouseUp_)); + Blockly.bindEventWithChecks_(document, 'mouseup', null, + Blockly.onMouseUp_)); } Blockly.onMouseMoveWrapper_ = Blockly.onMouseMoveWrapper_ || []; Blockly.onMouseMoveWrapper_ = Blockly.onMouseMoveWrapper_.concat( - Blockly.bindEvent_(document, 'mousemove', null, Blockly.onMouseMove_)); + Blockly.bindEventWithChecks_(document, 'mousemove', null, + Blockly.onMouseMove_)); } // This event has been handled. No need to bubble up to the document. e.stopPropagation(); diff --git a/core/zoom_controls.js b/core/zoom_controls.js index 3ae4eb765..be9a13be8 100644 --- a/core/zoom_controls.js +++ b/core/zoom_controls.js @@ -163,20 +163,20 @@ Blockly.ZoomControls.prototype.createDom = function() { workspace.options.pathToMedia + Blockly.SPRITE.url); // Attach event listeners. - Blockly.bindEvent_(zoomresetSvg, 'mousedown', null, function(e) { + Blockly.bindEventWithChecks_(zoomresetSvg, 'mousedown', null, function(e) { workspace.setScale(1); workspace.scrollCenter(); Blockly.Touch.clearTouchIdentifier(); // Don't block future drags. e.stopPropagation(); // Don't start a workspace scroll. e.preventDefault(); // Stop double-clicking from selecting text. }); - Blockly.bindEvent_(zoominSvg, 'mousedown', null, function(e) { + Blockly.bindEventWithChecks_(zoominSvg, 'mousedown', null, function(e) { workspace.zoomCenter(1); Blockly.Touch.clearTouchIdentifier(); // Don't block future drags. e.stopPropagation(); // Don't start a workspace scroll. e.preventDefault(); // Stop double-clicking from selecting text. }); - Blockly.bindEvent_(zoomoutSvg, 'mousedown', null, function(e) { + Blockly.bindEventWithChecks_(zoomoutSvg, 'mousedown', null, function(e) { workspace.zoomCenter(-1); Blockly.Touch.clearTouchIdentifier(); // Don't block future drags. e.stopPropagation(); // Don't start a workspace scroll.