[WIP] Merged block, blocks, blockly, and block_svg sans instrumentation issue

This commit is contained in:
Evan W. Patton
2016-09-28 18:18:45 -04:00
parent 16d1a6b362
commit eddade9eda
11 changed files with 253 additions and 4208 deletions

View File

@@ -26,6 +26,7 @@
goog.provide('Blockly.Block');
goog.require('Blockly.Instrument'); // lyn's instrumentation code
goog.require('Blockly.Blocks');
goog.require('Blockly.Comment');
goog.require('Blockly.Connection');
@@ -1200,7 +1201,7 @@ Blockly.Block.prototype.interpolate_ = function(message, args, lastDummyAlign) {
*/
Blockly.Block.prototype.appendInput_ = function(type, name) {
var connection = null;
if (type == Blockly.INPUT_VALUE || type == Blockly.NEXT_STATEMENT) {
if (type == Blockly.INPUT_VALUE || type == Blockly.NEXT_STATEMENT || type == Blockly.INDENTED_VALUE) {
connection = this.makeConnection_(type);
}
var input = new Blockly.Input(type, name, this, connection);

File diff suppressed because it is too large Load Diff

View File

@@ -1,510 +0,0 @@
***************
*** 26,40 ****
goog.provide('Blockly.Block');
goog.require('Blockly.BlockSvg');
goog.require('Blockly.Blocks');
goog.require('Blockly.Comment');
goog.require('Blockly.Connection');
goog.require('Blockly.ContextMenu');
goog.require('Blockly.Input');
goog.require('Blockly.Msg');
goog.require('Blockly.Mutator');
goog.require('Blockly.Warning');
goog.require('Blockly.Workspace');
goog.require('Blockly.Xml');
goog.require('goog.Timer');
--- 26,43 ----
goog.provide('Blockly.Block');
+ goog.require('Blockly.Instrument'); // lyn's instrumentation code
goog.require('Blockly.BlockSvg');
goog.require('Blockly.Blocks');
goog.require('Blockly.Comment');
goog.require('Blockly.Connection');
goog.require('Blockly.ContextMenu');
+ goog.require('Blockly.ErrorIcon');
goog.require('Blockly.Input');
goog.require('Blockly.Msg');
goog.require('Blockly.Mutator');
goog.require('Blockly.Warning');
+ goog.require('Blockly.WarningHandler');
goog.require('Blockly.Workspace');
goog.require('Blockly.Xml');
goog.require('goog.Timer');
***************
*** 149,154 ****
this.workspace = workspace;
this.isInFlyout = workspace.isFlyout;
// Copy the type-specific functions and data from the prototype.
if (prototypeName) {
--- 152,159 ----
this.workspace = workspace;
this.isInFlyout = workspace.isFlyout;
+ // This is missing from our latest version
+ //workspace.addTopBlock(this);
// Copy the type-specific functions and data from the prototype.
if (prototypeName) {
***************
*** 202,207 ****
Blockly.Block.prototype.warning = null;
/**
* Returns a list of mutator, comment, and warning icons.
* @return {!Array} List of icons.
*/
--- 212,223 ----
Blockly.Block.prototype.warning = null;
/**
+ * Block's error icon (if any).
+ * @type {Blockly.ErrorIcon}
+ */
+ Blockly.Block.prototype.errorIcon = null;
+
+ /**
* Returns a list of mutator, comment, and warning icons.
* @return {!Array} List of icons.
*/
***************
*** 216,221 ****
if (this.warning) {
icons.push(this.warning);
}
return icons;
};
--- 232,240 ----
if (this.warning) {
icons.push(this.warning);
}
+ if (this.errorIcon) {
+ icons.push(this.errorIcon);
+ }
return icons;
};
***************
*** 374,379 ****
for (var x = 0; x < icons.length; x++) {
icons[x].dispose();
}
// Dispose of all inputs and their fields.
for (var x = 0, input; input = this.inputList[x]; x++) {
input.dispose();
--- 393,402 ----
for (var x = 0; x < icons.length; x++) {
icons[x].dispose();
}
+ if (this.errorIcon) {
+ this.errorIcon.dispose();
+ }
+
// Dispose of all inputs and their fields.
for (var x = 0, input; input = this.inputList[x]; x++) {
input.dispose();
***************
*** 448,464 ****
* @return {!Object} Object with height and width properties.
*/
Blockly.Block.prototype.getHeightWidth = function() {
var height = this.svg_.height;
var width = this.svg_.width;
// Recursively add size of subsequent blocks.
var nextBlock = this.getNextBlock();
if (nextBlock) {
- var nextHeightWidth = nextBlock.getHeightWidth();
height += nextHeightWidth.height - 4; // Height of tab.
width = Math.max(width, nextHeightWidth.width);
}
return {height: height, width: width};
- };
/**
* Handle a mouse-down on an SVG block.
--- 473,534 ----
* @return {!Object} Object with height and width properties.
*/
Blockly.Block.prototype.getHeightWidth = function() {
+ var start = new Date().getTime();
+ var result;
+ if (Blockly.Instrument.useNeilGetHeightWidthFix) {
+ result = this.getHeightWidthNeil();
+ } else {
+ // Old inexplicably quadratic version of getHeightWidth
+ // The quadratic nature has something to do with getBBox that Lyn
+ // and others never figured out.
+ try {
+ // var bBox = this.getSvgRoot().getBBox();
+ var root = this.getSvgRoot(); //***lyn
+ var bBox = root.getBBox(); //***lyn
+ var height = bBox.height;
+
+ } catch (e) {
+ // Firefox has trouble with hidden elements (Bug 528969).
+ return {height: 0, width: 0};
+ }
+ if (Blockly.BROKEN_CONTROL_POINTS) {
+ /* HACK:
+ WebKit bug 67298 causes control points to be included in the reported
+ bounding box. The render functions (below) add two 5px spacer control
+ points that we need to subtract.
+ */
+ height -= 10;
+ if (this.nextConnection) {
+ // Bottom control point partially masked by lower tab.
+ height += 4;
+ }
+ }
+ // Subtract one from the height due to the shadow.
+ height -= 1;
+ result = {height: height, width: bBox.width}; //Why is width handled differently here
+ }
+ var stop = new Date().getTime();
+ var timeDiff = stop - start;
+ Blockly.Instrument.stats.getHeightWidthCalls++;
+ Blockly.Instrument.stats.getHeightWidthTime += timeDiff;
+ return result;
+ };
+
+ /**
+ * Neil's getHeightWidth
+ */
+ Blockly.Block.prototype.getHeightWidthNeil = function() {
var height = this.svg_.height;
var width = this.svg_.width;
// Recursively add size of subsequent blocks.
var nextBlock = this.getNextBlock();
if (nextBlock) {
+ var nextHeightWidth = nextBlock.getHeightWidthNeil();
height += nextHeightWidth.height - 4; // Height of tab.
width = Math.max(width, nextHeightWidth.width);
}
return {height: height, width: width};
+ }
/**
* Handle a mouse-down on an SVG block.
***************
*** 474,480 ****
* @private
*/
Blockly.Block.prototype.onMouseUp_ = function(e) {
var this_ = this;
Blockly.doCommand(function() {
Blockly.terminateDrag_();
if (Blockly.selected && Blockly.highlightedConnection_) {
--- 549,558 ----
* @private
*/
Blockly.Block.prototype.onMouseUp_ = function(e) {
+ var start = new Date().getTime();
+ Blockly.Instrument.initializeStats("onMouseUp");
var this_ = this;
+ Blockly.resetWorkspaceArrangements();
Blockly.doCommand(function() {
Blockly.terminateDrag_();
if (Blockly.selected && Blockly.highlightedConnection_) {
***************
*** 509,514 ****
Blockly.highlightedConnection_ = null;
}
});
};
/**
--- 587,602 ----
Blockly.highlightedConnection_ = null;
}
});
+ if (! Blockly.Instrument.avoidRenderWorkspaceInMouseUp) {
+ // [lyn, 04/01/14] rendering a workspace takes a *long* time and is *not* necessary!
+ // This is the key source of the laggy drag problem. Remove it!
+ Blockly.mainWorkspace.render();
+ }
+ Blockly.WarningHandler.checkAllBlocksForWarningsAndErrors();
+ var stop = new Date().getTime();
+ var timeDiff = stop - start;
+ Blockly.Instrument.stats.totalTime = timeDiff;
+ Blockly.Instrument.displayStats("onMouseUp");
};
/**
***************
*** 833,850 ****
/**
* Get the colour of a block.
- * @return {number} HSV hue value.
*/
Blockly.Block.prototype.getColour = function() {
- return this.colourHue_;
};
/**
* Change the colour of a block.
- * @param {number} colourHue HSV hue value.
*/
- Blockly.Block.prototype.setColour = function(colourHue) {
- this.colourHue_ = colourHue;
if (this.svg_) {
this.svg_.updateColour();
}
--- 924,954 ----
/**
* Get the colour of a block.
+ * @return {number|Array} HSV hue value or RGB Array.
*/
Blockly.Block.prototype.getColour = function() {
+ return (this.rgbArray_ == null ? this.colourHue_ : this.rgbArray_);
};
/**
* Change the colour of a block.
+ * @param {number|Array} hueOrRGBArray HSV hue value or array of RGB values.
*/
+ Blockly.Block.prototype.setColour = function(hueOrRGBArray) {
+ if(Array.isArray(hueOrRGBArray)) {
+ this.rgbArray_ = hueOrRGBArray;
+ this.colourHue_ = null;
+ } else {
+ this.colourHue_ = hueOrRGBArray;
+ this.rgbArray_ = null;
+ }
+ this.updateColour();
+ };
+
+ /**
+ * Update the colour of a block.
+ */
+ Blockly.Block.prototype.updateColour = function() {
if (this.svg_) {
this.svg_.updateColour();
}
***************
*** 852,857 ****
for (var x = 0; x < icons.length; x++) {
icons[x].updateColour();
}
if (this.rendered) {
// Bump every dropdown to change its colour.
for (var x = 0, input; input = this.inputList[x]; x++) {
--- 956,964 ----
for (var x = 0; x < icons.length; x++) {
icons[x].updateColour();
}
+ if (this.errorIcon) {
+ this.errorIcon.updateColour();
+ }
if (this.rendered) {
// Bump every dropdown to change its colour.
for (var x = 0, input; input = this.inputList[x]; x++) {
***************
*** 1095,1105 ****
if (this.collapsed_ == collapsed) {
return;
}
this.collapsed_ = collapsed;
var renderList = [];
// Show/hide the inputs.
- for (var x = 0, input; input = this.inputList[x]; x++) {
renderList.push.apply(renderList, input.setVisible(!collapsed));
}
var COLLAPSED_INPUT_NAME = '_TEMP_COLLAPSED_INPUT';
--- 1202,1225 ----
if (this.collapsed_ == collapsed) {
return;
}
+ var start = new Date().getTime();
this.collapsed_ = collapsed;
var renderList = [];
+ // //Prepare the string for collapsing if needed
+ // if (collapsed){
+ // if (this.prepareCollapsedText && goog.isFunction(this.prepareCollapsedText))
+ // this.prepareCollapsedText();
+ // }
// Show/hide the inputs.
+ if (Blockly.Instrument.useRenderDown) {
+ for (var x = 0, input; input = this.inputList[x]; x++) {
+ // No need to collect renderList if rendering down.
+ input.setVisible(!collapsed);
+ }
+ } else {
+ for (var x = 0, input; input = this.inputList[x]; x++) {
renderList.push.apply(renderList, input.setVisible(!collapsed));
+ }
}
var COLLAPSED_INPUT_NAME = '_TEMP_COLLAPSED_INPUT';
***************
*** 1108,1113 ****
for (var x = 0; x < icons.length; x++) {
icons[x].setVisible(false);
}
var text = this.toString(Blockly.COLLAPSE_CHARS);
this.appendDummyInput(COLLAPSED_INPUT_NAME).appendField(text);
} else {
--- 1228,1236 ----
for (var x = 0; x < icons.length; x++) {
icons[x].setVisible(false);
}
+ if (this.errorIcon) {
+ this.errorIcon.setVisible(false);
+ }
var text = this.toString(Blockly.COLLAPSE_CHARS);
this.appendDummyInput(COLLAPSED_INPUT_NAME).appendField(text);
} else {
***************
*** 1118,1129 ****
// No child blocks, just render this block.
renderList[0] = this;
}
if (this.rendered) {
- for (var x = 0, block; block = renderList[x]; x++) {
- block.render();
}
this.bumpNeighbours_();
}
};
/**
--- 1241,1264 ----
// No child blocks, just render this block.
renderList[0] = this;
}
+
if (this.rendered) {
+ if (Blockly.Instrument.useRenderDown) {
+ this.renderDown();
+ } else {
+ for (var x = 0, block; block = renderList[x]; x++) {
+ block.render();
+ }
}
this.bumpNeighbours_();
}
+
+ var stop = new Date().getTime();
+ var timeDiff = stop - start;
+ if (! collapsed) {
+ Blockly.Instrument.stats.expandCollapsedCalls++;
+ Blockly.Instrument.stats.expandCollapsedTime += timeDiff;
+ }
};
/**
***************
*** 1174,1180 ****
*/
Blockly.Block.prototype.appendInput_ = function(type, name) {
var connection = null;
- if (type == Blockly.INPUT_VALUE || type == Blockly.NEXT_STATEMENT) {
connection = new Blockly.Connection(this, type);
}
var input = new Blockly.Input(type, name, this, connection);
--- 1320,1326 ----
*/
Blockly.Block.prototype.appendInput_ = function(type, name) {
var connection = null;
+ if (type == Blockly.INPUT_VALUE || type == Blockly.NEXT_STATEMENT || type == Blockly.INDENTED_VALUE) {
connection = new Blockly.Connection(this, type);
}
var input = new Blockly.Input(type, name, this, connection);
***************
*** 1389,1400 ****
};
/**
* Render the block.
* Lays out and reflows a block based on its contents and settings.
*/
Blockly.Block.prototype.render = function() {
- goog.asserts.assertObject(this.svg_,
- 'Uninitialized block cannot be rendered. Call block.initSvg()');
- this.svg_.render();
- Blockly.Realtime.blockChanged(this);
};
--- 1535,1609 ----
};
/**
+ * Set this block's warning text.
+ * @param {?string} text The text, or null to delete.
+ */
+ Blockly.Block.prototype.setErrorIconText = function(text) {
+ if (!Blockly.ErrorIcon) {
+ throw 'Warnings not supported.';
+ }
+ var changedState = false;
+ if (goog.isString(text)) {
+ if (!this.errorIcon) {
+ this.errorIcon = new Blockly.ErrorIcon(this);
+ changedState = true;
+ }
+ this.errorIcon.setText(/** @type {string} */ (text));
+ } else {
+ if (this.errorIcon) {
+ this.errorIcon.dispose();
+ changedState = true;
+ }
+ }
+ if (this.rendered) {
+ this.render();
+ if (changedState) {
+ // Adding or removing a warning icon will cause the block to change shape.
+ this.bumpNeighbours_();
+ }
+ }
+ };
+
+ /**
+ * [lyn, 04/01/14] Global flag to control whether rendering is done.
+ * There is no need to render blocks in Blocky.SaveFile.load.
+ * We only need to render them when a Screen is loaded in the Blockly editor.
+ * This flag is used to turn off rendering for first case and turn it on for the second.
+ * @type {boolean}
+ */
+ Blockly.Block.isRenderingOn = true;
+
+ /**
* Render the block.
* Lays out and reflows a block based on its contents and settings.
*/
Blockly.Block.prototype.render = function() {
+ if (Blockly.Block.isRenderingOn) {
+ goog.asserts.assertObject(this.svg_,
+ 'Uninitialized block cannot be rendered. Call block.initSvg()');
+ this.svg_.render();
+ if (Blockly.Realtime.isEnabled() && !Blockly.Realtime.withinSync) {
+ Blockly.Realtime.blockChanged(this);
+ }
+ Blockly.Instrument.stats.renderCalls++;
+ // [lyn, 04/08/14] Because render is recursive, doesn't make sense to track its time here.
+ }
+ };
+
+ /**
+ * [lyn, 04/01/14] Render a tree of blocks from top down rather than bottom up.
+ * This is in contrast to render(), which renders a block and all its antecedents.
+ */
+ Blockly.Block.prototype.renderDown = function() {
+ if (Blockly.Block.isRenderingOn) {
+ goog.asserts.assertObject(this.svg_,
+ ' Uninitialized block cannot be renderedDown. Call block.initSvg()');
+ this.svg_.renderDown();
+ Blockly.Instrument.stats.renderDownCalls++; //***lyn
+ if (Blockly.Realtime.isEnabled() && !Blockly.Realtime.withinSync) {
+ Blockly.Realtime.blockChanged(this);
+ }
+ }
+ // [lyn, 04/08/14] Because renderDown is recursive, doesn't make sense to track its time here.
};
+

View File

@@ -263,6 +263,49 @@ Blockly.BlockSvg.prototype.render = function(opt_bubble) {
Blockly.Field.startCache();
this.rendered = true;
this.renderHere();
// Render all blocks above this one (propagate a reflow).
var parentBlock = this.getParent();
if (parentBlock) {
parentBlock.render();
}
Blockly.Field.stopCache();
};
/**
* [lyn, 04/01/14] Render a tree of blocks.
* In general, this is more efficient than calling render() on all the leaves of the tree,
* because that will:
* (1) repeat the rendering of all internal nodes; and
* (2) will unnecessarily call Blockly.fireUiEvent(window, 'resize') in the
* case where the parentPointer hasn't been set yet (particularly for
* value, statement, and next connections in Xml.domToBlock).
* These two factors account for much of the slow project loading times in Blockly
* and previous versions of AI2.
*/
Blockly.BlockSvg.prototype.renderDown = function() {
this.rendered = true;
// Recursively renderDown all my children (as long as I'm not collapsed)
if (! (Blockly.Instrument.avoidRenderDownOnCollapsedSubblocks && this.isCollapsed())) {
var childBlocks = this.childBlocks_;
for (var c = 0, childBlock; childBlock = childBlocks[c]; c++) {
childBlock.renderDown();
}
}
// Render me after all my children have been rendered.
this.renderHere();
};
/**
* Render this block. Assumes descendants have already been rendered.
*/
Blockly.BlockSvg.prototype.renderHere = function() {
var start = new Date().getTime();
// Now render me (even if I am collapsed, since still need to show collapsed block)
var cursorX = Blockly.BlockSvg.SEP_SPACE_X;
if (this.RTL) {
cursorX = -cursorX;
@@ -282,16 +325,16 @@ Blockly.BlockSvg.prototype.render = function(opt_bubble) {
this.renderMoveConnections_();
if (opt_bubble !== false) {
// Render all blocks above this one (propagate a reflow).
var parentBlock = this.getParent();
if (parentBlock) {
parentBlock.render(true);
} else {
if (!parentBlock) {
// Top-most block. Fire an event to allow scrollbars to resize.
this.workspace.resizeContents();
}
}
Blockly.Field.stopCache();
var stop = new Date().getTime();
var timeDiff = stop - start;
Blockly.Instrument.stats.renderHereCalls++;
Blockly.Instrument.stats.renderHereTime += timeDiff;
};
/**
@@ -368,6 +411,9 @@ Blockly.BlockSvg.prototype.renderCompute_ = function(iconWidth) {
row = [];
if (isInline && input.type != Blockly.NEXT_STATEMENT) {
row.type = Blockly.BlockSvg.INLINE;
} else if (input.subtype) {
row.type = input.type;
row.subtype = input.subtype;
} else {
row.type = input.type;
}
@@ -758,9 +804,37 @@ Blockly.BlockSvg.prototype.renderDrawRight_ = function(steps, highlightSteps,
}
}
this.renderFields_(input.fieldRow, fieldX, fieldY);
steps.push(Blockly.BlockSvg.TAB_PATH_DOWN);
var v = row.height - Blockly.BlockSvg.TAB_HEIGHT;
steps.push('v', v);
if (row.subtype == Blockly.INDENTED_VALUE){
cursorX = inputRows.statementEdge;
steps.push('H', cursorX+input.fieldWidth+8);
steps.push(Blockly.BlockSvg.TAB_PATH_DOWN);
steps.push('V',cursorY+row.height);
steps.push('H', inputRows.rightEdge);
steps.push('v 8');
if (this.RTL) {
highlightSteps.push('M',
(cursorX - Blockly.BlockSvg.NOTCH_WIDTH +
Blockly.BlockSvg.DISTANCE_45_OUTSIDE) +
',' + (cursorY + Blockly.BlockSvg.DISTANCE_45_OUTSIDE));
highlightSteps.push(
Blockly.BlockSvg.INNER_TOP_LEFT_CORNER_HIGHLIGHT_RTL);
highlightSteps.push('v',
row.height - 2 * Blockly.BlockSvg.CORNER_RADIUS);
highlightSteps.push(
Blockly.BlockSvg.INNER_BOTTOM_LEFT_CORNER_HIGHLIGHT_RTL);
highlightSteps.push('H', inputRows.rightEdge - 1);
} else {
highlightSteps.push('M',
(cursorX + 9 + input.fieldWidth) + ',' +
(cursorY + row.height));
highlightSteps.push('H', inputRows.rightEdge);
}
cursorY+=8;
} else {
steps.push(Blockly.BlockSvg.TAB_PATH_DOWN);
var v = row.height - Blockly.BlockSvg.TAB_HEIGHT
steps.push('v', v);
}
if (this.RTL) {
// Highlight around back of tab.
highlightSteps.push(Blockly.BlockSvg.TAB_PATH_DOWN_HIGHLIGHT_RTL);
@@ -773,8 +847,15 @@ Blockly.BlockSvg.prototype.renderDrawRight_ = function(steps, highlightSteps,
',-2.1');
}
// Create external input connection.
connectionX = this.RTL ? -inputRows.rightEdge - 1 :
inputRows.rightEdge + 1;
if (row.subtype == Blockly.INDENTED_VALUE) {
connectionX = connectionsXY.x +
(this.RTL ? -inputRows.statementEdge - 1: inputRows.statementEdge + 9 + input.fieldWidth);
connectionY = connectionsXY.y + cursorY-8;
} else {
connectionX = connectionsXY.x +
(this.RTL ? -inputRows.rightEdge - 1: inputRows.rightEdge + 1);
connectionY = connectionsXY.y + cursorY;
}
input.connection.setOffsetInBlock(connectionX, cursorY);
if (input.connection.isConnected()) {
this.width = Math.max(this.width, inputRows.rightEdge +

File diff suppressed because it is too large Load Diff

View File

@@ -1,231 +0,0 @@
***************
*** 26,31 ****
goog.provide('Blockly.BlockSvg');
goog.require('goog.userAgent');
--- 26,32 ----
goog.provide('Blockly.BlockSvg');
+ goog.require('Blockly.Instrument'); // lyn's instrumentation code
goog.require('goog.userAgent');
***************
*** 154,167 ****
* @const
*/
Blockly.BlockSvg.DISTANCE_45_INSIDE = (1 - Math.SQRT1_2) *
- (Blockly.BlockSvg.CORNER_RADIUS - 1) + 1;
/**
* Distance from shape edge to intersect with a curved corner at 45 degrees.
* Applies to highlighting on around the outside of a curve.
* @const
*/
Blockly.BlockSvg.DISTANCE_45_OUTSIDE = (1 - Math.SQRT1_2) *
- (Blockly.BlockSvg.CORNER_RADIUS + 1) - 1;
/**
* SVG path for drawing next/previous notch from left to right.
* @const
--- 155,168 ----
* @const
*/
Blockly.BlockSvg.DISTANCE_45_INSIDE = (1 - Math.SQRT1_2) *
+ (Blockly.BlockSvg.CORNER_RADIUS - 1) + 1;
/**
* Distance from shape edge to intersect with a curved corner at 45 degrees.
* Applies to highlighting on around the outside of a curve.
* @const
*/
Blockly.BlockSvg.DISTANCE_45_OUTSIDE = (1 - Math.SQRT1_2) *
+ (Blockly.BlockSvg.CORNER_RADIUS + 1) - 1;
/**
* SVG path for drawing next/previous notch from left to right.
* @const
***************
*** 483,488 ****
Blockly.BlockSvg.prototype.render = function() {
this.block_.rendered = true;
var cursorX = Blockly.BlockSvg.SEP_SPACE_X;
if (Blockly.RTL) {
cursorX = -cursorX;
--- 484,530 ----
Blockly.BlockSvg.prototype.render = function() {
this.block_.rendered = true;
+ this.renderHere();
+
+ // Render all blocks above this one (propagate a reflow).
+ var parentBlock = this.block_.getParent();
+ if (parentBlock) {
+ parentBlock.render();
+ }
+ };
+
+ /**
+ * [lyn, 04/01/14] Render a tree of blocks.
+ * In general, this is more efficient than calling render() on all the leaves of the tree,
+ * because that will:
+ * (1) repeat the rendering of all internal nodes; and
+ * (2) will unnecessarily call Blockly.fireUiEvent(window, 'resize') in the
+ * case where the parentPointer hasn't been set yet (particularly for
+ * value, statement, and next connections in Xml.domToBlock).
+ * These two factors account for much of the slow project loading times in Blockly
+ * and previous versions of AI2.
+ */
+ Blockly.BlockSvg.prototype.renderDown = function() {
+ this.block_.rendered = true;
+
+ // Recursively renderDown all my children (as long as I'm not collapsed)
+ if (! (Blockly.Instrument.avoidRenderDownOnCollapsedSubblocks && this.block_.isCollapsed())) {
+ var childBlocks = this.block_.childBlocks_;
+ for (var c = 0, childBlock; childBlock = childBlocks[c]; c++) {
+ childBlock.renderDown();
+ }
+ }
+
+ // Render me after all my children have been rendered.
+ this.renderHere();
+ };
+
+ /**
+ * Render this block. Assumes descendants have already been rendered.
+ */
+ Blockly.BlockSvg.prototype.renderHere = function() {
+ var start = new Date().getTime();
+ // Now render me (even if I am collapsed, since still need to show collapsed block)
var cursorX = Blockly.BlockSvg.SEP_SPACE_X;
if (Blockly.RTL) {
cursorX = -cursorX;
***************
*** 500,514 ****
var inputRows = this.renderCompute_(cursorX);
this.renderDraw_(cursorX, inputRows);
- // Render all blocks above this one (propagate a reflow).
var parentBlock = this.block_.getParent();
- if (parentBlock) {
- parentBlock.render();
- } else {
// Top-most block. Fire an event to allow scrollbars to resize.
Blockly.fireUiEvent(window, 'resize');
}
- };
/**
* Render a list of fields starting at the specified location.
--- 542,557 ----
var inputRows = this.renderCompute_(cursorX);
this.renderDraw_(cursorX, inputRows);
var parentBlock = this.block_.getParent();
+ if (!parentBlock) {
// Top-most block. Fire an event to allow scrollbars to resize.
Blockly.fireUiEvent(window, 'resize');
}
+ var stop = new Date().getTime();
+ var timeDiff = stop-start;
+ Blockly.Instrument.stats.renderHereCalls++;
+ Blockly.Instrument.stats.renderHereTime += timeDiff;
+ }
/**
* Render a list of fields starting at the specified location.
***************
*** 578,583 ****
row = [];
if (isInline && input.type != Blockly.NEXT_STATEMENT) {
row.type = Blockly.BlockSvg.INLINE;
} else {
row.type = input.type;
}
--- 621,629 ----
row = [];
if (isInline && input.type != Blockly.NEXT_STATEMENT) {
row.type = Blockly.BlockSvg.INLINE;
+ } else if (input.subtype) {
+ row.type = input.type;
+ row.subtype = input.subtype;
} else {
row.type = input.type;
}
***************
*** 924,932 ****
}
}
this.renderFields_(input.fieldRow, fieldX, fieldY);
- steps.push(Blockly.BlockSvg.TAB_PATH_DOWN);
- var v = row.height - Blockly.BlockSvg.TAB_HEIGHT
- steps.push('v', v);
if (Blockly.RTL) {
// Highlight around back of tab.
highlightSteps.push(Blockly.BlockSvg.TAB_PATH_DOWN_HIGHLIGHT_RTL);
--- 970,1006 ----
}
}
this.renderFields_(input.fieldRow, fieldX, fieldY);
+ if (row.subtype == Blockly.INDENTED_VALUE){
+ cursorX = inputRows.statementEdge;
+ steps.push('H', cursorX+input.fieldWidth+8);
+ steps.push(Blockly.BlockSvg.TAB_PATH_DOWN);
+ steps.push('V',cursorY+row.height);
+ steps.push('H', inputRows.rightEdge);
+ steps.push('v 8');
+ if (Blockly.RTL) {
+ highlightSteps.push('M',
+ (cursorX - Blockly.BlockSvg.NOTCH_WIDTH +
+ Blockly.BlockSvg.DISTANCE_45_OUTSIDE) +
+ ',' + (cursorY + Blockly.BlockSvg.DISTANCE_45_OUTSIDE));
+ highlightSteps.push(
+ Blockly.BlockSvg.INNER_TOP_LEFT_CORNER_HIGHLIGHT_RTL);
+ highlightSteps.push('v',
+ row.height - 2 * Blockly.BlockSvg.CORNER_RADIUS);
+ highlightSteps.push(
+ Blockly.BlockSvg.INNER_BOTTOM_LEFT_CORNER_HIGHLIGHT_RTL);
+ highlightSteps.push('H', inputRows.rightEdge - 1);
+ } else {
+ highlightSteps.push('M',
+ (cursorX + 9 + input.fieldWidth) + ',' +
+ (cursorY + row.height));
+ highlightSteps.push('H', inputRows.rightEdge);
+ }
+ cursorY+=8;
+ } else {
+ steps.push(Blockly.BlockSvg.TAB_PATH_DOWN);
+ var v = row.height - Blockly.BlockSvg.TAB_HEIGHT
+ steps.push('v', v);
+ }
if (Blockly.RTL) {
// Highlight around back of tab.
highlightSteps.push(Blockly.BlockSvg.TAB_PATH_DOWN_HIGHLIGHT_RTL);
***************
*** 939,947 ****
',-1.8');
}
// Create external input connection.
- connectionX = connectionsXY.x +
- (Blockly.RTL ? -inputRows.rightEdge - 1 : inputRows.rightEdge + 1);
- connectionY = connectionsXY.y + cursorY;
input.connection.moveTo(connectionX, connectionY);
if (input.connection.targetConnection) {
input.connection.tighten_();
--- 1013,1027 ----
',-1.8');
}
// Create external input connection.
+ if (row.subtype == Blockly.INDENTED_VALUE){
+ connectionX = connectionsXY.x +
+ (Blockly.RTL ? -inputRows.statementEdge - 1: inputRows.statementEdge + 9 + input.fieldWidth);
+ connectionY = connectionsXY.y + cursorY-8;
+ } else {
+ connectionX = connectionsXY.x +
+ (Blockly.RTL ? -inputRows.rightEdge - 1 : inputRows.rightEdge + 1);
+ connectionY = connectionsXY.y + cursorY;
+ }
input.connection.moveTo(connectionX, connectionY);
if (input.connection.targetConnection) {
input.connection.tighten_();

View File

@@ -269,12 +269,26 @@ Blockly.onKeyDown_ = function(e) {
Blockly.hideChaff();
} else if (e.keyCode == 8 || e.keyCode == 46) {
// Delete or backspace.
// Stop the browser from going back to the previous page.
// Do this first to prevent an error in the delete code from resulting in
// data loss.
e.preventDefault();
if (Blockly.selected && Blockly.selected.isDeletable()) {
deleteBlock = true;
try {
// Stop the browser from going back to the previous page.
// Do this first to prevent an error in the delete code from resulting in
// data loss.
e.preventDefault();
if (Blockly.selected && Blockly.selected.isDeletable()) {
var descendantCount = Blockly.selected.getDescendants().length;
if (Blockly.selected.nextConnection && Blockly.selected.nextConnection.targetConnection) {
descendantCount -= Blockly.selected.nextConnection.targetBlock().
getDescendants().length;
}
// Ask for confirmation before deleting 3 or more blocks
if (descendantCount >= 3) {
if (confirm("Are you sure you want to delete all " + descendantCount + " of these blocks?")) {
deleteBlock = true;
}
} else {
deleteBlock = true;
}
}
}
} else if (e.altKey || e.ctrlKey || e.metaKey) {
if (Blockly.selected &&

View File

@@ -1,228 +1,5 @@
***************
*** 24,32 ****
*/
'use strict';
// Top level object for Blockly.
goog.provide('Blockly');
// Blockly core dependencies.
goog.require('Blockly.Block');
goog.require('Blockly.Connection');
--- 24,38 ----
*/
'use strict';
+ /**
+ * [lyn, 10/10/13] Modified Blockly.hideChaff() method to hide single instance of Blockly.FieldFlydown.
+ */
+
// Top level object for Blockly.
goog.provide('Blockly');
+ goog.require('Blockly.Instrument'); // lyn's instrumentation code
+
// Blockly core dependencies.
goog.require('Blockly.Block');
goog.require('Blockly.Connection');
***************
*** 41,47 ****
goog.require('Blockly.Msg');
goog.require('Blockly.Procedures');
goog.require('Blockly.Realtime');
- goog.require('Blockly.Toolbox');
goog.require('Blockly.WidgetDiv');
goog.require('Blockly.Workspace');
goog.require('Blockly.inject');
--- 47,54 ----
goog.require('Blockly.Msg');
goog.require('Blockly.Procedures');
goog.require('Blockly.Realtime');
+ //goog.require('Blockly.Toolbox');
+ goog.require('Blockly.TypeBlock');
goog.require('Blockly.WidgetDiv');
goog.require('Blockly.Workspace');
goog.require('Blockly.inject');
***************
*** 99,107 ****
* @param {number} hue Hue on a colour wheel (0-360).
* @return {string} RGB code, e.g. '#5ba65b'.
*/
- Blockly.makeColour = function(hue) {
- return goog.color.hsvToHex(hue, Blockly.HSV_SATURATION,
Blockly.HSV_VALUE * 256);
};
/**
--- 106,118 ----
* @param {number} hue Hue on a colour wheel (0-360).
* @return {string} RGB code, e.g. '#5ba65b'.
*/
+ Blockly.makeColour = function(hueOrRGBArray) {
+ if(Array.isArray(hueOrRGBArray)){
+ return goog.color.rgbArrayToHex(hueOrRGBArray);
+ } else {
+ return goog.color.hsvToHex(hueOrRGBArray, Blockly.HSV_SATURATION,
Blockly.HSV_VALUE * 256);
+ }
};
/**
***************
*** 131,136 ****
Blockly.DUMMY_INPUT = 5;
/**
* ENUM for left alignment.
* @const
*/
--- 142,154 ----
Blockly.DUMMY_INPUT = 5;
/**
+ * ENUM for an indented value input. Similar to next_statement but with value
+ * input shape.
+ * @const
+ */
+ Blockly.INDENTED_VALUE = 6;
+
+ /**
* ENUM for left alignment.
* @const
*/
***************
*** 163,176 ****
};
/**
* Handle a mouse-down on SVG drawing surface.
* @param {!Event} e Mouse down event.
* @private
*/
Blockly.onMouseDown_ = function(e) {
Blockly.svgResize();
Blockly.terminateDrag_(); // In case mouse-up event was lost.
Blockly.hideChaff();
var isTargetSvg = e.target && e.target.nodeName &&
e.target.nodeName.toLowerCase() == 'svg';
if (!Blockly.readOnly && Blockly.selected && isTargetSvg) {
--- 196,237 ----
};
/**
+ * latest clicked position is used to open the type blocking suggestions window
+ * Initial position is 0,0
+ * @type {{x: number, y:number}}
+ */
+ Blockly.latestClick = { x: 0, y: 0 };
+
+ /**
* Handle a mouse-down on SVG drawing surface.
* @param {!Event} e Mouse down event.
* @private
*/
Blockly.onMouseDown_ = function(e) {
+ Blockly.latestClick = { x: e.clientX, y: e.clientY }; // Might be needed?
Blockly.svgResize();
Blockly.terminateDrag_(); // In case mouse-up event was lost.
Blockly.hideChaff();
+ //if drawer exists and supposed to close
+ if(Blockly.Drawer && Blockly.Drawer.flyout_.autoClose) {
+ Blockly.Drawer.hide();
+ }
+
+ //Closes mutators
+ var blocks = Blockly.mainWorkspace.getAllBlocks();
+ var numBlocks = blocks.length;
+ var temp_block = null;
+ for(var i =0; i<numBlocks; i++){
+ temp_block = blocks[i];
+ if(temp_block.mutator){
+ //deselect block in mutator workspace
+ if(Blockly.selected && Blockly.selected.workspace && Blockly.selected.workspace!=Blockly.mainWorkspace){
+ Blockly.selected.unselect();
+ }
+ blocks[i].mutator.setVisible(false);
+ }
+ }
+
var isTargetSvg = e.target && e.target.nodeName &&
e.target.nodeName.toLowerCase() == 'svg';
if (!Blockly.readOnly && Blockly.selected && isTargetSvg) {
***************
*** 265,272 ****
// Delete or backspace.
try {
if (Blockly.selected && Blockly.selected.isDeletable()) {
- Blockly.hideChaff();
- Blockly.selected.dispose(true, true);
}
} finally {
// Stop the browser from going back to the previous page.
--- 326,347 ----
// Delete or backspace.
try {
if (Blockly.selected && Blockly.selected.isDeletable()) {
+ var descendantCount = Blockly.selected.getDescendants().length;
+ if (Blockly.selected.nextConnection && Blockly.selected.nextConnection.targetConnection) {
+ descendantCount -= Blockly.selected.nextConnection.targetBlock().
+ getDescendants().length;
+ }
+ // Ask for confirmation before deleting 3 or more blocks
+ if (descendantCount >= 3) {
+ if (confirm("Are you sure you want to delete all " + descendantCount + " of these blocks?")) {
+ Blockly.hideChaff();
+ Blockly.selected.dispose(true, true);
+ }
+ }
+ else {
+ Blockly.hideChaff();
+ Blockly.selected.dispose(true, true);
+ }
}
} finally {
// Stop the browser from going back to the previous page.
***************
*** 363,368 ****
ms += COLLAPSE_DELAY;
}
}
};
options.push(collapseOption);
--- 438,444 ----
ms += COLLAPSE_DELAY;
}
}
+ Blockly.resetWorkspaceArrangements();
};
options.push(collapseOption);
***************
*** 370,390 ****
var expandOption = {enabled: hasCollapsedBlocks};
expandOption.text = Blockly.Msg.EXPAND_ALL;
expandOption.callback = function() {
- var ms = 0;
- for (var i = 0; i < topBlocks.length; i++) {
- var block = topBlocks[i];
- while (block) {
- setTimeout(block.setCollapsed.bind(block, false), ms);
- block = block.getNextBlock();
- ms += COLLAPSE_DELAY;
- }
- }
};
options.push(expandOption);
}
Blockly.ContextMenu.show(e, options);
};
/**
* Cancel the native context menu, unless the focus is on an HTML input widget.
--- 446,621 ----
var expandOption = {enabled: hasCollapsedBlocks};
*** 943,968 ****
var expandOption = {enabled: hasCollapsedBlocks};
expandOption.text = Blockly.Msg.EXPAND_ALL;
expandOption.callback = function() {
+ Blockly.Instrument.initializeStats("expandAllCollapsedBlocks");
@@ -247,215 +24,3 @@
};
options.push(expandOption);
}
+ // Arrange blocks in row order.
+ var arrangeOptionH = {enabled: (Blockly.workspace_arranged_position !== Blockly.BLKS_HORIZONTAL)};
+ arrangeOptionH.text = Blockly.Msg.ARRANGE_H;
+ arrangeOptionH.callback = function() {
+ Blockly.workspace_arranged_position = Blockly.BLKS_HORIZONTAL;
+ Blockly.workspace_arranged_latest_position= Blockly.BLKS_HORIZONTAL;
+ arrangeBlocks(Blockly.BLKS_HORIZONTAL);
+ };
+ options.push(arrangeOptionH);
+
+ // Arrange blocks in column order.
+ var arrangeOptionV = {enabled: (Blockly.workspace_arranged_position !== Blockly.BLKS_VERTICAL)};
+ arrangeOptionV.text = Blockly.Msg.ARRANGE_V;
+ arrangeOptionV.callback = function() {
+ Blockly.workspace_arranged_position = Blockly.BLKS_VERTICAL;
+ Blockly.workspace_arranged_latest_position = Blockly.BLKS_VERTICAL;
+ arrangeBlocks(Blockly.BLKS_VERTICAL);
+ };
+ options.push(arrangeOptionV);
+
+ /**
+ * Function that returns a name to be used to sort blocks.
+ * The general comparator is the block.category attribute.
+ * In the case of 'Components' the comparator is the instanceName of the component if it exists
+ * (it does not exist for generic components).
+ * In the case of Procedures the comparator is the NAME(for definitions) or PROCNAME (for calls)
+ * @param {!Blockly.Block} the block that will be compared in the sortByCategory function
+ * @returns {string} text to be used in the comparison
+ */
+ function comparisonName(block){
+ if (block.category === 'Component' && block.instanceName)
+ return block.instanceName;
+ if (block.category === 'Procedures')
+ return (block.getFieldValue('NAME') || block.getFieldValue('PROCNAME'));
+ return block.category;
+ }
+
+ /**
+ * Function used to sort blocks by Category.
+ * @param {!Blockly.Block} a first block to be compared
+ * @param {!Blockly.Block} b second block to be compared
+ * @returns {number} returns 0 if the blocks are equal, and -1 or 1 if they are not
+ */
+ function sortByCategory(a,b) {
+ var comparatorA = comparisonName(a).toLowerCase();
+ var comparatorB = comparisonName(b).toLowerCase();
+
+ if (comparatorA < comparatorB) return -1;
+ else if (comparatorA > comparatorB) return +1;
+ else return 0;
+ }
+
+ // Arranges block in layout (Horizontal or Vertical).
+ function arrangeBlocks(layout) {
+ var SPACER = 25;
+ var topblocks = Blockly.mainWorkspace.getTopBlocks(false);
+ // If the blocks are arranged by Category, sort the array
+ if (Blockly.workspace_arranged_type === Blockly.BLKS_CATEGORY){
+ topblocks.sort(sortByCategory);
+ }
+ var metrics = Blockly.mainWorkspace.getMetrics();
+ var viewLeft = metrics.viewLeft + 5;
+ var viewTop = metrics.viewTop + 5;
+ var x = viewLeft;
+ var y = viewTop;
+ var wsRight = viewLeft + metrics.viewWidth;
+ var wsBottom = viewTop + metrics.viewHeight;
+ var maxHgt = 0;
+ var maxWidth = 0;
+ for (var i = 0, len = topblocks.length; i < len; i++) {
+ var blk = topblocks[i];
+ var blkXY = blk.getRelativeToSurfaceXY();
+ var blockHW = blk.getHeightWidth();
+ var blkHgt = blockHW.height;
+ var blkWidth = blockHW.width;
+ switch (layout) {
+ case Blockly.BLKS_HORIZONTAL:
+ if (x < wsRight) {
+ blk.moveBy(x - blkXY.x, y - blkXY.y);
+ blk.select();
+ x += blkWidth + SPACER;
+ if (blkHgt > maxHgt) // Remember highest block
+ maxHgt = blkHgt;
+ } else {
+ y += maxHgt + SPACER;
+ maxHgt = blkHgt;
+ x = viewLeft;
+ blk.moveBy(x - blkXY.x, y - blkXY.y);
+ blk.select();
+ x += blkWidth + SPACER;
+ }
+ break;
+ case Blockly.BLKS_VERTICAL:
+ if (y < wsBottom) {
+ blk.moveBy(x - blkXY.x, y - blkXY.y);
+ blk.select();
+ y += blkHgt + SPACER;
+ if (blkWidth > maxWidth) // Remember widest block
+ maxWidth = blkWidth;
+ } else {
+ x += maxWidth + SPACER;
+ maxWidth = blkWidth;
+ y = viewTop;
+ blk.moveBy(x - blkXY.x, y - blkXY.y);
+ blk.select();
+ y += blkHgt + SPACER;
+ }
+ break;
+ }
+ }
+ }
+
+ // Sort by Category.
+ var sortOptionCat = {enabled: (Blockly.workspace_arranged_type !== Blockly.BLKS_CATEGORY)};
+ sortOptionCat.text = Blockly.Msg.SORT_C;
+ sortOptionCat.callback = function() {
+ Blockly.workspace_arranged_type = Blockly.BLKS_CATEGORY;
+ rearrangeWorkspace();
+ };
+ options.push(sortOptionCat);
+
+ // Called after a sort or collapse/expand to redisplay blocks.
+ function rearrangeWorkspace() {
+ //default arrangement position set to Horizontal if it hasn't been set yet (is null)
+ if (Blockly.workspace_arranged_latest_position === null || Blockly.workspace_arranged_latest_position === Blockly.BLKS_HORIZONTAL)
+ arrangeOptionH.callback();
+ else if (Blockly.workspace_arranged_latest_position === Blockly.BLKS_VERTICAL)
+ arrangeOptionV.callback();
+ }
+
+ // Option to get help.
+ var helpOption = {enabled: false};
+ helpOption.text = Blockly.Msg.HELP;
+ helpOption.callback = function() {};
+ options.push(helpOption);
+
Blockly.ContextMenu.show(e, options);
};
+ /**
+ * reset arrangement state; to be called when blocks in the workspace change
+ */
+ Blockly.resetWorkspaceArrangements = function(){
+ // reset the variables used for menus, but keep the latest position, so the current horizontal or
+ // vertical state can be kept
+ Blockly.workspace_arranged_type = null;
+ Blockly.workspace_arranged_position = null;
+ };
/**
* Cancel the native context menu, unless the focus is on an HTML input widget.
***************
*** 404,414 ****
*/
Blockly.hideChaff = function(opt_allowToolbox) {
Blockly.Tooltip.hide();
Blockly.WidgetDiv.hide();
- if (!opt_allowToolbox &&
- Blockly.Toolbox.flyout_ && Blockly.Toolbox.flyout_.autoClose) {
- Blockly.Toolbox.clearSelection();
- }
};
/**
--- 635,643 ----
*/
Blockly.hideChaff = function(opt_allowToolbox) {
Blockly.Tooltip.hide();
+ Blockly.FieldFlydown && Blockly.FieldFlydown.hide(); // [lyn, 10/06/13] for handling parameter & procedure flydowns
Blockly.WidgetDiv.hide();
+ Blockly.TypeBlock && Blockly.TypeBlock.hide();
};
/**
***************
*** 556,562 ****
*/
Blockly.getMainWorkspaceMetrics_ = function() {
var svgSize = Blockly.svgSize();
- svgSize.width -= Blockly.Toolbox.width; // Zero if no Toolbox.
var viewWidth = svgSize.width - Blockly.Scrollbar.scrollbarThickness;
var viewHeight = svgSize.height - Blockly.Scrollbar.scrollbarThickness;
try {
--- 785,793 ----
*/
Blockly.getMainWorkspaceMetrics_ = function() {
var svgSize = Blockly.svgSize();
+ //We don't use Blockly.Toolbox in our version of Blockly instead we use drawer.js
+ //svgSize.width -= Blockly.Toolbox.width; // Zero if no Toolbox.
+ svgSize.width -= 0; // Zero if no Toolbox.
var viewWidth = svgSize.width - Blockly.Scrollbar.scrollbarThickness;
var viewHeight = svgSize.height - Blockly.Scrollbar.scrollbarThickness;
try {
***************
*** 582,588 ****
var topEdge = blockBox.y;
var bottomEdge = topEdge + blockBox.height;
}
- var absoluteLeft = Blockly.RTL ? 0 : Blockly.Toolbox.width;
var metrics = {
viewHeight: svgSize.height,
viewWidth: svgSize.width,
--- 813,821 ----
var topEdge = blockBox.y;
var bottomEdge = topEdge + blockBox.height;
}
+ //We don't use Blockly.Toolbox in our version of Blockly instead we use drawer.js
+ //var absoluteLeft = Blockly.RTL ? 0 : Blockly.Toolbox.width;
+ var absoluteLeft = Blockly.RTL ? 0 : 0;
var metrics = {
viewHeight: svgSize.height,
viewWidth: svgSize.width,

View File

@@ -1,19 +0,0 @@
***************
*** 168,175 ****
* @this Blockly.Block
*/
block.mutationToDom = function() {
- var container = details.mutationToDomFunc ?
- details.mutatationToDomFunc() : document.createElement('mutation');
container.setAttribute('is_statement', this['isStatement'] || false);
return container;
};
--- 168,175 ----
* @this Blockly.Block
*/
block.mutationToDom = function() {
+ var container = details.mutationToDomFunc ? details.mutatationToDomFunc()
+ : document.createElement('mutation');
container.setAttribute('is_statement', this['isStatement'] || false);
return container;
};

View File

@@ -141,7 +141,7 @@ Blockly.Workspace.prototype.addTopBlock = function(block) {
*/
Blockly.Workspace.prototype.removeTopBlock = function(block) {
if (block.workspace == Blockly.mainWorkspace) //Do not reset arrangements for the flyout
Blockly.resetWorkspaceArrangements();
this.resetArrangements();
var found = false;
for (var child, i = 0; child = this.topBlocks_[i]; i++) {
if (child == block) {

View File

@@ -925,6 +925,7 @@ Blockly.WorkspaceSvg.prototype.showContextMenu_ = function(e) {
ms += DELAY;
}
}
this.resetArrangements();
};
// Option to collapse top blocks.
@@ -989,6 +990,142 @@ Blockly.WorkspaceSvg.prototype.showContextMenu_ = function(e) {
};
menuOptions.push(deleteOption);
// Arrange blocks in row order.
var arrangeOptionH = {enabled: (Blockly.workspace_arranged_position !== Blockly.BLKS_HORIZONTAL)};
arrangeOptionH.text = Blockly.Msg.ARRANGE_H;
arrangeOptionH.callback = function() {
Blockly.workspace_arranged_position = Blockly.BLKS_HORIZONTAL;
Blockly.workspace_arranged_latest_position= Blockly.BLKS_HORIZONTAL;
arrangeBlocks(Blockly.BLKS_HORIZONTAL);
};
options.push(arrangeOptionH);
// Arrange blocks in column order.
var arrangeOptionV = {enabled: (Blockly.workspace_arranged_position !== Blockly.BLKS_VERTICAL)};
arrangeOptionV.text = Blockly.Msg.ARRANGE_V;
arrangeOptionV.callback = function() {
Blockly.workspace_arranged_position = Blockly.BLKS_VERTICAL;
Blockly.workspace_arranged_latest_position = Blockly.BLKS_VERTICAL;
arrangeBlocks(Blockly.BLKS_VERTICAL);
};
options.push(arrangeOptionV);
/**
* Function that returns a name to be used to sort blocks.
* The general comparator is the block.category attribute.
* In the case of 'Components' the comparator is the instanceName of the component if it exists
* (it does not exist for generic components).
* In the case of Procedures the comparator is the NAME(for definitions) or PROCNAME (for calls)
* @param {!Blockly.Block} the block that will be compared in the sortByCategory function
* @returns {string} text to be used in the comparison
*/
function comparisonName(block){
if (block.category === 'Component' && block.instanceName)
return block.instanceName;
if (block.category === 'Procedures')
return (block.getFieldValue('NAME') || block.getFieldValue('PROCNAME'));
return block.category;
}
/**
* Function used to sort blocks by Category.
* @param {!Blockly.Block} a first block to be compared
* @param {!Blockly.Block} b second block to be compared
* @returns {number} returns 0 if the blocks are equal, and -1 or 1 if they are not
*/
function sortByCategory(a,b) {
var comparatorA = comparisonName(a).toLowerCase();
var comparatorB = comparisonName(b).toLowerCase();
if (comparatorA < comparatorB) return -1;
else if (comparatorA > comparatorB) return +1;
else return 0;
}
// Arranges block in layout (Horizontal or Vertical).
function arrangeBlocks(layout) {
var SPACER = 25;
var topblocks = Blockly.mainWorkspace.getTopBlocks(false);
// If the blocks are arranged by Category, sort the array
if (Blockly.workspace_arranged_type === Blockly.BLKS_CATEGORY){
topblocks.sort(sortByCategory);
}
var metrics = Blockly.mainWorkspace.getMetrics();
var viewLeft = metrics.viewLeft + 5;
var viewTop = metrics.viewTop + 5;
var x = viewLeft;
var y = viewTop;
var wsRight = viewLeft + metrics.viewWidth;
var wsBottom = viewTop + metrics.viewHeight;
var maxHgt = 0;
var maxWidth = 0;
for (var i = 0, len = topblocks.length; i < len; i++) {
var blk = topblocks[i];
var blkXY = blk.getRelativeToSurfaceXY();
var blockHW = blk.getHeightWidth();
var blkHgt = blockHW.height;
var blkWidth = blockHW.width;
switch (layout) {
case Blockly.BLKS_HORIZONTAL:
if (x < wsRight) {
blk.moveBy(x - blkXY.x, y - blkXY.y);
blk.select();
x += blkWidth + SPACER;
if (blkHgt > maxHgt) // Remember highest block
maxHgt = blkHgt;
} else {
y += maxHgt + SPACER;
maxHgt = blkHgt;
x = viewLeft;
blk.moveBy(x - blkXY.x, y - blkXY.y);
blk.select();
x += blkWidth + SPACER;
}
break;
case Blockly.BLKS_VERTICAL:
if (y < wsBottom) {
blk.moveBy(x - blkXY.x, y - blkXY.y);
blk.select();
y += blkHgt + SPACER;
if (blkWidth > maxWidth) // Remember widest block
maxWidth = blkWidth;
} else {
x += maxWidth + SPACER;
maxWidth = blkWidth;
y = viewTop;
blk.moveBy(x - blkXY.x, y - blkXY.y);
blk.select();
y += blkHgt + SPACER;
}
break;
}
}
}
// Sort by Category.
var sortOptionCat = {enabled: (Blockly.workspace_arranged_type !== Blockly.BLKS_CATEGORY)};
sortOptionCat.text = Blockly.Msg.SORT_C;
sortOptionCat.callback = function() {
Blockly.workspace_arranged_type = Blockly.BLKS_CATEGORY;
rearrangeWorkspace();
};
options.push(sortOptionCat);
// Called after a sort or collapse/expand to redisplay blocks.
function rearrangeWorkspace() {
//default arrangement position set to Horizontal if it hasn't been set yet (is null)
if (Blockly.workspace_arranged_latest_position === null || Blockly.workspace_arranged_latest_position === Blockly.BLKS_HORIZONTAL)
arrangeOptionH.callback();
else if (Blockly.workspace_arranged_latest_position === Blockly.BLKS_VERTICAL)
arrangeOptionV.callback();
}
// Option to get help.
var helpOption = {enabled: false};
helpOption.text = Blockly.Msg.HELP;
helpOption.callback = function() {};
options.push(helpOption);
Blockly.ContextMenu.show(e, menuOptions, this.RTL);
};