Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Keyboard nav ast node #2391

Merged
merged 6 commits into from
Apr 18, 2019
Merged

Conversation

alschmiedt
Copy link
Contributor

The basics

  • [] I branched from develop
  • [] My pull request is against develop
  • My code follows the style guide

The details

Resolves

Proposed Changes

Adds an AST Node for keyboard navigation. An AST Node will be able to find the next, prev, in, or out node from its current location.

Reason for Changes

To create a better keyboard navigation api.

Test Coverage

Tests are written in mocha.

Tested on:

Additional Information

@alschmiedt alschmiedt merged commit bd05929 into google:keyboard_nav Apr 18, 2019
Copy link
Contributor

@RoboErikG RoboErikG left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to refresh to pull in additional changes, so expect further comments.

core/ast_node.js Show resolved Hide resolved
* Class for an ASTNode.
* @constructor
* @param {!String} type This is the type of the location using
* Blockly.ASTNodes.types.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove s on ASTNodes

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Changes can be found in cursor_ast_update branch.

Blockly.ASTNode = function(type, location, params) {

/*
* The type of the location.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add "One of Blockly.ASTNode.types"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Changes can be found in cursor_ast_update branch.

/**
* Object holding different types for an ASTNode.
*/
Blockly.ASTNode.types = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move this up to the top of the file. We usually try to declare constants first so they're easy to find.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Changes can be found in cursor_ast_update branch.

Blockly.ASTNode.createConnectionNode = function(connection) {
var astNode;
if (!connection){return;}
if (connection.type === Blockly.INPUT_VALUE) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a difference between an input connection node and an input node? Do we want to enforce using Inputs for this case or silently remap it?

* block.
* @private
*/
Blockly.ASTNode.prototype.findOutLocationForBlock_ = function(block) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add some test cases for this method with notes on how out is expected to traverse the tree.


switch (this.type_) {
case Blockly.ASTNode.types.WORKSPACE:
var newX = this.wsCoordinate_.x + Blockly.ASTNode.wsMove_;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a TODO to limit this. The view is bounded to half a screen beyond the furthest blocks, but there's no easy way to translate that to Workspace coordinates right now (hence TODO).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Changes can be found in cursor_ast_update branch.

/**
* Navigate between stacks of blocks on the workspace.
* @param {?Boolean} forward True to go forward. False to go backwards.
* @return {?Blockly.BlockSvg} The first block of the next stack.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For consistency this should probably return a new ASTNode.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Changes can be found in cursor_ast_update branch.

* @return {?Blockly.ASTNode} The ast node holding the next field or connection.
* @private
*/
Blockly.ASTNode.prototype.findNextForField_ = function(location, parentInput) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be combined with findNextForInput since in both cases you need to iterate through fields and inputs until you find a valid location or hit the end of the block. Right now your code will go from an input to a field, then get stuck on the last field in that input.

You should probably add a test that iterates across a multi-input multi-field block using next and previous to make sure all editable elements are reachable.

* @return {?Blockly.ASTNode} The ast node holding the previous input or field.
* @private
*/
Blockly.ASTNode.prototype.findPrevForField_ = function(location, parentInput) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto about combining this with findPrevForInput_

break;

case Blockly.ASTNode.types.BLOCK:
var nextConnection = this.location_.nextConnection;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

next connection may not exist.

break;

case Blockly.ASTNode.types.PREVIOUS:
var output = this.location_.outputConnection;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a previous, so there will never be an output. Also, this case should be identical to OUTPUT since in both cases next should go to the block itself.

break;

case Blockly.ASTNode.types.NEXT:
if (this.location_.targetBlock()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can just use this.location_.targetConnection since that will either be null or the previous connection on the next block.

Blockly.ASTNode.prototype.next = function() {
var newAstNode = null;

switch (this.type_) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For each case in next/prev/in/out please add a comment about what you expect the returned node in the tree to be. For example, "If on a field next should return the next editable field or input connection on the block. It will not move between blocks and it will return null if this is the last valid field or input on the block."

* Find the element one level below and all the way to the left of the current
* location.
* @return {?Blockly.ASTNode} An ast node that wraps the next field, connection,
* workspace, or block.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Returns null if there is nothing below this node.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Changes can be found in cursor_ast_update branch.

break;

case Blockly.ASTNode.types.OUTPUT:
var sourceBlock = this.location_.sourceBlock_;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In our current tree diagram there is no previous from an output. you'd have to go up a level.


case Blockly.ASTNode.types.OUTPUT:
var sourceBlock = this.location_.sourceBlock_;
if (sourceBlock && sourceBlock.previousConnection) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A block with an output can't have a previous.

if (output) {
newAstNode = Blockly.ASTNode.createConnectionNode(output);
} else {
var prevConnection = this.location_.previousConnection;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

prev may be null.

break;

case Blockly.ASTNode.types.PREVIOUS:
var prevBlock = this.location_.targetBlock();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

location_.targetConnection

*/
Blockly.ASTNode.prototype.prev = function() {
if (!this.location_) {return null;}
var newAstNode;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here and elsewhere you should explicitly initialize this to null. JS initializes things to undefined, which is not what we're promising to return.

@alschmiedt alschmiedt mentioned this pull request Apr 25, 2019
3 tasks
@alschmiedt alschmiedt deleted the keyboard_nav_astNode branch May 29, 2020 15:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants