mirror of
https://github.com/google/blockly.git
synced 2026-01-04 15:40:08 +01:00
@@ -1,209 +0,0 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2019 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview The class representing a basic cursor.
|
||||
* Used to demo switching between different cursors.
|
||||
* @author aschmiedt@google.com (Abby Schmiedt)
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
|
||||
/**
|
||||
* Class for a basic cursor.
|
||||
* This will allow the user to get to all nodes in the AST by hitting next or
|
||||
* previous.
|
||||
* @constructor
|
||||
* @extends {Blockly.Cursor}
|
||||
*/
|
||||
Blockly.BasicCursor = function() {
|
||||
Blockly.BasicCursor.superClass_.constructor.call(this);
|
||||
};
|
||||
Blockly.utils.object.inherits(Blockly.BasicCursor, Blockly.Cursor);
|
||||
|
||||
/**
|
||||
* Decides what nodes to traverse and which ones to skip. Currently, it
|
||||
* skips output, stack and workspace nodes.
|
||||
* @param {Blockly.ASTNode} node The AST node to check whether it is valid.
|
||||
* @return {boolean} True if the node should be visited, false otherwise.
|
||||
* @private
|
||||
*/
|
||||
Blockly.BasicCursor.prototype.validNode_ = function(node) {
|
||||
var isValid = false;
|
||||
var type = node && node.getType();
|
||||
if (type == Blockly.ASTNode.types.OUTPUT ||
|
||||
type == Blockly.ASTNode.types.INPUT ||
|
||||
type == Blockly.ASTNode.types.FIELD ||
|
||||
type == Blockly.ASTNode.types.NEXT ||
|
||||
type == Blockly.ASTNode.types.PREVIOUS ||
|
||||
type == Blockly.ASTNode.types.WORKSPACE) {
|
||||
isValid = true;
|
||||
}
|
||||
return isValid;
|
||||
};
|
||||
|
||||
/**
|
||||
* From the given node find either the next valid sibling or parent.
|
||||
* @param {Blockly.ASTNode} node The current position in the AST.
|
||||
* @return {Blockly.ASTNode} The parent AST node or null if there are no
|
||||
* valid parents.
|
||||
* @private
|
||||
*/
|
||||
Blockly.BasicCursor.prototype.findSiblingOrParent_ = function(node) {
|
||||
if (!node) {
|
||||
return null;
|
||||
}
|
||||
var nextNode = node.next();
|
||||
if (nextNode) {
|
||||
return nextNode;
|
||||
}
|
||||
return this.findSiblingOrParent_(node.out());
|
||||
};
|
||||
|
||||
/**
|
||||
* Uses pre order traversal to navigate the Blockly AST. This will allow
|
||||
* a user to easily navigate the entire Blockly AST without having to go in
|
||||
* and out levels on the tree.
|
||||
* @param {Blockly.ASTNode} node The current position in the AST.
|
||||
* @return {Blockly.ASTNode} The next node in the traversal.
|
||||
* @private
|
||||
*/
|
||||
Blockly.BasicCursor.prototype.getNextNode_ = function(node) {
|
||||
if (!node) {
|
||||
return null;
|
||||
}
|
||||
var newNode = node.in() || node.next();
|
||||
if (this.validNode_(newNode)) {
|
||||
return newNode;
|
||||
} else if (newNode) {
|
||||
return this.getNextNode_(newNode);
|
||||
}
|
||||
var siblingOrParent = this.findSiblingOrParent_(node.out());
|
||||
if (this.validNode_(siblingOrParent)) {
|
||||
return siblingOrParent;
|
||||
} else if (siblingOrParent) {
|
||||
return this.getNextNode_(siblingOrParent);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the right most child of a node.
|
||||
* @param {Blockly.ASTNode} node The node to find the right most child of.
|
||||
* @return {Blockly.ASTNode} The right most child of the given node, or the node
|
||||
* if no child exists.
|
||||
* @private
|
||||
*/
|
||||
Blockly.BasicCursor.prototype.getRightMostChild_ = function(node) {
|
||||
if (!node.in()) {
|
||||
return node;
|
||||
}
|
||||
var newNode = node.in();
|
||||
while (newNode.next()) {
|
||||
newNode = newNode.next();
|
||||
}
|
||||
return this.getRightMostChild_(newNode);
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Reverses the pre order traversal in order to find the previous node. This will
|
||||
* allow a user to easily navigate the entire Blockly AST without having to go in
|
||||
* and out levels on the tree.
|
||||
* @param {Blockly.ASTNode} node The current position in the AST.
|
||||
* @return {Blockly.ASTNode} The previous node in the traversal or null if no
|
||||
* previous node exists.
|
||||
* @private
|
||||
*/
|
||||
Blockly.BasicCursor.prototype.getPreviousNode_ = function(node) {
|
||||
if (!node) {
|
||||
return null;
|
||||
}
|
||||
var newNode = node.prev();
|
||||
|
||||
if (newNode) {
|
||||
newNode = this.getRightMostChild_(newNode);
|
||||
} else {
|
||||
newNode = node.out();
|
||||
}
|
||||
if (this.validNode_(newNode)) {
|
||||
return newNode;
|
||||
} else if (newNode) {
|
||||
return this.getPreviousNode_(newNode);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Find the next node in the pre order traversal.
|
||||
* @return {Blockly.ASTNode} The next node, or null if the current node is
|
||||
* not set or there is no next value.
|
||||
* @override
|
||||
*/
|
||||
Blockly.BasicCursor.prototype.next = function() {
|
||||
var curNode = this.getCurNode();
|
||||
if (!curNode) {
|
||||
return null;
|
||||
}
|
||||
var newNode = this.getNextNode_(curNode);
|
||||
|
||||
if (newNode) {
|
||||
this.setCurNode(newNode);
|
||||
}
|
||||
return newNode;
|
||||
};
|
||||
|
||||
/**
|
||||
* For a basic cursor we only have the ability to go next and previous, so
|
||||
* in will also allow the user to get to the next node in the pre order traversal.
|
||||
* @return {Blockly.ASTNode} The next node, or null if the current node is
|
||||
* not set or there is no next value.
|
||||
* @override
|
||||
*/
|
||||
Blockly.BasicCursor.prototype.in = function() {
|
||||
return this.next();
|
||||
};
|
||||
|
||||
/**
|
||||
* Find the previous node in the pre order traversal.
|
||||
* @return {Blockly.ASTNode} The previous node, or null if the current node
|
||||
* is not set or there is no previous value.
|
||||
* @override
|
||||
*/
|
||||
Blockly.BasicCursor.prototype.prev = function() {
|
||||
var curNode = this.getCurNode();
|
||||
if (!curNode) {
|
||||
return null;
|
||||
}
|
||||
var newNode = this.getPreviousNode_(curNode);
|
||||
|
||||
if (newNode) {
|
||||
this.setCurNode(newNode);
|
||||
}
|
||||
return newNode;
|
||||
};
|
||||
|
||||
/**
|
||||
* For a basic cursor we only have the ability to go next and previou, so
|
||||
* out will allow the user to get to the previous node in the pre order traversal.
|
||||
* @return {Blockly.ASTNode} The previous node, or null if the current node is
|
||||
* not set or there is no previous value.
|
||||
* @override
|
||||
*/
|
||||
Blockly.BasicCursor.prototype.out = function() {
|
||||
return this.prev();
|
||||
};
|
||||
@@ -7,7 +7,7 @@
|
||||
<script src="../../blocks_compressed.js"></script>
|
||||
<script src="../../javascript_compressed.js"></script>
|
||||
<script src="../../msg/js/en.js"></script>
|
||||
<script src="basic_cursor.js"></script>
|
||||
<script src="line_cursor.js"></script>
|
||||
<style>
|
||||
body {
|
||||
background-color: #fff;
|
||||
@@ -88,6 +88,7 @@
|
||||
<select id="cursorChanger" name="cursor" onchange="changeCursor(this.value)">
|
||||
<option value="default">Default Cursor</option>
|
||||
<option value="basic">Basic Cursor</option>
|
||||
<option value="line">Line Cursor</option>
|
||||
</select>
|
||||
|
||||
<button onclick="preOrderDemo()">Start Pre-order Demo</button>
|
||||
@@ -290,8 +291,13 @@
|
||||
var oldCurNode = Blockly.getMainWorkspace().getCursor().getCurNode();
|
||||
|
||||
if (cursorType === "basic") {
|
||||
Blockly.ASTNode.NAVIGATE_ALL_FIELDS = false;
|
||||
Blockly.getMainWorkspace().setCursor(new Blockly.BasicCursor());
|
||||
} else if (cursorType === "line") {
|
||||
Blockly.ASTNode.NAVIGATE_ALL_FIELDS = true;
|
||||
Blockly.getMainWorkspace().setCursor(new Blockly.LineCursor());
|
||||
} else {
|
||||
Blockly.ASTNode.NAVIGATE_ALL_FIELDS = false;
|
||||
Blockly.getMainWorkspace().setCursor(new Blockly.Cursor());
|
||||
}
|
||||
if (oldCurNode) {
|
||||
|
||||
180
demos/keyboard_nav/line_cursor.js
Normal file
180
demos/keyboard_nav/line_cursor.js
Normal file
@@ -0,0 +1,180 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2019 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview The class representing a line cursor.
|
||||
* A line cursor traverses the blocks as if they were
|
||||
* lines of code in a text editor.
|
||||
* Previous and next go up and down lines. In and out go
|
||||
* through the elements in a line.
|
||||
* @author aschmiedt@google.com (Abby Schmiedt)
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
|
||||
/**
|
||||
* Class for a line cursor.
|
||||
* This will allow the user to get to all nodes in the AST by hitting next or
|
||||
* previous.
|
||||
* @constructor
|
||||
* @extends {Blockly.BasicCursor}
|
||||
*/
|
||||
Blockly.LineCursor = function() {
|
||||
Blockly.LineCursor.superClass_.constructor.call(this);
|
||||
};
|
||||
Blockly.utils.object.inherits(Blockly.LineCursor, Blockly.BasicCursor);
|
||||
|
||||
|
||||
/**
|
||||
* Find the next node in the pre order traversal.
|
||||
* @return {Blockly.ASTNode} The next node, or null if the current node is
|
||||
* not set or there is no next value.
|
||||
* @override
|
||||
*/
|
||||
Blockly.LineCursor.prototype.next = function() {
|
||||
var curNode = this.getCurNode();
|
||||
if (!curNode) {
|
||||
return null;
|
||||
}
|
||||
var newNode = this.getNextNode_(curNode, this.validLineNode_);
|
||||
|
||||
// Skip the input or next value if there is a connected block.
|
||||
if (newNode && (newNode.getType() == Blockly.ASTNode.types.INPUT ||
|
||||
newNode.getType() == Blockly.ASTNode.types.NEXT) &&
|
||||
newNode.getLocation().targetBlock()) {
|
||||
newNode = this.getNextNode_(newNode, this.validLineNode_);
|
||||
}
|
||||
if (newNode) {
|
||||
this.setCurNode(newNode);
|
||||
}
|
||||
return newNode;
|
||||
};
|
||||
|
||||
/**
|
||||
* For a basic cursor we only have the ability to go next and previous, so
|
||||
* in will also allow the user to get to the next node in the pre order traversal.
|
||||
* @return {Blockly.ASTNode} The next node, or null if the current node is
|
||||
* not set or there is no next value.
|
||||
* @override
|
||||
*/
|
||||
Blockly.LineCursor.prototype.in = function() {
|
||||
var curNode = this.getCurNode();
|
||||
if (!curNode) {
|
||||
return null;
|
||||
}
|
||||
var newNode = this.getNextNode_(curNode, this.validInLineNode_);
|
||||
|
||||
if (newNode) {
|
||||
this.setCurNode(newNode);
|
||||
}
|
||||
return newNode;
|
||||
};
|
||||
|
||||
/**
|
||||
* Find the previous node in the pre order traversal.
|
||||
* @return {Blockly.ASTNode} The previous node, or null if the current node
|
||||
* is not set or there is no previous value.
|
||||
* @override
|
||||
*/
|
||||
Blockly.LineCursor.prototype.prev = function() {
|
||||
var curNode = this.getCurNode();
|
||||
if (!curNode) {
|
||||
return null;
|
||||
}
|
||||
var newNode = this.getPreviousNode_(curNode, this.validLineNode_);
|
||||
|
||||
if (newNode && (newNode.getType() == Blockly.ASTNode.types.INPUT ||
|
||||
newNode.getType() == Blockly.ASTNode.types.NEXT) &&
|
||||
newNode.getLocation().targetBlock()) {
|
||||
newNode = this.getPreviousNode_(newNode, this.validLineNode_);
|
||||
}
|
||||
|
||||
if (newNode) {
|
||||
this.setCurNode(newNode);
|
||||
}
|
||||
return newNode;
|
||||
};
|
||||
|
||||
/**
|
||||
* For a basic cursor we only have the ability to go next and previou, so
|
||||
* out will allow the user to get to the previous node in the pre order traversal.
|
||||
* @return {Blockly.ASTNode} The previous node, or null if the current node is
|
||||
* not set or there is no previous value.
|
||||
* @override
|
||||
*/
|
||||
Blockly.LineCursor.prototype.out = function() {
|
||||
var curNode = this.getCurNode();
|
||||
if (!curNode) {
|
||||
return null;
|
||||
}
|
||||
var newNode = this.getPreviousNode_(curNode, this.validInLineNode_);
|
||||
|
||||
if (newNode) {
|
||||
this.setCurNode(newNode);
|
||||
}
|
||||
return newNode;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Meant to traverse by lines of code. This is blocks, statement inputs and
|
||||
* next connections.
|
||||
* @param {Blockly.ASTNode} node The AST node to check whether it is valid.
|
||||
* @return {boolean} True if the node should be visited, false otherwise.
|
||||
* @private
|
||||
*/
|
||||
Blockly.LineCursor.prototype.validLineNode_ = function(node) {
|
||||
if (!node) {
|
||||
return false;
|
||||
}
|
||||
var isValid = false;
|
||||
var location = node.getLocation();
|
||||
var type = node && node.getType();
|
||||
if (type == Blockly.ASTNode.types.BLOCK) {
|
||||
if (location.outputConnection === null) {
|
||||
isValid = true;
|
||||
}
|
||||
} else if (type == Blockly.ASTNode.types.INPUT &&
|
||||
location.type == Blockly.NEXT_STATEMENT) {
|
||||
isValid = true;
|
||||
} else if (type == Blockly.ASTNode.types.NEXT) {
|
||||
isValid = true;
|
||||
}
|
||||
return isValid;
|
||||
};
|
||||
|
||||
/**
|
||||
* Meant to traverse within a block. These are fields and input values.
|
||||
* @param {Blockly.ASTNode} node The AST node to check whether it is valid.
|
||||
* @return {boolean} True if the node should be visited, false otherwise.
|
||||
* @private
|
||||
*/
|
||||
Blockly.LineCursor.prototype.validInLineNode_ = function(node) {
|
||||
if (!node) {
|
||||
return false;
|
||||
}
|
||||
var isValid = false;
|
||||
var location = node.getLocation();
|
||||
var type = node && node.getType();
|
||||
if (type == Blockly.ASTNode.types.FIELD) {
|
||||
isValid = true;
|
||||
} else if (type == Blockly.ASTNode.types.INPUT &&
|
||||
location.type == Blockly.INPUT_VALUE) {
|
||||
isValid = true;
|
||||
}
|
||||
return isValid;
|
||||
};
|
||||
Reference in New Issue
Block a user