diff --git a/core/components/menu/menu.js b/core/components/menu/menu.js index 6bad647d7..ab89585db 100644 --- a/core/components/menu/menu.js +++ b/core/components/menu/menu.js @@ -44,6 +44,41 @@ Blockly.Menu = function() { * @private */ this.highlightedIndex_ = -1; + + /** + * Mouse over event data. + * @type {?Blockly.EventData} + * @private + */ + this.mouseOverHandler_ = null; + + /** + * Click event data. + * @type {?Blockly.EventData} + * @private + */ + this.clickHandler_ = null; + + /** + * Mouse enter event data. + * @type {?Blockly.EventData} + * @private + */ + this.mouseEnterHandler_ = null; + + /** + * Mouse leave event data. + * @type {?Blockly.EventData} + * @private + */ + this.mouseLeaveHandler_ = null; + + /** + * Key down event data. + * @type {?Blockly.EventData} + * @private + */ + this.onKeyDownWrapper_ = null; }; Blockly.utils.object.inherits(Blockly.Menu, Blockly.Component); @@ -147,7 +182,6 @@ Blockly.Menu.prototype.attachEvents_ = function() { 'mouseenter', this, this.handleMouseEnter_, true); this.mouseLeaveHandler_ = Blockly.bindEventWithChecks_(el, 'mouseleave', this, this.handleMouseLeave_, true); - this.onKeyDownWrapper_ = Blockly.bindEventWithChecks_(el, 'keydown', this, this.handleKeyEvent); }; @@ -157,11 +191,26 @@ Blockly.Menu.prototype.attachEvents_ = function() { * @private */ Blockly.Menu.prototype.detachEvents_ = function() { - Blockly.unbindEvent_(this.mouseOverHandler_); - Blockly.unbindEvent_(this.clickHandler_); - Blockly.unbindEvent_(this.mouseEnterHandler_); - Blockly.unbindEvent_(this.mouseLeaveHandler_); - Blockly.unbindEvent_(this.onKeyDownWrapper_); + if (this.mouseOverHandler_) { + Blockly.unbindEvent_(this.mouseOverHandler_); + this.mouseOverHandler_ = null; + } + if (this.clickHandler_) { + Blockly.unbindEvent_(this.clickHandler_); + this.clickHandler_ = null; + } + if (this.mouseEnterHandler_) { + Blockly.unbindEvent_(this.mouseEnterHandler_); + this.mouseEnterHandler_ = null; + } + if (this.mouseLeaveHandler_) { + Blockly.unbindEvent_(this.mouseLeaveHandler_); + this.mouseLeaveHandler_ = null; + } + if (this.onKeyDownWrapper_) { + Blockly.unbindEvent_(this.onKeyDownWrapper_); + this.onKeyDownWrapper_ = null; + } }; // Child component management. diff --git a/core/components/tree/treecontrol.js b/core/components/tree/treecontrol.js index a498b6938..f42c8089a 100644 --- a/core/components/tree/treecontrol.js +++ b/core/components/tree/treecontrol.js @@ -44,6 +44,34 @@ goog.require('Blockly.utils.style'); Blockly.tree.TreeControl = function(toolbox, config) { this.toolbox_ = toolbox; + /** + * Focus event data. + * @type {?Blockly.EventData} + * @private + */ + this.onFocusWrapper_ = null; + + /** + * Blur event data. + * @type {?Blockly.EventData} + * @private + */ + this.onBlurWrapper_ = null; + + /** + * Click event data. + * @type {?Blockly.EventData} + * @private + */ + this.onClickWrapper_ = null; + + /** + * Key down event data. + * @type {?Blockly.EventData} + * @private + */ + this.onKeydownWrapper_ = null; + Blockly.tree.BaseNode.call(this, '', config); // The root is open and selected by default. @@ -272,10 +300,8 @@ Blockly.tree.TreeControl.prototype.attachEvents_ = function() { 'focus', this, this.handleFocus_); this.onBlurWrapper_ = Blockly.bindEvent_(el, 'blur', this, this.handleBlur_); - this.onClickWrapper_ = Blockly.bindEventWithChecks_(el, 'click', this, this.handleMouseEvent_); - this.onKeydownWrapper_ = Blockly.bindEvent_(el, 'keydown', this, this.handleKeyEvent_); }; @@ -285,10 +311,22 @@ Blockly.tree.TreeControl.prototype.attachEvents_ = function() { * @private */ Blockly.tree.TreeControl.prototype.detachEvents_ = function() { - Blockly.unbindEvent_(this.onFocusWrapper_); - Blockly.unbindEvent_(this.onBlurWrapper_); - Blockly.unbindEvent_(this.onClickWrapper_); - Blockly.unbindEvent_(this.onKeydownWrapper_); + if (this.onFocusWrapper_) { + Blockly.unbindEvent_(this.onFocusWrapper_); + this.onFocusWrapper_ = null; + } + if (this.onBlurWrapper_) { + Blockly.unbindEvent_(this.onBlurWrapper_); + this.onBlurWrapper_ = null; + } + if (this.onClickWrapper_) { + Blockly.unbindEvent_(this.onClickWrapper_); + this.onClickWrapper_ = null; + } + if (this.onKeydownWrapper_) { + Blockly.unbindEvent_(this.onKeydownWrapper_); + this.onKeydownWrapper_ = null; + } }; /** diff --git a/core/contextmenu.js b/core/contextmenu.js index 9feee57d8..1c51704f7 100644 --- a/core/contextmenu.js +++ b/core/contextmenu.js @@ -166,6 +166,7 @@ Blockly.ContextMenu.hide = function() { Blockly.ContextMenu.currentBlock = null; if (Blockly.ContextMenu.eventWrapper_) { Blockly.unbindEvent_(Blockly.ContextMenu.eventWrapper_); + Blockly.ContextMenu.eventWrapper_ = null; } }; diff --git a/core/field_angle.js b/core/field_angle.js index 3a550bcbb..5b8b75bc3 100644 --- a/core/field_angle.js +++ b/core/field_angle.js @@ -330,9 +330,11 @@ Blockly.FieldAngle.prototype.dropdownCreate_ = function() { // a click handler on the drag surface to update the value if the surface // is clicked. this.clickSurfaceWrapper_ = - Blockly.bindEventWithChecks_(circle, 'click', this, this.onMouseMove_, true, true); + Blockly.bindEventWithChecks_(circle, 'click', this, this.onMouseMove_, + true, true); this.moveSurfaceWrapper_ = - Blockly.bindEventWithChecks_(circle, 'mousemove', this, this.onMouseMove_, true, true); + Blockly.bindEventWithChecks_(circle, 'mousemove', this, this.onMouseMove_, + true, true); return svg; }; @@ -343,12 +345,15 @@ Blockly.FieldAngle.prototype.dropdownCreate_ = function() { Blockly.FieldAngle.prototype.dropdownDispose_ = function() { if (this.clickWrapper_) { Blockly.unbindEvent_(this.clickWrapper_); + this.clickWrapper_ = null; } if (this.clickSurfaceWrapper_) { Blockly.unbindEvent_(this.clickSurfaceWrapper_); + this.clickSurfaceWrapper_ = null; } if (this.moveSurfaceWrapper_) { Blockly.unbindEvent_(this.moveSurfaceWrapper_); + this.moveSurfaceWrapper_ = null; } this.gauge_ = null; this.line_ = null; diff --git a/core/field_colour.js b/core/field_colour.js index 095f29c72..54204553e 100644 --- a/core/field_colour.js +++ b/core/field_colour.js @@ -610,18 +610,23 @@ Blockly.FieldColour.prototype.dropdownCreate_ = function() { Blockly.FieldColour.prototype.dropdownDispose_ = function() { if (this.onClickWrapper_) { Blockly.unbindEvent_(this.onClickWrapper_); + this.onClickWrapper_ = null; } if (this.onMouseMoveWrapper_) { Blockly.unbindEvent_(this.onMouseMoveWrapper_); + this.onMouseMoveWrapper_ = null; } if (this.onMouseEnterWrapper_) { Blockly.unbindEvent_(this.onMouseEnterWrapper_); + this.onMouseEnterWrapper_ = null; } if (this.onMouseLeaveWrapper_) { Blockly.unbindEvent_(this.onMouseLeaveWrapper_); + this.onMouseLeaveWrapper_ = null; } if (this.onKeyDownWrapper_) { Blockly.unbindEvent_(this.onKeyDownWrapper_); + this.onKeyDownWrapper_ = null; } this.picker_ = null; this.highlightedIndex_ = null; diff --git a/core/field_textinput.js b/core/field_textinput.js index ff39d69a9..98b12f78d 100644 --- a/core/field_textinput.js +++ b/core/field_textinput.js @@ -84,6 +84,13 @@ Blockly.FieldTextInput = function(opt_value, opt_validator, opt_config) { * @private */ this.onKeyInputWrapper_ = null; + + /** + * Blur input event data. + * @type {?Blockly.EventData} + * @private + */ + this.onBlurInputWrapper_ = null; }; Blockly.utils.object.inherits(Blockly.FieldTextInput, Blockly.Field); @@ -349,7 +356,6 @@ Blockly.FieldTextInput.prototype.bindInputEvents_ = function(htmlInput) { this.onKeyInputWrapper_ = Blockly.bindEventWithChecks_( htmlInput, 'input', this, this.onHtmlInputChange_); - this.onBlurInputWrapper_ = Blockly.bindEventWithChecks_( htmlInput, 'blur', this, this.onHtmlInputBlur_); @@ -362,12 +368,15 @@ Blockly.FieldTextInput.prototype.bindInputEvents_ = function(htmlInput) { Blockly.FieldTextInput.prototype.unbindInputEvents_ = function() { if (this.onKeyDownWrapper_) { Blockly.unbindEvent_(this.onKeyDownWrapper_); + this.onKeyDownWrapper_ = null; } if (this.onKeyInputWrapper_) { Blockly.unbindEvent_(this.onKeyInputWrapper_); + this.onKeyInputWrapper_ = null; } if (this.onBlurInputWrapper_) { Blockly.unbindEvent_(this.onBlurInputWrapper_); + this.onBlurInputWrapper_ = null; } }; diff --git a/core/flyout_button.js b/core/flyout_button.js index 84898cf37..a8cd5360d 100644 --- a/core/flyout_button.js +++ b/core/flyout_button.js @@ -87,6 +87,13 @@ Blockly.FlyoutButton = function(workspace, targetWorkspace, xml, isLabel) { * @private */ this.cssClass_ = xml.getAttribute('web-class') || null; + + /** + * Mouse up event data. + * @type {?Blockly.EventData} + * @private + */ + this.onMouseUpWrapper_ = null; }; /** @@ -106,13 +113,6 @@ Blockly.FlyoutButton.prototype.width = 0; */ Blockly.FlyoutButton.prototype.height = 0; -/** - * Opaque data that can be passed to Blockly.unbindEvent_. - * @type {Array.} - * @private - */ -Blockly.FlyoutButton.prototype.onMouseUpWrapper_ = null; - /** * Create the button elements. * @return {!SVGElement} The button's SVG group. diff --git a/core/gesture.js b/core/gesture.js index 536f665fc..6e25b9051 100644 --- a/core/gesture.js +++ b/core/gesture.js @@ -162,7 +162,7 @@ Blockly.Gesture = function(e, creatorWorkspace) { /** * A handle to use to unbind a mouse move listener at the end of a drag. * Opaque data returned from Blockly.bindEventWithChecks_. - * @type {Array.} + * @type {?Blockly.EventData} * @protected */ this.onMoveWrapper_ = null; @@ -170,7 +170,7 @@ Blockly.Gesture = function(e, creatorWorkspace) { /** * A handle to use to unbind a mouse up listener at the end of a drag. * Opaque data returned from Blockly.bindEventWithChecks_. - * @type {Array.} + * @type {?Blockly.EventData} * @protected */ this.onUpWrapper_ = null; diff --git a/core/touch_gesture.js b/core/touch_gesture.js index 8cfa68351..374fdddb5 100644 --- a/core/touch_gesture.js +++ b/core/touch_gesture.js @@ -81,7 +81,7 @@ Blockly.TouchGesture = function(e, creatorWorkspace) { * A handle to use to unbind the second touch start or pointer down listener * at the end of a drag. * Opaque data returned from Blockly.bindEventWithChecks_. - * @type {Array.} + * @type {?Blockly.EventData} * @private */ this.onStartWrapper_ = null; diff --git a/core/workspace_comment_svg.js b/core/workspace_comment_svg.js index 7b9c41268..d8d79ff00 100644 --- a/core/workspace_comment_svg.js +++ b/core/workspace_comment_svg.js @@ -49,6 +49,21 @@ goog.require('Blockly.WorkspaceComment'); */ Blockly.WorkspaceCommentSvg = function(workspace, content, height, width, opt_id) { + + /** + * Mouse up event data. + * @type {?Blockly.EventData} + * @private + */ + this.onMouseUpWrapper_ = null; + + /** + * Mouse move event data. + * @type {?Blockly.EventData} + * @private + */ + this.onMouseMoveWrapper_ = null; + // Create core elements for the block. /** * @type {SVGElement} diff --git a/demos/custom-fields/pitch/field_pitch.js b/demos/custom-fields/pitch/field_pitch.js index f5bdf505b..3d3621030 100644 --- a/demos/custom-fields/pitch/field_pitch.js +++ b/demos/custom-fields/pitch/field_pitch.js @@ -39,6 +39,20 @@ var CustomFields = CustomFields || {}; */ CustomFields.FieldPitch = function(text) { CustomFields.FieldPitch.superClass_.constructor.call(this, text); + + /** + * Click event data. + * @type {?Blockly.EventData} + * @private + */ + this.clickWrapper_ = null; + + /** + * Move event data. + * @type {?Blockly.EventData} + * @private + */ + this.moveWrapper_ = null; }; Blockly.utils.object.inherits(CustomFields.FieldPitch, Blockly.FieldTextInput); @@ -112,8 +126,15 @@ CustomFields.FieldPitch.prototype.dropdownCreate_ = function() { * @private */ CustomFields.FieldPitch.prototype.dropdownDispose_ = function() { - Blockly.unbindEvent_(this.clickWrapper_); - Blockly.unbindEvent_(this.moveWrapper_); + if (this.clickWrapper_) { + Blockly.unbindEvent_(this.clickWrapper_); + this.clickWrapper_ = null; + } + if (this.moveWrapper_) { + Blockly.unbindEvent_(this.moveWrapper_); + this.moveWrapper_ = null; + } + this.imageElement_ = null; }; /**