Update APIs and Add New Cursor Look (#3009)

* Updates methods to be private in navigation.js

* Update cursor with new look
This commit is contained in:
alschmiedt
2019-09-16 12:33:43 -07:00
committed by GitHub
parent 77185906d8
commit 2c98ecaed6
12 changed files with 552 additions and 286 deletions

View File

@@ -117,6 +117,22 @@ Blockly.BlockSvg = function(workspace, prototypeName, opt_id) {
if (this.svgGroup_.dataset) {
this.svgGroup_.dataset.id = this.id;
}
/**
* Holds the cursors svg element when the cursor is attached to the block.
* This is null if there is no cursor on the block.
* @type {SVGElement}
* @private
*/
this.cursorSvg_ = null;
/**
* Holds the markers svg element when the marker is attached to the block.
* This is null if there is no marker on the block.
* @type {SVGElement}
* @private
*/
this.markerSvg_ = null;
};
Blockly.utils.object.inherits(Blockly.BlockSvg, Blockly.Block);
@@ -1606,3 +1622,39 @@ Blockly.BlockSvg.prototype.updateConnectionLocations_ = function() {
}
}
};
/**
* Add the cursor svg to this block's svg group.
* @param {SVGElement} cursorSvg The svg root of the cursor to be added to the
* block svg group.
* @package
*/
Blockly.BlockSvg.prototype.setCursorSvg = function(cursorSvg) {
if (!cursorSvg) {
this.cursorSvg_ = null;
return;
}
this.svgGroup_.appendChild(cursorSvg);
this.cursorSvg_ = cursorSvg;
};
/**
* Add the marker svg to this block's svg group.
* @param {SVGElement} markerSvg The svg root of the marker to be added to the
* block svg group.
* @package
*/
Blockly.BlockSvg.prototype.setMarkerSvg = function(markerSvg) {
if (!markerSvg) {
this.markerSvg_ = null;
return;
}
if (this.cursorSvg_) {
this.svgGroup_.insertBefore(markerSvg, this.cursorSvg_);
} else {
this.svgGroup_.appendChild(markerSvg);
}
this.markerSvg_ = markerSvg;
};

View File

@@ -80,6 +80,23 @@ Blockly.Field = function(value, opt_validator, opt_config) {
* @protected
*/
this.size_ = new Blockly.utils.Size(0, 0);
/**
* Holds the cursors svg element when the cursor is attached to the field.
* This is null if there is no cursor on the field.
* @type {SVGElement}
* @private
*/
this.cursorSvg_ = null;
/**
* Holds the markers svg element when the marker is attached to the field.
* This is null if there is no marker on the field.
* @type {SVGElement}
* @private
*/
this.markerSvg_ = null;
opt_config && this.configure_(opt_config);
this.setValue(value);
opt_validator && this.setValidator(opt_validator);
@@ -906,3 +923,35 @@ Blockly.Field.prototype.getParentInput = function() {
Blockly.Field.prototype.onBlocklyAction = function(_action) {
return false;
};
/**
* Add the cursor svg to this fields svg group.
* @param {SVGElement} cursorSvg The svg root of the cursor to be added to the
* field group.
* @package
*/
Blockly.Field.prototype.setCursorSvg = function(cursorSvg) {
if (!cursorSvg) {
this.cursorSvg_ = null;
return;
}
this.fieldGroup_.appendChild(cursorSvg);
this.cursorSvg_ = cursorSvg;
};
/**
* Add the marker svg to this fields svg group.
* @param {SVGElement} markerSvg The svg root of the marker to be added to the
* field group.
* @package
*/
Blockly.Field.prototype.setMarkerSvg = function(markerSvg) {
if (!markerSvg) {
this.markerSvg_ = null;
return;
}
this.fieldGroup_.appendChild(markerSvg);
this.markerSvg_ = markerSvg;
};

View File

@@ -500,7 +500,7 @@ Blockly.Gesture.prototype.doStart = function(e) {
if (this.targetBlock_) {
if (!this.targetBlock_.isInFlyout && e.shiftKey) {
Blockly.navigation.enableKeyboardAccessibility();
this.creatorWorkspace_.cursor.setLocation(
this.creatorWorkspace_.getCursor().setLocation(
Blockly.navigation.getTopNode(this.targetBlock_));
} else {
this.targetBlock_.select();

View File

@@ -56,7 +56,7 @@ Blockly.ASTNode = function(type, location, opt_params) {
* @type {boolean}
* @private
*/
this.isConnection_ = Blockly.ASTNode.isConnectionType(type);
this.isConnection_ = Blockly.ASTNode.isConnectionType_(type);
/**
* The location of the AST node.
@@ -103,9 +103,9 @@ Blockly.ASTNode.DEFAULT_OFFSET_Y = -20;
* Whether an AST node of the given type points to a connection.
* @param {string} type The type to check. One of Blockly.ASTNode.types.
* @return {boolean} True if a node of the given type points to a connection.
* @package
* @private
*/
Blockly.ASTNode.isConnectionType = function(type) {
Blockly.ASTNode.isConnectionType_ = function(type) {
switch (type) {
case Blockly.ASTNode.types.PREVIOUS:
case Blockly.ASTNode.types.NEXT:
@@ -161,11 +161,7 @@ Blockly.ASTNode.createInputNode = function(input) {
if (!input) {
return null;
}
var params = {
"input": input
};
return new Blockly.ASTNode(Blockly.ASTNode.types.INPUT, input.connection,
params);
return new Blockly.ASTNode(Blockly.ASTNode.types.INPUT, input.connection);
};
/**
@@ -216,8 +212,6 @@ Blockly.ASTNode.prototype.processParams_ = function(params) {
}
if (params['wsCoordinate']) {
this.wsCoordinate_ = params['wsCoordinate'];
} else if (params['input']) {
this.parentInput_ = params['input'];
}
};
@@ -250,16 +244,6 @@ Blockly.ASTNode.prototype.getWsCoordinate = function() {
return this.wsCoordinate_;
};
/**
* Get the parent input of the location.
* @return {Blockly.Input} The parent input of the location or null if the node
* is not input type.
* @package
*/
Blockly.ASTNode.prototype.getParentInput = function() {
return this.parentInput_;
};
/**
* Whether the node points to a connection.
* @return {boolean} [description]

View File

@@ -106,10 +106,12 @@ Blockly.Cursor.prototype.next = function() {
if (!curNode) {
return null;
}
var newNode = curNode.next();
if (newNode && newNode.getType() === Blockly.ASTNode.types.NEXT) {
newNode = newNode.next() || newNode;
var newNode = curNode.next();
while (newNode && newNode.next() &&
(newNode.getType() === Blockly.ASTNode.types.NEXT ||
newNode.getType() === Blockly.ASTNode.types.BLOCK)) {
newNode = newNode.next();
}
if (newNode) {
@@ -128,6 +130,12 @@ Blockly.Cursor.prototype.in = function() {
if (!curNode) {
return null;
}
// If we are on a previous or output connection, go to the block level before
// performing next operation.
if (curNode.getType() === Blockly.ASTNode.types.PREVIOUS ||
curNode.getType() === Blockly.ASTNode.types.OUTPUT) {
curNode = curNode.next();
}
var newNode = curNode.in();
if (newNode && newNode.getType() === Blockly.ASTNode.types.OUTPUT) {
@@ -152,8 +160,10 @@ Blockly.Cursor.prototype.prev = function() {
}
var newNode = curNode.prev();
if (newNode && newNode.getType() === Blockly.ASTNode.types.NEXT) {
newNode = newNode.prev() || newNode;
while (newNode && newNode.prev() &&
(newNode.getType() === Blockly.ASTNode.types.NEXT ||
newNode.getType() === Blockly.ASTNode.types.BLOCK)) {
newNode = newNode.prev();
}
if (newNode) {

View File

@@ -32,7 +32,7 @@ goog.require('Blockly.utils.object');
/**
* Class for a cursor.
* @param {!Blockly.Workspace} workspace The workspace the cursor belongs to.
* @param {!Blockly.WorkspaceSvg} workspace The workspace the cursor belongs to.
* @param {boolean=} opt_marker True if the cursor is a marker. A marker is used
* to save a location and is an immovable cursor. False or undefined if the
* cursor is not a marker.
@@ -41,7 +41,7 @@ goog.require('Blockly.utils.object');
Blockly.CursorSvg = function(workspace, opt_marker) {
/**
* The workspace the cursor belongs to.
* @type {!Blockly.Workspace}
* @type {!Blockly.WorkspaceSvg}
* @private
*/
this.workspace_ = workspace;
@@ -50,11 +50,19 @@ Blockly.CursorSvg = function(workspace, opt_marker) {
* True if the cursor should be drawn as a marker, false otherwise.
* A marker is drawn as a solid blue line, while the cursor is drawns as a
* flashing red one.
* @type {boolean}
* @type {boolean|undefined}
* @private
*/
this.isMarker_ = opt_marker;
/**
* The workspace, field, or block that the cursor svg element should be
* attached to.
* @type {Blockly.WorkspaceSvg|Blockly.Field|Blockly.BlockSvg}
* @private
*/
this.parent_ = null;
/**
* The constants necessary to draw the cursor.
* @type {Blockly.blockRendering.ConstantProvider}
@@ -98,6 +106,22 @@ Blockly.CursorSvg.VERTICAL_PADDING = 5;
* @const
*/
Blockly.CursorSvg.STACK_PADDING = 10;
/**
* Padding around a block.
* @type {number}
* @const
*/
Blockly.CursorSvg.BLOCK_PADDING = 2;
/**
* What we multiply the height by to get the height of the cursor.
* Only used for the block and block connections.
* @type {number}
* @const
*/
Blockly.CursorSvg.HEIGHT_MULTIPLIER = 3 / 4;
/**
* Cursor color.
* @type {string}
@@ -124,13 +148,6 @@ Blockly.CursorSvg.CURSOR_CLASS = 'blocklyCursor';
*/
Blockly.CursorSvg.MARKER_CLASS = 'blocklyMarker';
/**
* Parent SVG element.
* This is generally a block's SVG root, unless the cursor is on the workspace.
* @type {Element}
*/
Blockly.CursorSvg.prototype.parent_ = null;
/**
* The current SVG element for the cursor.
* @type {Element}
@@ -139,7 +156,7 @@ Blockly.CursorSvg.prototype.currentCursorSvg = null;
/**
* Return the root node of the SVG or null if none exists.
* @return {Element} The root SVG node.
* @return {SVGElement} The root SVG node.
*/
Blockly.CursorSvg.prototype.getSvgRoot = function() {
return this.svgGroup_;
@@ -147,7 +164,8 @@ Blockly.CursorSvg.prototype.getSvgRoot = function() {
/**
* Create the DOM element for the cursor.
* @return {!Element} The cursor controls SVG group.
* @return {!SVGElement} The cursor controls SVG group.
* @package
*/
Blockly.CursorSvg.prototype.createDom = function() {
var className = this.isMarker_ ?
@@ -163,33 +181,25 @@ Blockly.CursorSvg.prototype.createDom = function() {
};
/**
* Set parent of the cursor. This is so that the cursor will be on the correct
* SVG group.
* @param {Element} newParent New parent of the cursor.
* Attaches the svg root of the cursor to the svg group of the parent.
* @param {!Blockly.WorkspaceSvg|!Blockly.Field|!Blockly.BlockSvg} newParent
* The workspace, field, or block that the cursor svg element should be
* attached to.
* @private
*/
Blockly.CursorSvg.prototype.setParent_ = function(newParent) {
var oldParent = this.parent_;
if (newParent == oldParent) {
return;
}
var svgRoot = this.getSvgRoot();
var cursorNode = null;
if (newParent) {
if (this.isMarker_) {
// Put the marker before the cursor so the cursor does not get covered.
for (var i = 0, childNode; childNode = newParent.childNodes[i]; i++) {
if (Blockly.utils.dom.hasClass(childNode , Blockly.CursorSvg.CURSOR_CLASS)) {
cursorNode = childNode;
}
}
newParent.insertBefore(svgRoot, cursorNode);
} else {
newParent.appendChild(svgRoot);
if (this.isMarker_) {
if (this.parent_) {
this.parent_.setMarkerSvg(null);
}
this.parent_ = newParent;
newParent.setMarkerSvg(this.getSvgRoot());
} else {
if (this.parent_) {
this.parent_.setCursorSvg(null);
}
newParent.setCursorSvg(this.getSvgRoot());
}
this.parent_ = newParent;
};
/**************************/
@@ -197,107 +207,112 @@ Blockly.CursorSvg.prototype.setParent_ = function(newParent) {
/**************************/
/**
* Show the cursor using coordinates.
* Show the cursor as a combination of the previous connection and block,
* the output connection and block, or just the block.
* @param {Blockly.BlockSvg} block The block the cursor is currently on.
* @private
*/
Blockly.CursorSvg.prototype.showWithBlockPrevOutput_ = function(block) {
if (!block) {
return;
}
var width = block.width;
var height = block.height;
var cursorHeight = height * Blockly.CursorSvg.HEIGHT_MULTIPLIER;
var cursorOffset = Blockly.CursorSvg.BLOCK_PADDING;
if (block.previousConnection) {
this.positionPrevious_(width, cursorOffset, cursorHeight);
} else if (block.outputConnection) {
this.positionOutput_(width, height);
} else {
this.positionBlock_(width, cursorOffset, cursorHeight);
}
this.currentCursorSvg = this.cursorBlock_;
this.setParent_(block);
this.showCurrent_();
};
/**
* Show the visual representation of a workspace coordinate.
* This is a horizontal line.
* @param {!Blockly.ASTNode} curNode The node that we want to draw the cursor for.
* @private
*/
Blockly.CursorSvg.prototype.showWithCoordinates_ = function(curNode) {
var wsCoordinate = curNode.getWsCoordinate();
this.currentCursorSvg = this.cursorSvgLine_;
this.setParent_(this.workspace_.svgBlockCanvas_);
this.setParent_(this.workspace_);
this.positionLine_(wsCoordinate.x, wsCoordinate.y,
Blockly.CursorSvg.CURSOR_WIDTH);
this.showCurrent_();
};
/**
* Show the cursor using a block.
* Show the visual representation of a field.
* This is a box around the field.
* @param {!Blockly.ASTNode} curNode The node that we want to draw the cursor for.
* @private
*/
Blockly.CursorSvg.prototype.showWithBlock_ = function(curNode) {
var block = curNode.getLocation();
this.currentCursorSvg = this.cursorSvgRect_;
this.setParent_(block.getSvgRoot());
this.positionRect_(0, 0, block.width , block.height);
this.showCurrent_();
};
/**
* Show the cursor using a connection with input or output type.
* @param {!Blockly.ASTNode} curNode The node that we want to draw the cursor for.
* @private
*/
Blockly.CursorSvg.prototype.showWithInputOutput_ = function(curNode) {
var connection = /** @type {Blockly.Connection} */
(curNode.getLocation());
this.currentCursorSvg = this.cursorInputOutput_;
var path = Blockly.utils.svgPaths.moveTo(0, 0) +
this.constants_.shapeFor(connection).pathDown;
this.cursorInputOutput_.setAttribute('d', path);
this.setParent_(connection.getSourceBlock().getSvgRoot());
this.positionInputOutput_(connection);
this.showCurrent_();
};
/**
* Show the cursor using a next connection.
* @param {!Blockly.ASTNode} curNode The node that we want to draw the cursor for.
* @private
*/
Blockly.CursorSvg.prototype.showWithNext_ = function(curNode) {
var connection = curNode.getLocation();
var targetBlock = connection.getSourceBlock();
var x = 0;
var y = connection.getOffsetInBlock().y;
var width = targetBlock.getHeightWidth().width;
this.currentCursorSvg = this.cursorSvgLine_;
this.setParent_(connection.getSourceBlock().getSvgRoot());
this.positionLine_(x, y, width);
this.showCurrent_();
};
/**
* Show the cursor using a previous connection.
* @param {!Blockly.ASTNode} curNode The node that we want to draw the cursor for.
* @private
*/
Blockly.CursorSvg.prototype.showWithPrev_ = function(curNode) {
var connection = curNode.getLocation();
var targetBlock = connection.getSourceBlock();
var width = targetBlock.getHeightWidth().width;
this.currentCursorSvg = this.cursorSvgLine_;
this.setParent_(connection.getSourceBlock().getSvgRoot());
this.positionLine_(0, 0, width);
this.showCurrent_();
};
/**
* Show the cursor using a field.
* @param {!Blockly.ASTNode} curNode The node that we want to draw the cursor for.
* @private
*/
Blockly.CursorSvg.prototype.showWithField_ = function(curNode) {
var field = curNode.getLocation();
var field = /** @type {Blockly.Field} */ (curNode.getLocation());
var width = field.borderRect_.width.baseVal.value;
var height = field.borderRect_.height.baseVal.value;
this.currentCursorSvg = this.cursorSvgRect_;
this.setParent_(field.getSvgRoot());
this.setParent_(field);
this.positionRect_(0, 0, width, height);
this.showCurrent_();
};
/**
* Show the cursor using a stack.
* @param {!Blockly.ASTNode} curNode The node that we want to draw the cursor for.
* Show the visual representation of an input.
* This is a puzzle piece.
* @param {!Blockly.ASTNode} curNode The node that we want to draw the cursor for.
* @private
*/
Blockly.CursorSvg.prototype.showWithInput_ = function(curNode) {
var connection = /** @type {Blockly.Connection} */
(curNode.getLocation());
var path = Blockly.utils.svgPaths.moveTo(0,0) +
this.constants_.PUZZLE_TAB.pathDown;
var sourceBlock = /** @type {Blockly.BlockSvg} */ (connection.getSourceBlock());
this.currentCursorSvg = this.cursorInput_;
this.cursorInput_.setAttribute('d', path);
this.setParent_(sourceBlock);
this.positionInput_(connection);
this.showCurrent_();
};
/**
* Show the visual representation of a next connection.
* This is a horizontal line.
* @param {!Blockly.ASTNode} curNode The node that we want to draw the cursor for.
* @private
*/
Blockly.CursorSvg.prototype.showWithNext_ = function(curNode) {
var connection = curNode.getLocation();
var targetBlock = /** @type {Blockly.BlockSvg} */ (connection.getSourceBlock());
var x = 0;
var y = connection.getOffsetInBlock().y;
var width = targetBlock.getHeightWidth().width;
this.currentCursorSvg = this.cursorSvgLine_;
this.setParent_(targetBlock);
this.positionLine_(x, y, width);
this.showCurrent_();
};
/**
* Show the visual representation of a stack.
* This is a box with extra padding around the entire stack of blocks.
* @param {!Blockly.ASTNode} curNode The node that we want to draw the cursor for.
* @private
*/
Blockly.CursorSvg.prototype.showWithStack_ = function(curNode) {
var block = curNode.getLocation();
var block = /** @type {Blockly.BlockSvg} */ (curNode.getLocation());
// Gets the height and width of entire stack.
var heightWidth = block.getHeightWidth();
@@ -311,59 +326,12 @@ Blockly.CursorSvg.prototype.showWithStack_ = function(curNode) {
var y = -1 * Blockly.CursorSvg.STACK_PADDING / 2;
this.currentCursorSvg = this.cursorSvgRect_;
this.setParent_(block.getSvgRoot());
this.setParent_(block);
this.positionRect_(x, y, width, height);
this.showCurrent_();
};
/**************************/
/**** Position ****/
/**************************/
/**
* Move and show the cursor at the specified coordinate in workspace units.
* @param {number} x The new x, in workspace units.
* @param {number} y The new y, in workspace units.
* @param {number} width The new width, in workspace units.
* @private
*/
Blockly.CursorSvg.prototype.positionLine_ = function(x, y, width) {
this.cursorSvgLine_.setAttribute('x', x);
this.cursorSvgLine_.setAttribute('y', y);
this.cursorSvgLine_.setAttribute('width', width);
};
/**
* Move and show the cursor at the specified coordinate in workspace units.
* @param {number} x The new x, in workspace units.
* @param {number} y The new y, in workspace units.
* @param {number} width The new width, in workspace units.
* @param {number} height The new height, in workspace units.
* @private
*/
Blockly.CursorSvg.prototype.positionRect_ = function(x, y, width, height) {
this.cursorSvgRect_.setAttribute('x', x);
this.cursorSvgRect_.setAttribute('y', y);
this.cursorSvgRect_.setAttribute('width', width);
this.cursorSvgRect_.setAttribute('height', height);
};
/**
* Position the cursor for an output connection.
* @param {Blockly.Connection} connection The connection to position cursor around.
* @private
*/
Blockly.CursorSvg.prototype.positionInputOutput_ = function(connection) {
var x = connection.getOffsetInBlock().x;
var y = connection.getOffsetInBlock().y;
this.cursorInputOutput_.setAttribute('transform',
'translate(' + x + ',' + y + ')' +
(connection.getSourceBlock().RTL ? ' scale(-1 1)' : ''));
};
/**
* Show the current cursor.
* @private
@@ -373,18 +341,121 @@ Blockly.CursorSvg.prototype.showCurrent_ = function() {
this.currentCursorSvg.style.display = '';
};
/**************************/
/**** Position ****/
/**************************/
/**
* Position the cursor for a block.
* Displays an outline of the top half of a rectangle around a block.
* @param {!number} width The width of the block.
* @param {!number} cursorOffset The extra padding for around the block.
* @param {!number} cursorHeight The height of the cursor.
*/
Blockly.CursorSvg.prototype.positionBlock_ = function(width, cursorOffset, cursorHeight) {
var cursorPath = Blockly.utils.svgPaths.moveBy(-1 * cursorOffset, cursorHeight) +
Blockly.utils.svgPaths.lineOnAxis('V', -1 * cursorOffset) +
Blockly.utils.svgPaths.lineOnAxis('H', width + cursorOffset * 2) +
Blockly.utils.svgPaths.lineOnAxis('V', cursorHeight);
this.cursorBlock_.setAttribute('d', cursorPath);
};
/**
* Position the cursor for an input connection.
* Displays a filled in puzzle piece.
* @param {!Blockly.Connection} connection The connection to position cursor around.
* @private
*/
Blockly.CursorSvg.prototype.positionInput_ = function(connection) {
var x = connection.getOffsetInBlock().x;
var y = connection.getOffsetInBlock().y;
this.cursorInput_.setAttribute('transform',
'translate(' + x + ',' + y + ')' +
(connection.getSourceBlock().RTL ? ' scale(-1 1)' : ''));
};
/**
* Move and show the cursor at the specified coordinate in workspace units.
* Displays a horizontal line.
* @param {!number} x The new x, in workspace units.
* @param {!number} y The new y, in workspace units.
* @param {!number} width The new width, in workspace units.
* @private
*/
Blockly.CursorSvg.prototype.positionLine_ = function(x, y, width) {
this.cursorSvgLine_.setAttribute('x', x);
this.cursorSvgLine_.setAttribute('y', y);
this.cursorSvgLine_.setAttribute('width', width);
};
/**
* Position the cursor for an output connection.
* Displays a puzzle outline and the top and bottom path.
* @param {!number} width The width of the block.
* @param {!number} height The height of the block.
* @private
*/
Blockly.CursorSvg.prototype.positionOutput_ = function(width, height) {
var cursorPath = Blockly.utils.svgPaths.moveBy(width, 0) +
Blockly.utils.svgPaths.lineOnAxis('h', -1 * (width - this.constants_.PUZZLE_TAB.width)) +
Blockly.utils.svgPaths.lineOnAxis('v', this.constants_.TAB_OFFSET_FROM_TOP) +
this.constants_.PUZZLE_TAB.pathDown +
Blockly.utils.svgPaths.lineOnAxis('V', height) +
Blockly.utils.svgPaths.lineOnAxis('H', width);
this.cursorBlock_.setAttribute('d', cursorPath);
};
/**
* Position the cursor for a previous connection.
* Displays a half rectangle with a notch in the top to represent the previous
* conenction.
* @param {!number} width The width of the block.
* @param {!number} cursorOffset The offset of the cursor from around the block.
* @param {!number} cursorHeight The height of the cursor.
* @private
*/
Blockly.CursorSvg.prototype.positionPrevious_ = function(width, cursorOffset, cursorHeight) {
var cursorPath = Blockly.utils.svgPaths.moveBy(-1 * cursorOffset, cursorHeight) +
Blockly.utils.svgPaths.lineOnAxis('V', -1 * cursorOffset) +
Blockly.utils.svgPaths.lineOnAxis('H', this.constants_.NOTCH_OFFSET_LEFT) +
this.constants_.NOTCH.pathLeft +
Blockly.utils.svgPaths.lineOnAxis('H', width + cursorOffset * 2) +
Blockly.utils.svgPaths.lineOnAxis('V', cursorHeight);
this.cursorBlock_.setAttribute('d', cursorPath);
this.cursorInput_.setAttribute('transform', ' scale(-1 1)');
};
/**
* Move and show the cursor at the specified coordinate in workspace units.
* Displays a filled in rectangle.
* @param {!number} x The new x, in workspace units.
* @param {!number} y The new y, in workspace units.
* @param {!number} width The new width, in workspace units.
* @param {!number} height The new height, in workspace units.
* @private
*/
Blockly.CursorSvg.prototype.positionRect_ = function(x, y, width, height) {
this.cursorSvgRect_.setAttribute('x', x);
this.cursorSvgRect_.setAttribute('y', y);
this.cursorSvgRect_.setAttribute('width', width);
this.cursorSvgRect_.setAttribute('height', height);
};
/**
* Hide the cursor.
* @package
*/
Blockly.CursorSvg.prototype.hide = function() {
this.cursorSvgLine_.style.display = 'none';
this.cursorSvgRect_.style.display = 'none';
this.cursorInputOutput_.style.display = 'none';
this.cursorInput_.style.display = 'none';
this.cursorBlock_.style.display = 'none';
};
/**
* Update the cursor.
* @param {!Blockly.ASTNode} curNode The node that we want to draw the cursor for.
* @param {Blockly.ASTNode} curNode The node that we want to draw the cursor for.
* @package
*/
Blockly.CursorSvg.prototype.draw = function(curNode) {
@@ -392,16 +463,18 @@ Blockly.CursorSvg.prototype.draw = function(curNode) {
return;
}
if (curNode.getType() === Blockly.ASTNode.types.BLOCK) {
this.showWithBlock_(curNode);
// This needs to be the location type because next connections can be input
// type but they need to draw like they are a next statement
} else if (curNode.getLocation().type === Blockly.INPUT_VALUE ||
curNode.getType() === Blockly.ASTNode.types.OUTPUT) {
this.showWithInputOutput_(curNode);
var block = /** @type {Blockly.BlockSvg} */ (curNode.getLocation());
this.showWithBlockPrevOutput_(block);
} else if (curNode.getType() === Blockly.ASTNode.types.OUTPUT) {
var outputBlock = /** @type {Blockly.BlockSvg} */ (curNode.getLocation().getSourceBlock());
this.showWithBlockPrevOutput_(outputBlock);
} else if (curNode.getLocation().type === Blockly.INPUT_VALUE) {
this.showWithInput_(curNode);
} else if (curNode.getLocation().type === Blockly.NEXT_STATEMENT) {
this.showWithNext_(curNode);
} else if (curNode.getType() === Blockly.ASTNode.types.PREVIOUS) {
this.showWithPrev_(curNode);
var previousBlock = /** @type {Blockly.BlockSvg} */ (curNode.getLocation().getSourceBlock());
this.showWithBlockPrevOutput_(previousBlock);
} else if (curNode.getType() === Blockly.ASTNode.types.FIELD) {
this.showWithField_(curNode);
} else if (curNode.getType() === Blockly.ASTNode.types.WORKSPACE) {
@@ -434,6 +507,7 @@ Blockly.CursorSvg.prototype.createCursorSvg_ = function() {
'height': Blockly.CursorSvg.CURSOR_HEIGHT
}, this.svgGroup_);
// A horizontal line used to represent a workspace coordinate or next connection.
this.cursorSvgLine_ = Blockly.utils.dom.createSvgElement('rect',
{
'x': '0',
@@ -445,6 +519,7 @@ Blockly.CursorSvg.prototype.createCursorSvg_ = function() {
},
this.cursorSvg_);
// A filled in rectangle used to represent a stack.
this.cursorSvgRect_ = Blockly.utils.dom.createSvgElement('rect',
{
'class': 'blocklyVerticalCursor',
@@ -456,7 +531,8 @@ Blockly.CursorSvg.prototype.createCursorSvg_ = function() {
},
this.cursorSvg_);
this.cursorInputOutput_ = Blockly.utils.dom.createSvgElement(
// A filled in puzzle piece used to represent an input value.
this.cursorInput_ = Blockly.utils.dom.createSvgElement(
'path',
{
'width': Blockly.CursorSvg.CURSOR_WIDTH,
@@ -467,7 +543,22 @@ Blockly.CursorSvg.prototype.createCursorSvg_ = function() {
},
this.cursorSvg_);
// Markers don't blink.
// A path used to repreesent a previous connection and a block, an output
// connection and a block, or a block.
this.cursorBlock_ = Blockly.utils.dom.createSvgElement(
'path',
{
'width': Blockly.CursorSvg.CURSOR_WIDTH,
'height': Blockly.CursorSvg.CURSOR_HEIGHT,
'transform':'',
'style':'display: none;',
'fill': 'none',
'stroke': colour,
'stroke-width': '4'
},
this.cursorSvg_);
// Markers and stack cursors don't blink.
if (!this.isMarker_) {
Blockly.utils.dom.createSvgElement('animate',
{
@@ -487,7 +578,17 @@ Blockly.CursorSvg.prototype.createCursorSvg_ = function() {
'values': Blockly.CursorSvg.CURSOR_COLOR + ';transparent;transparent;',
'repeatCount': 'indefinite'
},
this.cursorInputOutput_);
this.cursorInput_);
Blockly.utils.dom.createSvgElement('animate',
{
'attributeType': 'XML',
'attributeName': 'stroke',
'dur': '1s',
'values': Blockly.CursorSvg.CURSOR_COLOR + ';transparent;transparent;',
'repeatCount': 'indefinite'
},
this.cursorBlock_);
}
return this.cursorSvg_;
@@ -495,6 +596,7 @@ Blockly.CursorSvg.prototype.createCursorSvg_ = function() {
/**
* Dispose of this cursor.
* @package
*/
Blockly.CursorSvg.prototype.dispose = function() {
if (this.svgGroup_) {

View File

@@ -48,7 +48,7 @@ Blockly.navigation.currentCategory_ = null;
* Null by default.
* The first argument is one of 'log', 'warn', and 'error'.
* The second argument is the message.
* @type {function(string, string)}
* @type {?function(string, string)}
* @public
*/
Blockly.navigation.loggingCallback = null;
@@ -99,18 +99,18 @@ Blockly.navigation.actionNames = {
/**
* Move the marker to the cursor's current location.
* @package
* @private
*/
Blockly.navigation.markAtCursor = function() {
Blockly.navigation.markAtCursor_ = function() {
Blockly.getMainWorkspace().getMarker().setLocation(
Blockly.getMainWorkspace().getCursor().getCurNode());
};
/**
* Remove the marker from its current location and hide it.
* @package
* @private
*/
Blockly.navigation.removeMark = function() {
Blockly.navigation.removeMark_ = function() {
Blockly.getMainWorkspace().getMarker().setLocation(null);
Blockly.getMainWorkspace().getMarker().hide();
};
@@ -143,15 +143,16 @@ Blockly.navigation.getTopNode = function(block) {
/**
* Set the state to the toolbox state and the current category as the first
* category.
* @private
*/
Blockly.navigation.focusToolbox = function() {
Blockly.navigation.resetFlyout(false /* shouldHide */);
Blockly.navigation.focusToolbox_ = function() {
Blockly.navigation.resetFlyout_(false /* shouldHide */);
Blockly.navigation.currentState_ = Blockly.navigation.STATE_TOOLBOX;
var workspace = Blockly.getMainWorkspace();
var toolbox = workspace.getToolbox();
if (!Blockly.getMainWorkspace().getMarker().getCurNode()) {
Blockly.navigation.markAtCursor();
Blockly.navigation.markAtCursor_();
}
if (workspace && !Blockly.navigation.currentCategory_) {
Blockly.navigation.currentCategory_ = toolbox.tree_.firstChild_;
@@ -162,8 +163,9 @@ Blockly.navigation.focusToolbox = function() {
/**
* Select the next category.
* Taken from closure/goog/ui/tree/basenode.js
* @private
*/
Blockly.navigation.nextCategory = function() {
Blockly.navigation.nextCategory_ = function() {
if (!Blockly.navigation.currentCategory_) {
return;
}
@@ -179,8 +181,9 @@ Blockly.navigation.nextCategory = function() {
/**
* Select the previous category.
* Taken from closure/goog/ui/tree/basenode.js
* @private
*/
Blockly.navigation.previousCategory = function() {
Blockly.navigation.previousCategory_ = function() {
if (!Blockly.navigation.currentCategory_) {
return;
}
@@ -196,8 +199,9 @@ Blockly.navigation.previousCategory = function() {
/**
* Go to child category if there is a nested category.
* Taken from closure/goog/ui/tree/basenode.js
* @private
*/
Blockly.navigation.inCategory = function() {
Blockly.navigation.inCategory_ = function() {
if (!Blockly.navigation.currentCategory_) {
return;
}
@@ -211,15 +215,16 @@ Blockly.navigation.inCategory = function() {
Blockly.navigation.currentCategory_ = curCategory.getFirstChild();
}
} else {
Blockly.navigation.focusFlyout();
Blockly.navigation.focusFlyout_();
}
};
/**
* Go to parent category if we are in a child category.
* Taken from closure/goog/ui/tree/basenode.js
* @private
*/
Blockly.navigation.outCategory = function() {
Blockly.navigation.outCategory_ = function() {
if (!Blockly.navigation.currentCategory_) {
return;
}
@@ -245,8 +250,9 @@ Blockly.navigation.outCategory = function() {
/**
* Change focus to the flyout.
* @private
*/
Blockly.navigation.focusFlyout = function() {
Blockly.navigation.focusFlyout_ = function() {
var topBlock = null;
Blockly.navigation.currentState_ = Blockly.navigation.STATE_FLYOUT;
var workspace = Blockly.getMainWorkspace();
@@ -254,7 +260,7 @@ Blockly.navigation.focusFlyout = function() {
var flyout = toolbox ? toolbox.flyout_ : workspace.getFlyout();
if (!Blockly.getMainWorkspace().getMarker().getCurNode()) {
Blockly.navigation.markAtCursor();
Blockly.navigation.markAtCursor_();
}
if (flyout && flyout.getWorkspace()) {
@@ -270,6 +276,7 @@ Blockly.navigation.focusFlyout = function() {
/**
* Get the cursor from the flyouts workspace.
* @return {Blockly.FlyoutCursor} The flyouts cursor or null if no flyout exists.
* @private
*/
Blockly.navigation.getFlyoutCursor_ = function() {
var workspace = Blockly.getMainWorkspace();
@@ -290,7 +297,7 @@ Blockly.navigation.getFlyoutCursor_ = function() {
Blockly.navigation.insertFromFlyout = function() {
var flyout = Blockly.getMainWorkspace().getFlyout();
if (!flyout || !flyout.isVisible()) {
Blockly.navigation.warn('Trying to insert from the flyout when the flyout does not ' +
Blockly.navigation.warn_('Trying to insert from the flyout when the flyout does not ' +
' exist or is not visible');
return;
}
@@ -306,19 +313,20 @@ Blockly.navigation.insertFromFlyout = function() {
Blockly.getMainWorkspace().getCursor().setLocation(
Blockly.ASTNode.createBlockNode(newBlock));
if (!Blockly.navigation.modify_()) {
Blockly.navigation.warn('Something went wrong while inserting a block from the flyout.');
Blockly.navigation.warn_('Something went wrong while inserting a block from the flyout.');
}
Blockly.navigation.focusWorkspace();
Blockly.navigation.focusWorkspace_();
Blockly.getMainWorkspace().getCursor().setLocation(Blockly.navigation.getTopNode(newBlock));
Blockly.navigation.removeMark();
Blockly.navigation.removeMark_();
};
/**
* Reset flyout information, and optionally close the flyout.
* @param {boolean} shouldHide True if the flyout should be hidden.
* @private
*/
Blockly.navigation.resetFlyout = function(shouldHide) {
Blockly.navigation.resetFlyout_ = function(shouldHide) {
if (Blockly.navigation.getFlyoutCursor_()) {
Blockly.navigation.getFlyoutCursor_().hide();
if (shouldHide) {
@@ -342,12 +350,12 @@ Blockly.navigation.modifyWarn_ = function() {
var cursorNode = Blockly.getMainWorkspace().getCursor().getCurNode();
if (!markerNode) {
Blockly.navigation.warn('Cannot insert with no marked node.');
Blockly.navigation.warn_('Cannot insert with no marked node.');
return false;
}
if (!cursorNode) {
Blockly.navigation.warn('Cannot insert with no cursor node.');
Blockly.navigation.warn_('Cannot insert with no cursor node.');
return false;
}
var markerType = markerNode.getType();
@@ -355,22 +363,22 @@ Blockly.navigation.modifyWarn_ = function() {
// Check the marker for invalid types.
if (markerType == Blockly.ASTNode.types.FIELD) {
Blockly.navigation.warn('Should not have been able to mark a field.');
Blockly.navigation.warn_('Should not have been able to mark a field.');
return false;
} else if (markerType == Blockly.ASTNode.types.BLOCK) {
Blockly.navigation.warn('Should not have been able to mark a block.');
Blockly.navigation.warn_('Should not have been able to mark a block.');
return false;
} else if (markerType == Blockly.ASTNode.types.STACK) {
Blockly.navigation.warn('Should not have been able to mark a stack.');
Blockly.navigation.warn_('Should not have been able to mark a stack.');
return false;
}
// Check the cursor for invalid types.
if (cursorType == Blockly.ASTNode.types.FIELD) {
Blockly.navigation.warn('Cannot attach a field to anything else.');
Blockly.navigation.warn_('Cannot attach a field to anything else.');
return false;
} else if (cursorType == Blockly.ASTNode.types.WORKSPACE) {
Blockly.navigation.warn('Cannot attach a workspace to anything else.');
Blockly.navigation.warn_('Cannot attach a workspace to anything else.');
return false;
}
return true;
@@ -388,7 +396,7 @@ Blockly.navigation.modifyWarn_ = function() {
*/
Blockly.navigation.moveBlockToWorkspace_ = function(block, wsNode) {
if (block.isShadow()) {
Blockly.navigation.warn('Cannot move a shadow block to the workspace.');
Blockly.navigation.warn_('Cannot move a shadow block to the workspace.');
return false;
}
if (block.getParent()) {
@@ -419,7 +427,7 @@ Blockly.navigation.modify_ = function() {
var markerLoc = markerNode.getLocation();
if (markerNode.isConnection() && cursorNode.isConnection()) {
return Blockly.navigation.connect(cursorLoc, markerLoc);
return Blockly.navigation.connect_(cursorLoc, markerLoc);
} else if (markerNode.isConnection() &&
(cursorType == Blockly.ASTNode.types.BLOCK ||
cursorType == Blockly.ASTNode.types.STACK)) {
@@ -428,7 +436,7 @@ Blockly.navigation.modify_ = function() {
var block = Blockly.navigation.getSourceBlock_(cursorNode);
return Blockly.navigation.moveBlockToWorkspace_(block, markerNode);
}
Blockly.navigation.warn('Unexpected state in Blockly.navigation.modify_.');
Blockly.navigation.warn_('Unexpected state in Blockly.navigation.modify_.');
return false;
};
@@ -445,7 +453,7 @@ Blockly.navigation.disconnectChild_ = function(movingConnection, destConnection)
var destBlock = destConnection.getSourceBlock();
if (movingBlock.getRootBlock() == destBlock.getRootBlock()) {
if (movingBlock.getDescendants().indexOf(destBlock) > -1) {
if (movingBlock.getDescendants(false).indexOf(destBlock) > -1) {
Blockly.navigation.getInferiorConnection_(destConnection).disconnect();
} else {
Blockly.navigation.getInferiorConnection_(movingConnection).disconnect();
@@ -530,9 +538,9 @@ Blockly.navigation.getSuperiorConnection_ = function(connection) {
* @param {Blockly.Connection} destConnection The connection to be moved to.
* @return {boolean} True if the two connections or their target connections
* were connected, false otherwise.
* @package
* @private
*/
Blockly.navigation.connect = function(movingConnection, destConnection) {
Blockly.navigation.connect_ = function(movingConnection, destConnection) {
if (!movingConnection || !destConnection) {
return false;
}
@@ -558,7 +566,7 @@ Blockly.navigation.connect = function(movingConnection, destConnection) {
}
catch (e) {
// If nothing worked report the error from the original connections.
Blockly.navigation.warn('Connection failed with error: ' + e);
Blockly.navigation.warn_('Connection failed with error: ' + e);
}
return false;
}
@@ -598,7 +606,7 @@ Blockly.navigation.insertBlock = function(block, destConnection) {
}
break;
}
Blockly.navigation.warn('This block can not be inserted at the marked location.');
Blockly.navigation.warn_('This block can not be inserted at the marked location.');
return false;
};
@@ -606,17 +614,17 @@ Blockly.navigation.insertBlock = function(block, destConnection) {
* Disconnect the connection that the cursor is pointing to, and bump blocks.
* This is a no-op if the connection cannot be broken or if the cursor is not
* pointing to a connection.
* @package
* @private
*/
Blockly.navigation.disconnectBlocks = function() {
Blockly.navigation.disconnectBlocks_ = function() {
var curNode = Blockly.getMainWorkspace().getCursor().getCurNode();
if (!curNode.isConnection()) {
Blockly.navigation.log('Cannot disconnect blocks when the cursor is not on a connection');
Blockly.navigation.log_('Cannot disconnect blocks when the cursor is not on a connection');
return;
}
var curConnection = curNode.getLocation();
if (!curConnection.isConnected()) {
Blockly.navigation.log('Cannot disconnect unconnected connection');
Blockly.navigation.log_('Cannot disconnect unconnected connection');
return;
}
var superiorConnection =
@@ -626,7 +634,7 @@ Blockly.navigation.disconnectBlocks = function() {
curConnection.isSuperior() ? curConnection.targetConnection : curConnection;
if (inferiorConnection.getSourceBlock().isShadow()) {
Blockly.navigation.log('Cannot disconnect a shadow block');
Blockly.navigation.log_('Cannot disconnect a shadow block');
return;
}
superiorConnection.disconnect();
@@ -646,14 +654,15 @@ Blockly.navigation.disconnectBlocks = function() {
/**
* Finds where the cursor should go on the workspace. This is either the top
* block or a set position on the workspace.
* @private
*/
Blockly.navigation.focusWorkspace = function() {
Blockly.navigation.focusWorkspace_ = function() {
Blockly.hideChaff();
var cursor = Blockly.getMainWorkspace().getCursor();
var reset = Blockly.getMainWorkspace().getToolbox() ? true : false;
var topBlocks = Blockly.getMainWorkspace().getTopBlocks();
Blockly.navigation.resetFlyout(reset);
Blockly.navigation.resetFlyout_(reset);
Blockly.navigation.currentState_ = Blockly.navigation.STATE_WS;
if (topBlocks.length > 0) {
cursor.setLocation(Blockly.navigation.getTopNode(topBlocks[0]));
@@ -668,8 +677,9 @@ Blockly.navigation.focusWorkspace = function() {
/**
* Handles hitting the enter key on the workspace.
* @private
*/
Blockly.navigation.handleEnterForWS = function() {
Blockly.navigation.handleEnterForWS_ = function() {
var cursor = Blockly.getMainWorkspace().getCursor();
var curNode = cursor.getCurNode();
var nodeType = curNode.getType();
@@ -678,11 +688,11 @@ Blockly.navigation.handleEnterForWS = function() {
location.showEditor_();
} else if (curNode.isConnection() ||
nodeType == Blockly.ASTNode.types.WORKSPACE) {
Blockly.navigation.markAtCursor();
Blockly.navigation.markAtCursor_();
} else if (nodeType == Blockly.ASTNode.types.BLOCK) {
Blockly.navigation.warn('Cannot mark a block.');
Blockly.navigation.warn_('Cannot mark a block.');
} else if (nodeType == Blockly.ASTNode.types.STACK) {
Blockly.navigation.warn('Cannot mark a stack.');
Blockly.navigation.warn_('Cannot mark a stack.');
}
};
@@ -715,7 +725,6 @@ Blockly.navigation.getSourceBlock_ = function(node) {
/**
* Before a block is deleted move the cursor to the appropriate position.
* @param {!Blockly.Block} deletedBlock The block that is being deleted.
* @package
*/
Blockly.navigation.moveCursorOnBlockDelete = function(deletedBlock) {
if (!Blockly.getMainWorkspace()) {
@@ -769,7 +778,7 @@ Blockly.navigation.moveCursorOnBlockMutation = function(mutatedBlock) {
/**
* Handler for all the keyboard navigation events.
* @param {Event} e The keyboard event.
* @param {!Event} e The keyboard event.
* @return {boolean} True if the key was handled false otherwise.
*/
Blockly.navigation.onKeyPress = function(e) {
@@ -825,9 +834,9 @@ Blockly.navigation.handleActions_ = function(action) {
return true;
} else if (action.name === Blockly.navigation.actionNames.TOOLBOX) {
if (!Blockly.getMainWorkspace().getToolbox()) {
Blockly.navigation.focusFlyout();
Blockly.navigation.focusFlyout_();
} else {
Blockly.navigation.focusToolbox();
Blockly.navigation.focusToolbox_();
}
return true;
} else if (Blockly.navigation.currentState_ === Blockly.navigation.STATE_WS) {
@@ -864,10 +873,10 @@ Blockly.navigation.workspaceOnAction_ = function(action) {
Blockly.navigation.modify_();
return true;
case Blockly.navigation.actionNames.MARK:
Blockly.navigation.handleEnterForWS();
Blockly.navigation.handleEnterForWS_();
return true;
case Blockly.navigation.actionNames.DISCONNECT:
Blockly.navigation.disconnectBlocks();
Blockly.navigation.disconnectBlocks_();
return true;
default:
return false;
@@ -886,7 +895,7 @@ Blockly.navigation.flyoutOnAction_ = function(action) {
Blockly.navigation.getFlyoutCursor_().prev();
return true;
case Blockly.navigation.actionNames.OUT:
Blockly.navigation.focusToolbox();
Blockly.navigation.focusToolbox_();
return true;
case Blockly.navigation.actionNames.NEXT:
Blockly.navigation.getFlyoutCursor_().next();
@@ -895,7 +904,7 @@ Blockly.navigation.flyoutOnAction_ = function(action) {
Blockly.navigation.insertFromFlyout();
return true;
case Blockly.navigation.actionNames.EXIT:
Blockly.navigation.focusWorkspace();
Blockly.navigation.focusWorkspace_();
return true;
default:
return false;
@@ -911,19 +920,19 @@ Blockly.navigation.flyoutOnAction_ = function(action) {
Blockly.navigation.toolboxOnAction_ = function(action) {
switch (action.name) {
case Blockly.navigation.actionNames.PREVIOUS:
Blockly.navigation.previousCategory();
Blockly.navigation.previousCategory_();
return true;
case Blockly.navigation.actionNames.OUT:
Blockly.navigation.outCategory();
Blockly.navigation.outCategory_();
return true;
case Blockly.navigation.actionNames.NEXT:
Blockly.navigation.nextCategory();
Blockly.navigation.nextCategory_();
return true;
case Blockly.navigation.actionNames.IN:
Blockly.navigation.inCategory();
Blockly.navigation.inCategory_();
return true;
case Blockly.navigation.actionNames.EXIT:
Blockly.navigation.focusWorkspace();
Blockly.navigation.focusWorkspace_();
return true;
default:
return false;
@@ -936,7 +945,7 @@ Blockly.navigation.toolboxOnAction_ = function(action) {
Blockly.navigation.enableKeyboardAccessibility = function() {
if (!Blockly.keyboardAccessibilityMode) {
Blockly.keyboardAccessibilityMode = true;
Blockly.navigation.focusWorkspace();
Blockly.navigation.focusWorkspace_();
}
};
@@ -960,7 +969,7 @@ Blockly.navigation.disableKeyboardAccessibility = function() {
* @param {string} msg The message to log.
* @package
*/
Blockly.navigation.log = function(msg) {
Blockly.navigation.log_ = function(msg) {
if (Blockly.navigation.loggingCallback) {
Blockly.navigation.loggingCallback('log', msg);
} else {
@@ -970,11 +979,11 @@ Blockly.navigation.log = function(msg) {
/**
* Navigation warning handler. If loggingCallback is defined, use it.
* Otherwise call Blockly.navigation.warn.
* Otherwise call Blockly.navigation.warn_.
* @param {string} msg The warning message.
* @package
*/
Blockly.navigation.warn = function(msg) {
Blockly.navigation.warn_ = function(msg) {
if (Blockly.navigation.loggingCallback) {
Blockly.navigation.loggingCallback('warn', msg);
} else {
@@ -988,7 +997,7 @@ Blockly.navigation.warn = function(msg) {
* @param {string} msg The error message.
* @package
*/
Blockly.navigation.error = function(msg) {
Blockly.navigation.error_ = function(msg) {
if (Blockly.navigation.loggingCallback) {
Blockly.navigation.loggingCallback('error', msg);
} else {

View File

@@ -120,14 +120,14 @@ Blockly.Workspace = function(opt_options) {
/**
* The cursor used to navigate around the AST for keyboard navigation.
* @type {Blockly.Cursor}
* @private
* @protected
*/
this.cursor_ = null;
/**
* The marker used to mark a location for keyboard navigation.
* @type {Blockly.MarkerCursor}
* @private
* @protected
*/
this.marker_ = null;

View File

@@ -113,6 +113,22 @@ Blockly.WorkspaceSvg = function(options,
this.grid_ = this.options.gridPattern ?
new Blockly.Grid(options.gridPattern, options.gridOptions) : null;
/**
* Holds the cursors svg element when the cursor is attached to the workspace.
* This is null if there is no cursor on the workspace.
* @type {SVGElement}
* @private
*/
this.cursorSvg_ = null;
/**
* Holds the markers svg element when the marker is attached to the workspace.
* This is null if there is no marker on the workspace.
* @type {SVGElement}
* @private
*/
this.markerSvg_ = null;
if (Blockly.Variables && Blockly.Variables.flyoutCategory) {
this.registerToolboxCategoryCallback(Blockly.VARIABLE_CATEGORY_NAME,
Blockly.Variables.flyoutCategory);
@@ -410,32 +426,74 @@ Blockly.WorkspaceSvg.prototype.getRenderer = function() {
/**
* Sets the cursor for use with keyboard navigation.
* @param {!Blockly.Cursor} cursor The cursor used to move around this workspace.
* @param {Blockly.Cursor} cursor The cursor used to move around this workspace.
* @override
*/
Blockly.WorkspaceSvg.prototype.setCursor = function(cursor) {
if (this.cursor_) {
this.cursor_.getDrawer().dispose();
}
this.cursor_ = cursor;
this.cursor_.setDrawer(new Blockly.CursorSvg(this, false));
if (this.svgGroup_) {
this.svgGroup_.appendChild(this.cursor_.getDrawer().createDom());
if (this.cursor_) {
this.cursor_.setDrawer(new Blockly.CursorSvg(this, false));
this.setCursorSvg(this.cursor_.getDrawer().createDom());
}
};
/**
* Sets the marker for use with keyboard navigation.
* @param {!Blockly.MarkerCursor} marker The immovable cursor used to mark a
* @param {Blockly.MarkerCursor} marker The immovable cursor used to mark a
* location on the workspace.
* @override
*/
Blockly.WorkspaceSvg.prototype.setMarker = function(marker) {
if (this.marker_) {
this.marker_.getDrawer().dispose();
}
this.marker_ = marker;
this.marker_.setDrawer(new Blockly.CursorSvg(this, true));
if (this.marker_) {
this.marker_.setDrawer(new Blockly.CursorSvg(this, true));
this.setMarkerSvg(this.marker_.getDrawer().createDom());
}
};
/**
* Add the cursor svg to this workspaces svg group.
* @param {SVGElement} cursorSvg The svg root of the cursor to be added to the
* workspace svg group.
* @package
*/
Blockly.WorkspaceSvg.prototype.setCursorSvg = function(cursorSvg) {
if (!cursorSvg) {
this.cursorSvg_ = null;
return;
}
if (this.svgGroup_) {
this.svgGroup_.appendChild(this.marker_.getDrawer().createDom());
this.svgGroup_.appendChild(cursorSvg);
this.cursorSvg_ = cursorSvg;
}
};
/**
* Add the marker svg to this workspaces svg group.
* @param {SVGElement} markerSvg The svg root of the marker to be added to the
* workspace svg group.
* @package
*/
Blockly.WorkspaceSvg.prototype.setMarkerSvg = function(markerSvg) {
if (!markerSvg) {
this.markerSvg_ = null;
return;
}
if (this.svgGroup_) {
if (this.cursorSvg_) {
this.svgGroup_.insertBefore(markerSvg, this.cursorSvg_);
} else {
this.svgGroup_.appendChild(markerSvg);
}
this.markerSvg_ = markerSvg;
}
};
@@ -657,8 +715,8 @@ Blockly.WorkspaceSvg.prototype.dispose = function() {
this.marker_.getDrawer().dispose();
}
if (this.cursor_) {
this.cursor_.getDrawer().dispose();
if (this.getCursor()) {
this.getCursor().getDrawer().dispose();
}
if (this.audioManager_) {

View File

@@ -102,6 +102,6 @@ suite('Cursor', function() {
this.cursor.setLocation(prevConnectionNode);
this.cursor.prev();
var curNode = this.cursor.getCurNode();
assertEquals(curNode.getLocation(), this.blocks.A);
assertEquals(curNode.getLocation(), this.blocks.A.previousConnection);
});
});

View File

@@ -87,6 +87,8 @@ suite('Gesture', function() {
test('Workspace click - Shift click enters accessibility mode', function() {
var event = {
shiftKey : true,
clientX : 10,
clientY : 10,
};
var ws = Blockly.inject('blocklyDiv', {});

View File

@@ -17,7 +17,7 @@ suite('Navigation', function() {
}]);
var toolbox = document.getElementById('toolbox-categories');
this.workspace = Blockly.inject('blocklyDiv', {toolbox: toolbox});
Blockly.navigation.focusToolbox();
Blockly.navigation.focusToolbox_();
this.mockEvent = {
getModifierState: function() {
return false;
@@ -45,7 +45,7 @@ suite('Navigation', function() {
// Should be a no-op.
test('Next at end', function() {
Blockly.navigation.nextCategory();
Blockly.navigation.nextCategory_();
this.mockEvent.keyCode = Blockly.utils.KeyCodes.S;
var startCategory = Blockly.navigation.currentCategory_;
chai.assert.isTrue(Blockly.navigation.onKeyPress(this.mockEvent));
@@ -57,7 +57,7 @@ suite('Navigation', function() {
test('Previous', function() {
// Go forward one so that we can go back one:
Blockly.navigation.nextCategory();
Blockly.navigation.nextCategory_();
this.mockEvent.keyCode = Blockly.utils.KeyCodes.W;
chai.assert.equal(Blockly.navigation.currentCategory_,
this.secondCategory_);
@@ -134,8 +134,8 @@ suite('Navigation', function() {
}]);
var toolbox = document.getElementById('toolbox-categories');
this.workspace = Blockly.inject('blocklyDiv', {toolbox: toolbox});
Blockly.navigation.focusToolbox();
Blockly.navigation.focusFlyout();
Blockly.navigation.focusToolbox_();
Blockly.navigation.focusFlyout_();
this.mockEvent = {
getModifierState: function() {
return false;
@@ -383,14 +383,14 @@ suite('Navigation', function() {
test('Toggle Action On', function() {
this.mockEvent.keyCode = 'Control75';
sinon.stub(Blockly.navigation, 'focusWorkspace');
sinon.stub(Blockly.navigation, 'focusWorkspace_');
Blockly.keyboardAccessibilityMode = false;
var isHandled = Blockly.navigation.onKeyPress(this.mockEvent);
chai.assert.isTrue(isHandled);
chai.assert.isTrue(Blockly.navigation.focusWorkspace.calledOnce);
chai.assert.isTrue(Blockly.navigation.focusWorkspace_.calledOnce);
chai.assert.isTrue(Blockly.keyboardAccessibilityMode);
Blockly.navigation.focusWorkspace.restore();
Blockly.navigation.focusWorkspace_.restore();
this.workspace.dispose();
});
@@ -493,8 +493,8 @@ suite('Navigation', function() {
var prevNode = Blockly.ASTNode.createConnectionNode(previousConnection);
this.workspace.getMarker().setLocation(prevNode);
Blockly.navigation.focusToolbox();
Blockly.navigation.focusFlyout();
Blockly.navigation.focusToolbox_();
Blockly.navigation.focusFlyout_();
Blockly.navigation.insertFromFlyout();
var insertedBlock = this.basicBlock.previousConnection.targetBlock();
@@ -505,8 +505,8 @@ suite('Navigation', function() {
});
test('Insert Block from flyout without marking a connection', function() {
Blockly.navigation.focusToolbox();
Blockly.navigation.focusFlyout();
Blockly.navigation.focusToolbox_();
Blockly.navigation.focusFlyout_();
Blockly.navigation.insertFromFlyout();
var numBlocks = this.workspace.getTopBlocks().length;
@@ -599,7 +599,7 @@ suite('Navigation', function() {
var markedLocation = this.basicBlock2.previousConnection;
var cursorLocation = this.basicBlock3.previousConnection;
Blockly.navigation.connect(cursorLocation, markedLocation);
Blockly.navigation.connect_(cursorLocation, markedLocation);
chai.assert.equal(this.basicBlock.nextConnection.targetBlock(), this.basicBlock3);
chai.assert.equal(this.basicBlock2.previousConnection.targetBlock(), this.basicBlock4);
@@ -609,7 +609,7 @@ suite('Navigation', function() {
var markedLocation = this.basicBlock3.previousConnection;
var cursorLocation = this.basicBlock2.previousConnection;
Blockly.navigation.connect(cursorLocation, markedLocation);
Blockly.navigation.connect_(cursorLocation, markedLocation);
chai.assert.equal(this.basicBlock.nextConnection.targetBlock(), this.basicBlock3);
chai.assert.equal(this.basicBlock2.previousConnection.targetBlock(), this.basicBlock4);
@@ -620,7 +620,7 @@ suite('Navigation', function() {
var markedLocation = this.basicBlock2.previousConnection;
var cursorLocation = this.basicBlock4.nextConnection;
Blockly.navigation.connect(cursorLocation, markedLocation);
Blockly.navigation.connect_(cursorLocation, markedLocation);
chai.assert.equal(this.basicBlock.nextConnection.targetBlock(), this.basicBlock4);
chai.assert.equal(this.basicBlock3.nextConnection.targetConnection, null);
@@ -630,7 +630,7 @@ suite('Navigation', function() {
var markedLocation = this.basicBlock3.previousConnection;
var cursorLocation = this.basicBlock2.nextConnection;
Blockly.navigation.connect(cursorLocation, markedLocation);
Blockly.navigation.connect_(cursorLocation, markedLocation);
chai.assert.equal(this.basicBlock3.previousConnection.targetBlock(), this.basicBlock2);
});
@@ -639,7 +639,7 @@ suite('Navigation', function() {
var markedLocation = this.inlineBlock2.inputList[0].connection;
var cursorLocation = this.inlineBlock1.outputConnection;
Blockly.navigation.connect(cursorLocation, markedLocation);
Blockly.navigation.connect_(cursorLocation, markedLocation);
chai.assert.equal(this.inlineBlock2.outputConnection.targetBlock(), null);
chai.assert.equal(this.inlineBlock1.outputConnection.targetBlock(), this.inlineBlock2);