From 15b34f7e737e12d9a75b3b8ecdda8671a2eb750d Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Sun, 2 Dec 2018 20:26:09 -0800 Subject: [PATCH 1/5] Added flyout to trashcan to "get back" deleted blocks.` --- core/blockly.js | 8 ++- core/inject.js | 14 ++++ core/trashcan.js | 159 +++++++++++++++++++++++++++++++++++++++--- core/workspace_svg.js | 19 +---- core/zoom_controls.js | 3 + 5 files changed, 175 insertions(+), 28 deletions(-) diff --git a/core/blockly.js b/core/blockly.js index 366e55fdf..f17be4d61 100644 --- a/core/blockly.js +++ b/core/blockly.js @@ -326,8 +326,14 @@ Blockly.onContextMenu_ = function(e) { Blockly.hideChaff = function(opt_allowToolbox) { Blockly.Tooltip.hide(); Blockly.WidgetDiv.hide(); + // For now the trashcan flyout always autocloses because it overlays the + // trashcan UI (no trashcan to click to close it) + var workspace = Blockly.getMainWorkspace(); + if (workspace.trashcan && + workspace.trashcan.flyout_) { + workspace.trashcan.flyout_.hide(); + } if (!opt_allowToolbox) { - var workspace = Blockly.getMainWorkspace(); if (workspace.toolbox_ && workspace.toolbox_.flyout_ && workspace.toolbox_.flyout_.autoClose) { diff --git a/core/inject.js b/core/inject.js index 5ee706d15..aba6c196d 100644 --- a/core/inject.js +++ b/core/inject.js @@ -218,6 +218,12 @@ Blockly.createMainWorkspace_ = function(svg, options, blockDragSurface, var flyout = mainWorkspace.addFlyout_('svg'); Blockly.utils.insertAfter(flyout, svg); } + if (options.hasTrashcan) { + mainWorkspace.addTrashcan_(); + } + if (options.zoomOptions && options.zoomOptions.controls) { + mainWorkspace.addZoomControls_(); + } // A null translation will also apply the correct initial scale. mainWorkspace.translate(0, 0); @@ -322,6 +328,14 @@ Blockly.init_ = function(mainWorkspace) { } } + var bottom = Blockly.Scrollbar.scrollbarThickness; + if (options.hasTrashcan) { + bottom = mainWorkspace.trashcan.init(bottom); + } + if (options.zoomOptions && options.zoomOptions.controls) { + mainWorkspace.zoomControls_.init(bottom); + } + if (options.hasScrollbars) { mainWorkspace.scrollbar = new Blockly.ScrollbarPair(mainWorkspace); mainWorkspace.scrollbar.resize(); diff --git a/core/trashcan.js b/core/trashcan.js index bd6a70954..47238d46e 100644 --- a/core/trashcan.js +++ b/core/trashcan.js @@ -38,6 +38,19 @@ goog.require('goog.math.Rect'); */ Blockly.Trashcan = function(workspace) { this.workspace_ = workspace; + var flyoutWorkspaceOptions = { + scrollbars: true, + disabledPatternId: this.workspace_.options.disabledPatternId, + parentWorkspace: this.workspace_, + RTL: this.workspace_.RTL, + oneBasedIndex: workspace.options.oneBasedIndex, + // TODO: Add horizontal. + /*horizontalLayout: this.workspace_.horizontalLayout,*/ + toolboxPosition: this.workspace_.RTL ? Blockly.TOOLBOX_AT_LEFT : + Blockly.TOOLBOX_AT_RIGHT + }; + this.flyout_ = new Blockly.VerticalFlyout(flyoutWorkspaceOptions); + this.workspace_.addChangeListener(this.onDelete_()); }; /** @@ -96,12 +109,46 @@ Blockly.Trashcan.prototype.SPRITE_LEFT_ = 0; */ Blockly.Trashcan.prototype.SPRITE_TOP_ = 32; +/** + * The openness of the lid when the trashcan contains blocks. + * (0.0 = closed, 1.0 = open) + * @type {number} + * @private + */ +Blockly.Trashcan.prototype.HAS_BLOCKS_LID_ANGLE = 0.1; + +/** + * The maximum number of blocks that can go in the trashcan's flyout. '0' turns + * turns off trashcan contents, 'Infinity' sets it to unlimited. + * @type {number} + */ +Blockly.Trashcan.prototype.MAX_CONTENTS = 32; + /** * Current open/close state of the lid. * @type {boolean} */ Blockly.Trashcan.prototype.isOpen = false; +/** + * The minimum openness of the lid. Used to indicate if the trashcan contains + * blocks. + * @type {number} + */ +Blockly.Trashcan.prototype.minOpenness_ = 0; + +/** + * True if the trashcan contains blocks, otherwise false. + * @type {boolean} + */ +Blockly.Trashcan.prototype.hasBlocks = false; + +/** + * A list of Xml representing blocks "inside" the trashcan. + * @type {Array} + */ +Blockly.Trashcan.prototype.contents = []; + /** * The SVG group containing the trash can. * @type {Element} @@ -207,6 +254,11 @@ Blockly.Trashcan.prototype.createDom = function() { this.workspace_.options.pathToMedia + Blockly.SPRITE.url); Blockly.bindEventWithChecks_(this.svgGroup_, 'mouseup', this, this.click); + // bindEventWithChecks_ quashes events too aggressively. See: + // https://groups.google.com/forum/#!topic/blockly/QF4yB9Wx00s + // Bind to body instead of this.svgGroup_ so that we don't get lid jitters + Blockly.bindEvent_(body, 'mouseover', this, this.mouseOver_); + Blockly.bindEvent_(body, 'mouseout', this, this.mouseOut_); this.animateLid_(); return this.svgGroup_; }; @@ -217,6 +269,10 @@ Blockly.Trashcan.prototype.createDom = function() { * @return {number} Distance from workspace bottom to the top of trashcan. */ Blockly.Trashcan.prototype.init = function(bottom) { + Blockly.utils.insertAfter(this.flyout_.createDom('svg'), + this.workspace_.getParentSvg()); + this.flyout_.init(this.workspace_); + this.bottom_ = this.MARGIN_BOTTOM_ + bottom; this.setOpen_(false); return this.bottom_ + this.BODY_HEIGHT_ + this.LID_HEIGHT_; @@ -240,6 +296,9 @@ Blockly.Trashcan.prototype.dispose = function() { * Move the trash can to the bottom-right corner. */ Blockly.Trashcan.prototype.position = function() { + if (!this.bottom_) { + return; + } var metrics = this.workspace_.getMetrics(); if (!metrics) { // There are no metrics available (workspace is probably not visible). @@ -309,20 +368,28 @@ Blockly.Trashcan.prototype.setOpen_ = function(state) { */ Blockly.Trashcan.prototype.animateLid_ = function() { this.lidOpen_ += this.isOpen ? 0.2 : -0.2; - this.lidOpen_ = Math.min(Math.max(this.lidOpen_, 0), 1); - var lidAngle = this.lidOpen_ * 45; - this.svgLid_.setAttribute('transform', 'rotate(' + - (this.workspace_.RTL ? -lidAngle : lidAngle) + ',' + - (this.workspace_.RTL ? 4 : this.WIDTH_ - 4) + ',' + - (this.LID_HEIGHT_ - 2) + ')'); + this.lidOpen_ = Math.min(Math.max(this.lidOpen_, this.minOpenness_), 1); + this.setLidAngle_(this.lidOpen_ * 45); // Linear interpolation between 0.4 and 0.8. var opacity = 0.4 + this.lidOpen_ * (0.8 - 0.4); this.svgGroup_.style.opacity = opacity; - if (this.lidOpen_ > 0 && this.lidOpen_ < 1) { + if (this.lidOpen_ > this.minOpenness_ && this.lidOpen_ < 1) { this.lidTask_ = setTimeout(this.animateLid_.bind(this), 20); } }; +/** + * Set the angle of the trashcan's lid. + * @param {!number} lidAngle The angle at which to set the lid. + * @private + */ +Blockly.Trashcan.prototype.setLidAngle_ = function(lidAngle) { + this.svgLid_.setAttribute('transform', 'rotate(' + + (this.workspace_.RTL ? -lidAngle : lidAngle) + ',' + + (this.workspace_.RTL ? 4 : this.WIDTH_ - 4) + ',' + + (this.LID_HEIGHT_ - 2) + ')'); +}; + /** * Flip the lid shut. * Called externally after a drag. @@ -335,10 +402,80 @@ Blockly.Trashcan.prototype.close = function() { * Inspect the contents of the trash. */ Blockly.Trashcan.prototype.click = function() { - var dx = this.workspace_.startScrollX - this.workspace_.scrollX; - var dy = this.workspace_.startScrollY - this.workspace_.scrollY; - if (Math.sqrt(dx * dx + dy * dy) > Blockly.DRAG_RADIUS) { + if (!this.hasBlocks) { return; } - console.log('TODO: Inspect trash.'); + + var xml = []; + for (var i = 0, text; text = this.contents[i]; i++) { + xml[i] = Blockly.Xml.textToDom(text).firstChild; + } + this.flyout_.show(xml); +}; + +/** + * Indicate that the trashcan can be clicked (by opening it) if it has blocks. + * @private + */ +Blockly.Trashcan.prototype.mouseOver_ = function() { + if (!this.hasBlocks) { + return; + } + this.setOpen_(true); +}; + +/** + * Close the lid of the trashcan if it was open (Vis. it was indicating it had + * blocks). + * @private + */ +Blockly.Trashcan.prototype.mouseOut_ = function() { + // No need to do a .hasBlocks check here because if it doesn't the trashcan + // wont be open in the first place, and setOpen_ won't run. + this.setOpen_(false); +}; + +/** + * Handle a BLOCK_DELETE event. Adds deleted blocks oldXml to the content array. + * @returns {!Function} Function to call when a block is deleted. + * @private + */ +Blockly.Trashcan.prototype.onDelete_ = function() { + var trashcan = this; + return function(event) { + if (!trashcan.MAX_CONTENTS) { + return; + } + if (event.type == Blockly.Events.BLOCK_DELETE) { + var textBlock = trashcan.blockXmlToText(event.oldXml); + if (trashcan.contents.indexOf(textBlock) != -1) { + return; + } + trashcan.contents.unshift(textBlock); + if (trashcan.contents.length > trashcan.MAX_CONTENTS) { + trashcan.contents.splice(trashcan.MAX_CONTENTS, + trashcan.contents.length - trashcan.MAX_CONTENTS); + } + + trashcan.hasBlocks = true; + trashcan.minOpenness_ = trashcan.HAS_BLOCKS_LID_ANGLE; + trashcan.setLidAngle_(trashcan.minOpenness_); + } + }; +}; + +/** + * Converts xml representing a block into text that can be stored in the + * content array. + * @param {!Element} xml An XML tree defining the block and any + * connected child blocks. + * @returns {string} The XML tree converted into a usable text string. + */ +Blockly.Trashcan.prototype.blockXmlToText = function(xml) { + var xmlBlock = xml.cloneNode(true); + Blockly.Xml.deleteNext(xmlBlock); + xmlBlock.removeAttribute('x'); + xmlBlock.removeAttribute('y'); + xmlBlock.removeAttribute('id'); + return '' + Blockly.Xml.domToText(xmlBlock) + ''; }; diff --git a/core/workspace_svg.js b/core/workspace_svg.js index 7484650e8..c0ab970c7 100644 --- a/core/workspace_svg.js +++ b/core/workspace_svg.js @@ -466,13 +466,6 @@ Blockly.WorkspaceSvg.prototype.createDom = function(opt_backgroundClass) { /** @type {SVGElement} */ this.svgBubbleCanvas_ = Blockly.utils.createSvgElement('g', {'class': 'blocklyBubbleCanvas'}, this.svgGroup_); - var bottom = Blockly.Scrollbar.scrollbarThickness; - if (this.options.hasTrashcan) { - bottom = this.addTrashcan_(bottom); - } - if (this.options.zoomOptions && this.options.zoomOptions.controls) { - this.addZoomControls_(bottom); - } if (!this.isFlyout) { Blockly.bindEventWithChecks_(this.svgGroup_, 'mousedown', this, @@ -582,30 +575,24 @@ Blockly.WorkspaceSvg.prototype.newBlock = function(prototypeName, opt_id) { /** * Add a trashcan. - * @param {number} bottom Distance from workspace bottom to bottom of trashcan. - * @return {number} Distance from workspace bottom to the top of trashcan. * @private */ -Blockly.WorkspaceSvg.prototype.addTrashcan_ = function(bottom) { +Blockly.WorkspaceSvg.prototype.addTrashcan_ = function() { /** @type {Blockly.Trashcan} */ this.trashcan = new Blockly.Trashcan(this); var svgTrashcan = this.trashcan.createDom(); - this.svgGroup_.insertBefore(svgTrashcan, this.svgBlockCanvas_); - return this.trashcan.init(bottom); + this.svgGroup_.insertBefore(svgTrashcan, this.svgBlockCanvas_).nextSibling; }; /** * Add zoom controls. - * @param {number} bottom Distance from workspace bottom to bottom of controls. - * @return {number} Distance from workspace bottom to the top of controls. * @private */ -Blockly.WorkspaceSvg.prototype.addZoomControls_ = function(bottom) { +Blockly.WorkspaceSvg.prototype.addZoomControls_ = function() { /** @type {Blockly.ZoomControls} */ this.zoomControls_ = new Blockly.ZoomControls(this); var svgZoomControls = this.zoomControls_.createDom(); this.svgGroup_.appendChild(svgZoomControls); - return this.zoomControls_.init(bottom); }; /** diff --git a/core/zoom_controls.js b/core/zoom_controls.js index 09ffe934c..3ab7d208a 100644 --- a/core/zoom_controls.js +++ b/core/zoom_controls.js @@ -132,6 +132,9 @@ Blockly.ZoomControls.prototype.dispose = function() { * Move the zoom controls to the bottom-right corner. */ Blockly.ZoomControls.prototype.position = function() { + if (!this.bottom_) { + return; + } var metrics = this.workspace_.getMetrics(); if (!metrics) { // There are no metrics available (workspace is probably not visible). From 31daf37922e8b82c2fc9c4944fe0bd9b6f20adec Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Mon, 10 Dec 2018 16:43:18 -0800 Subject: [PATCH 2/5] Fixed lid angle not being set property through events. --- core/trashcan.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/trashcan.js b/core/trashcan.js index 47238d46e..88d11fa57 100644 --- a/core/trashcan.js +++ b/core/trashcan.js @@ -459,7 +459,7 @@ Blockly.Trashcan.prototype.onDelete_ = function() { trashcan.hasBlocks = true; trashcan.minOpenness_ = trashcan.HAS_BLOCKS_LID_ANGLE; - trashcan.setLidAngle_(trashcan.minOpenness_); + trashcan.setLidAngle_(trashcan.minOpenness_ * 45); } }; }; From 5f2d5df3212266df67dafc9375ea80820467f021 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Tue, 11 Dec 2018 16:46:24 -0800 Subject: [PATCH 3/5] Fixed nits. Changed contents to store XML. Added removing IDs from all descendants. Removed deleteNext. --- core/inject.js | 4 +-- core/trashcan.js | 77 ++++++++++++++++++++++++++++++------------- core/workspace_svg.js | 10 +++--- core/zoom_controls.js | 1 + 4 files changed, 62 insertions(+), 30 deletions(-) diff --git a/core/inject.js b/core/inject.js index aba6c196d..04d3c3e74 100644 --- a/core/inject.js +++ b/core/inject.js @@ -219,10 +219,10 @@ Blockly.createMainWorkspace_ = function(svg, options, blockDragSurface, Blockly.utils.insertAfter(flyout, svg); } if (options.hasTrashcan) { - mainWorkspace.addTrashcan_(); + mainWorkspace.addTrashcan(); } if (options.zoomOptions && options.zoomOptions.controls) { - mainWorkspace.addZoomControls_(); + mainWorkspace.addZoomControls(); } // A null translation will also apply the correct initial scale. diff --git a/core/trashcan.js b/core/trashcan.js index 88d11fa57..812ed4fae 100644 --- a/core/trashcan.js +++ b/core/trashcan.js @@ -121,6 +121,7 @@ Blockly.Trashcan.prototype.HAS_BLOCKS_LID_ANGLE = 0.1; * The maximum number of blocks that can go in the trashcan's flyout. '0' turns * turns off trashcan contents, 'Infinity' sets it to unlimited. * @type {number} + * @private */ Blockly.Trashcan.prototype.MAX_CONTENTS = 32; @@ -134,20 +135,23 @@ Blockly.Trashcan.prototype.isOpen = false; * The minimum openness of the lid. Used to indicate if the trashcan contains * blocks. * @type {number} + * @private */ Blockly.Trashcan.prototype.minOpenness_ = 0; /** * True if the trashcan contains blocks, otherwise false. * @type {boolean} + * @private */ -Blockly.Trashcan.prototype.hasBlocks = false; +Blockly.Trashcan.prototype.hasBlocks_ = false; /** * A list of Xml representing blocks "inside" the trashcan. * @type {Array} + * @private */ -Blockly.Trashcan.prototype.contents = []; +Blockly.Trashcan.prototype.contents_ = []; /** * The SVG group containing the trash can. @@ -296,6 +300,7 @@ Blockly.Trashcan.prototype.dispose = function() { * Move the trash can to the bottom-right corner. */ Blockly.Trashcan.prototype.position = function() { + // Not yet initialized. if (!this.bottom_) { return; } @@ -402,15 +407,11 @@ Blockly.Trashcan.prototype.close = function() { * Inspect the contents of the trash. */ Blockly.Trashcan.prototype.click = function() { - if (!this.hasBlocks) { + if (!this.hasBlocks_) { return; } - var xml = []; - for (var i = 0, text; text = this.contents[i]; i++) { - xml[i] = Blockly.Xml.textToDom(text).firstChild; - } - this.flyout_.show(xml); + this.flyout_.show(this.contents_); }; /** @@ -418,7 +419,7 @@ Blockly.Trashcan.prototype.click = function() { * @private */ Blockly.Trashcan.prototype.mouseOver_ = function() { - if (!this.hasBlocks) { + if (!this.hasBlocks_) { return; } this.setOpen_(true); @@ -447,17 +448,21 @@ Blockly.Trashcan.prototype.onDelete_ = function() { return; } if (event.type == Blockly.Events.BLOCK_DELETE) { - var textBlock = trashcan.blockXmlToText(event.oldXml); - if (trashcan.contents.indexOf(textBlock) != -1) { + var cleanedXML = trashcan.cleanBlockXML_(event.oldXml); + console.log('cleaned XML:'); + console.log(cleanedXML); + if (trashcan.contents_.indexOf(cleanedXML) != -1) { return; } - trashcan.contents.unshift(textBlock); - if (trashcan.contents.length > trashcan.MAX_CONTENTS) { - trashcan.contents.splice(trashcan.MAX_CONTENTS, - trashcan.contents.length - trashcan.MAX_CONTENTS); + trashcan.contents_.unshift(cleanedXML); + console.log('added to contents: '); + console.log(trashcan.contents_); + if (trashcan.contents_.length > trashcan.MAX_CONTENTS) { + trashcan.contents_.splice(trashcan.MAX_CONTENTS, + trashcan.contents_.length - trashcan.MAX_CONTENTS); } - trashcan.hasBlocks = true; + trashcan.hasBlocks_ = true; trashcan.minOpenness_ = trashcan.HAS_BLOCKS_LID_ANGLE; trashcan.setLidAngle_(trashcan.minOpenness_ * 45); } @@ -469,13 +474,39 @@ Blockly.Trashcan.prototype.onDelete_ = function() { * content array. * @param {!Element} xml An XML tree defining the block and any * connected child blocks. - * @returns {string} The XML tree converted into a usable text string. + * @returns {!Element} The XML tree cleaned of all unnecessary attributes. + * @private */ -Blockly.Trashcan.prototype.blockXmlToText = function(xml) { +Blockly.Trashcan.prototype.cleanBlockXML_ = function(xml) { var xmlBlock = xml.cloneNode(true); - Blockly.Xml.deleteNext(xmlBlock); - xmlBlock.removeAttribute('x'); - xmlBlock.removeAttribute('y'); - xmlBlock.removeAttribute('id'); - return '' + Blockly.Xml.domToText(xmlBlock) + ''; + var block = xmlBlock; + while (block) { + // Things like text inside tags are still treated as nodes, but they + // don't have attributes (or the removeAttribute function) so we can + // skip removing attributes from them. + if (block.removeAttribute) { + block.removeAttribute('x'); + block.removeAttribute('y'); + block.removeAttribute('id'); + } + + // Try to traverse down the tree + var nextBlock = block.firstChild || block.nextSibling; + // If we can't go down, try to traverse back up the tree. + if (!nextBlock) { + nextBlock = block.parentNode; + while (nextBlock) { + // We are valid again! + if (nextBlock.nextSibling) { + nextBlock = nextBlock.nextSibling; + break; + } + // Try going up again. If parentNode is null that means we have + // reached the top, and we will break out of both loops. + nextBlock = nextBlock.parentNode; + } + } + block = nextBlock; + } + return xmlBlock; }; diff --git a/core/workspace_svg.js b/core/workspace_svg.js index c0ab970c7..0ea797bae 100644 --- a/core/workspace_svg.js +++ b/core/workspace_svg.js @@ -575,20 +575,20 @@ Blockly.WorkspaceSvg.prototype.newBlock = function(prototypeName, opt_id) { /** * Add a trashcan. - * @private + * @package */ -Blockly.WorkspaceSvg.prototype.addTrashcan_ = function() { +Blockly.WorkspaceSvg.prototype.addTrashcan = function() { /** @type {Blockly.Trashcan} */ this.trashcan = new Blockly.Trashcan(this); var svgTrashcan = this.trashcan.createDom(); - this.svgGroup_.insertBefore(svgTrashcan, this.svgBlockCanvas_).nextSibling; + this.svgGroup_.insertBefore(svgTrashcan, this.svgBlockCanvas_); }; /** * Add zoom controls. - * @private + * @package */ -Blockly.WorkspaceSvg.prototype.addZoomControls_ = function() { +Blockly.WorkspaceSvg.prototype.addZoomControls = function() { /** @type {Blockly.ZoomControls} */ this.zoomControls_ = new Blockly.ZoomControls(this); var svgZoomControls = this.zoomControls_.createDom(); diff --git a/core/zoom_controls.js b/core/zoom_controls.js index 3ab7d208a..952a1b610 100644 --- a/core/zoom_controls.js +++ b/core/zoom_controls.js @@ -132,6 +132,7 @@ Blockly.ZoomControls.prototype.dispose = function() { * Move the zoom controls to the bottom-right corner. */ Blockly.ZoomControls.prototype.position = function() { + // Not yet initialized. if (!this.bottom_) { return; } From 39b7f95827bf16be288732febb16100066df9d9d Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Wed, 12 Dec 2018 06:50:35 -0800 Subject: [PATCH 4/5] Renamed var block to node in cleanBlockXML_. --- core/trashcan.js | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/core/trashcan.js b/core/trashcan.js index 812ed4fae..44d0dafa4 100644 --- a/core/trashcan.js +++ b/core/trashcan.js @@ -479,34 +479,34 @@ Blockly.Trashcan.prototype.onDelete_ = function() { */ Blockly.Trashcan.prototype.cleanBlockXML_ = function(xml) { var xmlBlock = xml.cloneNode(true); - var block = xmlBlock; - while (block) { + var node = xmlBlock; + while (node) { // Things like text inside tags are still treated as nodes, but they // don't have attributes (or the removeAttribute function) so we can // skip removing attributes from them. - if (block.removeAttribute) { - block.removeAttribute('x'); - block.removeAttribute('y'); - block.removeAttribute('id'); + if (node.removeAttribute) { + node.removeAttribute('x'); + node.removeAttribute('y'); + node.removeAttribute('id'); } - // Try to traverse down the tree - var nextBlock = block.firstChild || block.nextSibling; - // If we can't go down, try to traverse back up the tree. - if (!nextBlock) { - nextBlock = block.parentNode; - while (nextBlock) { + // Try to go down the tree + var nextNode = node.firstChild || node.nextSibling; + // If we can't go down, try to go back up the tree. + if (!nextNode) { + nextNode = node.parentNode; + while (nextNode) { // We are valid again! - if (nextBlock.nextSibling) { - nextBlock = nextBlock.nextSibling; + if (nextNode.nextSibling) { + nextNode = nextNode.nextSibling; break; } // Try going up again. If parentNode is null that means we have // reached the top, and we will break out of both loops. - nextBlock = nextBlock.parentNode; + nextNode = nextNode.parentNode; } } - block = nextBlock; + node = nextNode; } return xmlBlock; }; From 77ee4c8e22b41f7f127bda05833ec929829263d8 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Wed, 12 Dec 2018 15:20:12 -0800 Subject: [PATCH 5/5] Reverted to storing xml as text. --- core/trashcan.js | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/core/trashcan.js b/core/trashcan.js index 44d0dafa4..8c2c47f70 100644 --- a/core/trashcan.js +++ b/core/trashcan.js @@ -147,7 +147,7 @@ Blockly.Trashcan.prototype.minOpenness_ = 0; Blockly.Trashcan.prototype.hasBlocks_ = false; /** - * A list of Xml representing blocks "inside" the trashcan. + * A list of Xml (stored as strings) representing blocks "inside" the trashcan. * @type {Array} * @private */ @@ -411,7 +411,11 @@ Blockly.Trashcan.prototype.click = function() { return; } - this.flyout_.show(this.contents_); + var xml = []; + for (var i = 0, text; text = this.contents_[i]; i++) { + xml[i] = Blockly.Xml.textToDom(text).firstChild; + } + this.flyout_.show(xml); }; /** @@ -449,14 +453,10 @@ Blockly.Trashcan.prototype.onDelete_ = function() { } if (event.type == Blockly.Events.BLOCK_DELETE) { var cleanedXML = trashcan.cleanBlockXML_(event.oldXml); - console.log('cleaned XML:'); - console.log(cleanedXML); if (trashcan.contents_.indexOf(cleanedXML) != -1) { return; } trashcan.contents_.unshift(cleanedXML); - console.log('added to contents: '); - console.log(trashcan.contents_); if (trashcan.contents_.length > trashcan.MAX_CONTENTS) { trashcan.contents_.splice(trashcan.MAX_CONTENTS, trashcan.contents_.length - trashcan.MAX_CONTENTS); @@ -474,7 +474,8 @@ Blockly.Trashcan.prototype.onDelete_ = function() { * content array. * @param {!Element} xml An XML tree defining the block and any * connected child blocks. - * @returns {!Element} The XML tree cleaned of all unnecessary attributes. + * @returns {!string} Text representing the XML tree, cleaned of all unnecessary + * attributes. * @private */ Blockly.Trashcan.prototype.cleanBlockXML_ = function(xml) { @@ -508,5 +509,5 @@ Blockly.Trashcan.prototype.cleanBlockXML_ = function(xml) { } node = nextNode; } - return xmlBlock; + return '' + Blockly.Xml.domToText(xmlBlock) + ''; };