Change how blockly handles cursors. The old way was quite slow becau… (#1057)

* Change how blockly handles cursors.  The old way was quite slow because it changed the stylesheet directly.  See issue #981 for more details on implementation and tradeoffs.  This changes makes the following high level changes: deprecate Blockly.Css.setCursor, use built in open and closed hand cursor instead of custom .cur files, add css to draggable objects to set the open and closed hand cursors.
This commit is contained in:
picklesrus
2017-04-21 14:57:54 -07:00
committed by GitHub
parent 54178c65ae
commit 52f76013b5
7 changed files with 108 additions and 49 deletions

View File

@@ -292,7 +292,6 @@ Blockly.BlockSvg.terminateDrag = function() {
}
}
Blockly.dragMode_ = Blockly.DRAG_NONE;
Blockly.Css.setCursor(Blockly.Css.Cursor.OPEN);
};
/**
@@ -653,8 +652,6 @@ Blockly.BlockSvg.prototype.onMouseDown_ = function(e) {
Blockly.Events.setGroup(true);
}
// Left-click (or middle click)
Blockly.Css.setCursor(Blockly.Css.Cursor.CLOSED);
this.dragStartXY_ = this.getRelativeToSurfaceXY();
this.workspace.startDrag(e, this.dragStartXY_);
@@ -691,6 +688,11 @@ Blockly.BlockSvg.prototype.onMouseUp_ = function(e) {
Blockly.Touch.clearTouchIdentifier();
if (Blockly.dragMode_ != Blockly.DRAG_FREE &&
!Blockly.WidgetDiv.isVisible()) {
// Move the block in front of the others. Do this at the end of a click
// instead of rearranging the dom on mousedown. This helps with
// performance and makes it easier to use psuedo element :active
// to set the cursor.
this.bringToFront_();
Blockly.Events.fire(
new Blockly.Events.Ui(this, 'click', undefined, undefined));
}
@@ -721,13 +723,16 @@ Blockly.BlockSvg.prototype.onMouseUp_ = function(e) {
if (trashcan) {
goog.Timer.callOnce(trashcan.close, 100, trashcan);
}
if (this.workspace.toolbox_) {
this.workspace.toolbox_.removeDeleteStyle();
}
Blockly.selected.dispose(false, true);
}
if (Blockly.highlightedConnection_) {
Blockly.highlightedConnection_.unhighlight();
Blockly.highlightedConnection_ = null;
}
Blockly.Css.setCursor(Blockly.Css.Cursor.OPEN);
if (!Blockly.WidgetDiv.isVisible()) {
Blockly.Events.setGroup(false);
}
@@ -1063,16 +1068,28 @@ Blockly.BlockSvg.prototype.updateCursor_ = function(e, closestConnection) {
var showDeleteCursor = wouldDelete && !wouldConnect;
if (showDeleteCursor) {
Blockly.Css.setCursor(Blockly.Css.Cursor.DELETE);
Blockly.utils.addClass(/** @type {!Element} */ (this.svgGroup_),
'blocklyDraggingDelete');
if (this.workspace.toolbox_) {
// Change the cursor to a hand with an 'x'
this.workspace.toolbox_.addDeleteStyle();
}
if (deleteArea == Blockly.DELETE_AREA_TRASH && this.workspace.trashcan) {
this.workspace.trashcan.setOpen_(true);
}
return true;
} else {
Blockly.Css.setCursor(Blockly.Css.Cursor.CLOSED);
if (this.workspace.trashcan) {
this.workspace.trashcan.setOpen_(false);
}
Blockly.utils.removeClass(/** @type {!Element} */ (this.svgGroup_),
'blocklyDraggingDelete');
if (this.workspace.toolbox_) {
// Change the cursor on the toolbox
this.workspace.toolbox_.removeDeleteStyle();
}
return false;
}
};
@@ -1587,13 +1604,6 @@ Blockly.BlockSvg.prototype.setHighlighted = function(highlighted) {
Blockly.BlockSvg.prototype.addSelect = function() {
Blockly.utils.addClass(/** @type {!Element} */ (this.svgGroup_),
'blocklySelected');
// Move the selected block to the top of the stack.
var block = this;
do {
var root = block.getSvgRoot();
root.parentNode.appendChild(root);
block = block.getParent();
} while (block);
};
/**
@@ -1619,6 +1629,21 @@ Blockly.BlockSvg.prototype.setColour = function(colour) {
}
};
/**
* Move this block to the front of the visible workspace.
* <g> tags do not respect z-index so svg renders them in the
* order that they are in the dom. By placing this block first within the
* block group's <g>, it will render on top of any other blocks.
*/
Blockly.BlockSvg.prototype.bringToFront_ = function() {
var block = this;
do {
var root = block.getSvgRoot();
root.parentNode.appendChild(root);
block = block.getParent();
} while (block);
};
/**
* Set whether this block can chain onto the bottom of another block.
* @param {boolean} newBoolean True if there can be a previous statement.

View File

@@ -152,7 +152,6 @@ Blockly.Bubble.unbindDragEvents_ = function() {
*/
Blockly.Bubble.bubbleMouseUp_ = function(/*e*/) {
Blockly.Touch.clearTouchIdentifier();
Blockly.Css.setCursor(Blockly.Css.Cursor.OPEN);
Blockly.Bubble.unbindDragEvents_();
};
@@ -280,8 +279,6 @@ Blockly.Bubble.prototype.bubbleMouseDown_ = function(e) {
return;
}
// Left-click (or middle click)
Blockly.Css.setCursor(Blockly.Css.Cursor.CLOSED);
this.workspace_.startDrag(e, new goog.math.Coordinate(
this.workspace_.RTL ? -this.relativeLeft_ : this.relativeLeft_,
this.relativeTop_));
@@ -323,8 +320,6 @@ Blockly.Bubble.prototype.resizeMouseDown_ = function(e) {
return;
}
// Left-click (or middle click)
Blockly.Css.setCursor(Blockly.Css.Cursor.CLOSED);
this.workspace_.startDrag(e, new goog.math.Coordinate(
this.workspace_.RTL ? -this.width_ : this.width_, this.height_));

View File

@@ -95,41 +95,17 @@ Blockly.Css.inject = function(hasCss, pathToMedia) {
var cssTextNode = document.createTextNode(text);
cssNode.appendChild(cssTextNode);
Blockly.Css.styleSheet_ = cssNode.sheet;
Blockly.Css.setCursor(Blockly.Css.Cursor.OPEN);
};
/**
* Set the cursor to be displayed when over something draggable.
* See See https://github.com/google/blockly/issues/981 for context.
* @param {Blockly.Css.Cursor} cursor Enum.
* @deprecated April 2017.
*/
Blockly.Css.setCursor = function(cursor) {
if (Blockly.Css.currentCursor_ == cursor) {
return;
}
Blockly.Css.currentCursor_ = cursor;
var url = 'url(' + Blockly.Css.mediaPath_ + '/' + cursor + '.cur), auto';
// There are potentially hundreds of draggable objects. Changing their style
// properties individually is too slow, so change the CSS rule instead.
var rule = '.blocklyDraggable {\n cursor: ' + url + ';\n}\n';
Blockly.Css.styleSheet_.deleteRule(0);
Blockly.Css.styleSheet_.insertRule(rule, 0);
// There is probably only one toolbox, so just change its style property.
var toolboxen = document.getElementsByClassName('blocklyToolboxDiv');
for (var i = 0, toolbox; toolbox = toolboxen[i]; i++) {
if (cursor == Blockly.Css.Cursor.DELETE) {
toolbox.style.cursor = url;
} else {
toolbox.style.cursor = '';
}
}
// Set cursor on the whole document, so that rapid movements
// don't result in cursor changing to an arrow momentarily.
var html = document.body.parentNode;
if (cursor == Blockly.Css.Cursor.OPEN) {
html.style.cursor = '';
} else {
html.style.cursor = url;
}
console.warn('Deprecated call to Blockly.Css.setCursor.' +
'See https://github.com/google/blockly/issues/981 for context');
};
/**
@@ -232,6 +208,49 @@ Blockly.Css.CONTENT = [
'display: none;',
'}',
'.blocklyDraggable {',
/* backup for browsers (e.g. IE11) that don't support grab */
'cursor: url("<<<PATH>>>/handopen.cur"), auto;',
'cursor: grab;',
'cursor: -webkit-grab;',
'cursor: -moz-grab;',
'}',
'.blocklyDragging {',
/* backup for browsers (e.g. IE11) that don't support grabbing */
'cursor: url("<<<PATH>>>/handclosed.cur"), auto;',
'cursor: grabbing;',
'cursor: -webkit-grabbing;',
'cursor: -moz-grabbing;',
'}',
/* Changes cursor on mouse down. Not effective in Firefox because of
https://bugzilla.mozilla.org/show_bug.cgi?id=771241 */
'.blocklyDraggable:active {',
/* backup for browsers (e.g. IE11) that don't support grabbing */
'cursor: url("<<<PATH>>>/handclosed.cur"), auto;',
'cursor: grabbing;',
'cursor: -webkit-grabbing;',
'cursor: -moz-grabbing;',
'}',
/* Change the cursor on the whole drag surface in case the mouse gets
ahead of block during a drag. This way the cursor is still a closed hand.
*/
'.blocklyBlockDragSurface .blocklyDraggable {',
/* backup for browsers (e.g. IE11) that don't support grabbing */
'cursor: url("<<<PATH>>>/handclosed.cur"), auto;',
'cursor: grabbing;',
'cursor: -webkit-grabbing;',
'cursor: -moz-grabbing;',
'}',
'.blocklyDragging.blocklyDraggingDelete {',
'cursor: url("<<<PATH>>>/handdelete.cur"), auto;',
'}',
'.blocklyToolboxDelete {',
'cursor: url("<<<PATH>>>/handdelete.cur"), auto;',
'}',
'.blocklyDragging>.blocklyPath,',
'.blocklyDragging>.blocklyPathLight {',
'fill-opacity: .8;',

View File

@@ -960,7 +960,6 @@ Blockly.Flyout.prototype.blockMouseDown_ = function(block) {
Blockly.terminateDrag_();
Blockly.hideChaff(true);
// Left-click (or middle click)
Blockly.Css.setCursor(Blockly.Css.Cursor.CLOSED);
// Record the current mouse position.
flyout.startDragMouseY_ = e.clientY;
flyout.startDragMouseX_ = e.clientX;

View File

@@ -137,7 +137,11 @@ Blockly.Mutator.prototype.createEditor_ = function() {
// To fix this, scale needs to be applied at a different level in the dom.
var flyoutSvg = this.workspace_.addFlyout_('g');
var background = this.workspace_.createDom('blocklyMutatorBackground');
background.appendChild(flyoutSvg);
// Insert the flyout after the <rect> but before the block canvas so that
// the flyout is underneath in z-order. This makes blocks layering during
// dragging work properly.
background.insertBefore(flyoutSvg, this.workspace_.svgBlockCanvas_);
this.svgDialog_.appendChild(background);
return this.svgDialog_;

View File

@@ -413,6 +413,24 @@ Blockly.Toolbox.prototype.clearSelection = function() {
this.tree_.setSelectedItem(null);
};
/**
* Adds styles on the toolbox indicating blocks will be deleted.
* @package
*/
Blockly.Toolbox.prototype.addDeleteStyle = function() {
Blockly.utils.addClass(/** @type {!Element} */ (this.HtmlDiv),
'blocklyToolboxDelete');
};
/**
* Remove styles from the toolbox that indicate blocks will be deleted.
* @package
*/
Blockly.Toolbox.prototype.removeDeleteStyle = function() {
Blockly.utils.removeClass(/** @type {!Element} */ (this.HtmlDiv),
'blocklyToolboxDelete');
};
/**
* Return the deletion rectangle for this toolbox.
* @return {goog.math.Rect} Rectangle in which to delete.

View File

@@ -121,7 +121,6 @@ Blockly.onMouseUp_ = function(e) {
// TODO(#781): Check whether this needs to be called for all drag modes.
workspace.resetDragSurface();
Blockly.Css.setCursor(Blockly.Css.Cursor.OPEN);
workspace.dragMode_ = Blockly.DRAG_NONE;
// Unbind the touch event if it exists.
if (Blockly.Touch.onTouchUpWrapper_) {