Skip to content

Insertion markers in Blockly!#1987

Merged
rachel-fenichel merged 15 commits intoRaspberryPiFoundation:developfrom
rachel-fenichel:feature/insertion_markers
Nov 20, 2018
Merged

Insertion markers in Blockly!#1987
rachel-fenichel merged 15 commits intoRaspberryPiFoundation:developfrom
rachel-fenichel:feature/insertion_markers

Conversation

@rachel-fenichel
Copy link
Collaborator

The basics

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

The details

Proposed Changes

Add the insertion marker manager class
Mark the dragged connection manager class deprecated, and remove the only use of it
(I propose leaving it in until we have a clear upgrade strategy for developers)
Add utility functions that are called by the insertion marker manager

Reason for Changes

Blockly should have insertion markers! They look snazzy on Scratch Blocks, and the plan was always to backport them to Blockly.

Test Coverage

Unit tests pass.
Tested on:

  • Desktop Chrome

Additional Information

You can play with this on my demo site for now. I reserve the right to update that site without warning.

Copy link
Contributor

@AnmAtAnm AnmAtAnm left a comment

Choose a reason for hiding this comment

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

Stepping back, is there any reason we need to support the original behavior for existing applications? Put another way, are we confident that this change is positive change for all developers and their users.

Off the top of my head, I can't think of any way in which the previous behavior is preferable, but I want our answer to be explicit and shared by everyone on our team.

core/block.js Outdated
}
this.isInsertionMarker_ = insertionMarker;
if (this.isInsertionMarker_) {
// TODO: Why is this in Block.js instead of block_svg.js?
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 TODO/question to the the setColour method in block.js?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

As I said, this isn't for review yet. I'm not done with cleanup.


/**
* Visual effect to show that if the dragging block is dropped, this block will
* be replaced. If a shadow block it will disappear. Otherwise it will bump.
Copy link
Contributor

Choose a reason for hiding this comment

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

Comma after

If a shadow block

@@ -34,82 +34,83 @@ this.BLOCKLY_BOOT = function(root) {
dir = this.BLOCKLY_DIR.match(/[^\/]+$/)[0];
}
// Execute after Closure has loaded.
goog.addDependency("../../../" + dir + "/core/block.js", ['Blockly.Block'], ['Blockly.Blocks', 'Blockly.Comment', 'Blockly.Connection', 'Blockly.Events.BlockChange', 'Blockly.Events.BlockCreate', 'Blockly.Events.BlockDelete', 'Blockly.Events.BlockMove', 'Blockly.Extensions', 'Blockly.Input', 'Blockly.Mutator', 'Blockly.Warning', 'Blockly.Workspace', 'Blockly.Xml', 'goog.array', 'goog.asserts', 'goog.math.Coordinate', 'goog.string']);
Copy link
Contributor

Choose a reason for hiding this comment

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

I know this is the only compressed file that should be impacted by your changes, but it doesn't seem right to only update one of the files. I would rather see all three updated in a single followup push.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

If I don't update this file it's not testable.

@ewpatton
Copy link
Contributor

ewpatton commented Jul 27, 2018 via email

@RoboErikG
Copy link
Contributor

@ewpatton
Regarding 2. That was a trade off done mostly to reduce the cost of creating the insertion marker and re-rendering the stack. The insertion marker is actually a block, so it has to go through the whole rendering pass to figure out the size and shape. If there was a really big stack that you were putting inside another block it took a while to make the shadow of the entire stack.

It was also a little jarring when you dragged a stack down another stack and everything kept jumping off the bottom of the page. We found just using a single block was less jumpy. It may be confusing for some users, though, since at first they might think only one block will be connected.

@rachel-fenichel
Copy link
Collaborator Author

This is a preliminary pull request to show what changes are required. I'm not planning to land anything until I'm happy with behaviour and appearance in all cases and we have a good developer story.

Some information to consider:

  • InsertionMarkerManager and DraggedConnectionManager are fully interchangeable--that was a deliberate design choice.
  • All of the changes are additive except for the changes to block_dragger.js.
  • Put another way, you can get back to the old behaviour by reverting the three lines that changed in block_dragger.js.
  • The eventual goal is to fully switch to insertion markers, rather than maintaining both styles.
  • The maintenance cost of two paths like this is extremely high, mostly in manual testing on every release.
  • As a result, I do not want to add an option to the injection struct to choose between insertion markers and small highlights.
  • We've been working with insertion markers on scratch blocks for ~2 years and have been very happy with how intuitive they look and feel.
  • Insertion markers can cause performance problems for extremely deep block stacks or slow browsers.
  • We can continue to fix performance problems as we find them, which usually boosts performance across the board.
  • Performance fixes are worthwhile in their own right, and are still less work than ongoing maintenance of the dragged_connection_manager.

My current plan is to leave dragged_connection_manager.js in the repository, marked deprecated, for a few releases after we enable insertion markers. Developers who want to switch over more slowly, or keep the old style, can revert the three lines in block_dragger.js.

Developers who want it to be user-configurable would be responsible for including both styles (easy to do) and piping the user's decision to the right place in block_dragger.js. Those developers would also be responsible for keeping the old dragged_connection_manager.js in working form for their project. That's generally a smaller maintenance job than trying to keep it working for all possibly types of blockly projects.

Thoughts?

@rachel-fenichel
Copy link
Collaborator Author

@ewpatton for a working example of why the single-block behaviour is the right way to do it, hit the "Spaghetti" button and drag one of the if statements around inside the stack. It'll be slow, but you'll notice that you can move it down one block at a time, allowing you to insert it anywhere.

If the insertion marker contains the entire stack, the next block would jump out of view. The jumpiness isn't just annoying: it makes it impossible to move the insertion marker down by a single block. Instead you have to drag it to the side until the marker disappears, then drag back to the stack at (hopefully) the correct place.

@ewpatton
Copy link
Contributor

@RoboErikG @rachel-fenichel Okay, that's sounds like a reasonable argument for the one blockly only approach. Thanks for the info.

Copy link
Collaborator Author

@rachel-fenichel rachel-fenichel left a comment

Choose a reason for hiding this comment

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

These changes are now ready for review. I chose to make C-shape blocks always insert instead of wrapping. That choice isn't permanent: we may add more complex behaviour later.

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.

Needs tests.


// // During a drag there may be a lot of rerenders, but not field changes.
// // Turn the cache on so we don't do spurious remeasures during the drag.
// Blockly.Field.startCache();
Copy link
Contributor

Choose a reason for hiding this comment

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

Did you forget to uncomment this line?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Whoops, fixed in a commit that I forgot to push.

* @return {boolean} true if the connection is not connected or is connected to
* an insertion marker, false otherwise.
*/
Blockly.Connection.prototype.isConnectedToNonInsertionMarker = function() {
Copy link
Contributor

Choose a reason for hiding this comment

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

This doesn't seem to be used anywhere. Also, what about connections that would be connected except there's an insertion marker between blocks?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Removed.

// marker is in the middle of a stack, it won't work.
return !targetBlock.getPreviousBlock();
}
// ???
Copy link
Contributor

Choose a reason for hiding this comment

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

????

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

!!!

I'm unsure of what cases would end up here. I think it's worth having a log statement here, which will let me debug until all cases are covered. Any objections?

Copy link
Contributor

Choose a reason for hiding this comment

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

sgtm

@rachel-fenichel
Copy link
Collaborator Author

I added tests; PTAL.

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.

Some references to Scratch specific code in the comments that need to be cleaned up. Once that's done lgtm.


/**
* Get rid of the highlighting marking the block that will be replaced.
* Scratch-specific code, where "highlighting" applies to a block rather than
Copy link
Contributor

Choose a reason for hiding this comment

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

"Scratch-specific code" then why is it here?


/**
* Add highlighting showing which block will be replaced.
* Scratch-specific code, where "highlighting" applies to a block rather than
Copy link
Contributor

Choose a reason for hiding this comment

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

'Scratch specific code'?

/**
* The insertion marker that shows up between blocks to show where a block
* would go if dropped immediately.
* This is the scratch-blocks equivalent of connection highlighting.
Copy link
Contributor

Choose a reason for hiding this comment

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

remove ref to scratch-blocks.

/**
* Connection on the insertion marker block that corresponds to
* this.localConnection_ on the currently dragged block.
* This is part of the scratch-blocks equivalent of connection highlighting.
Copy link
Contributor

Choose a reason for hiding this comment

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

remove scratch-blocks ref.

@rachel-fenichel rachel-fenichel merged commit c7b5028 into RaspberryPiFoundation:develop Nov 20, 2018
@rachel-fenichel rachel-fenichel deleted the feature/insertion_markers branch November 20, 2018 00:34
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.

4 participants