mirror of
https://github.com/google/blockly.git
synced 2026-01-11 02:47:09 +01:00
Revise handling of mouse events on flyout blocks
- allows scrolling by dragging a block up and down - dragging a block towards the workspace creates it - dragging a block any direction in a non-scrollable flyout creates it - dragging a shadow block works properly - clicks on fields in non-closeable flyouts always open editors - clicks in closeable flyouts create the block but don't open editors Fixes #385 and fixes #405.
This commit is contained in:
@@ -528,7 +528,6 @@ Blockly.BlockSvg.prototype.onMouseDown_ = function(e) {
|
||||
return;
|
||||
}
|
||||
if (this.isInFlyout) {
|
||||
e.stopPropagation();
|
||||
return;
|
||||
}
|
||||
this.workspace.markFocused();
|
||||
|
||||
158
core/flyout.js
158
core/flyout.js
@@ -114,6 +114,13 @@ Blockly.Flyout.prototype.autoClose = true;
|
||||
*/
|
||||
Blockly.Flyout.prototype.CORNER_RADIUS = 8;
|
||||
|
||||
/**
|
||||
* Number of pixels the mouse must move before a drag/scroll starts. Because the
|
||||
* drag-intention is determined when this is reached, it is larger than
|
||||
* Blockly.DRAG_RADIUS so that the drag-direction is clearer.
|
||||
*/
|
||||
Blockly.Flyout.prototype.DRAG_RADIUS = 10;
|
||||
|
||||
/**
|
||||
* Margin around the edges of the blocks in the flyout.
|
||||
* @type {number}
|
||||
@@ -142,6 +149,30 @@ Blockly.Flyout.prototype.width_ = 0;
|
||||
*/
|
||||
Blockly.Flyout.prototype.height_ = 0;
|
||||
|
||||
/**
|
||||
* Is the flyout dragging (scrolling)?
|
||||
* 0 - DRAG_NONE - no drag is ongoing or state is undetermined
|
||||
* 1 - DRAG_STICKY - still within the sticky drag radius
|
||||
* 2 - DRAG_FREE - in scroll mode (never create a new block)
|
||||
* @private
|
||||
*/
|
||||
Blockly.Flyout.prototype.dragMode_ = Blockly.DRAG_NONE;
|
||||
|
||||
/**
|
||||
* Range of a drag angle from a fixed flyout considered "dragging toward workspace."
|
||||
* Drags that are within the bounds of this many degrees from the orthogonal
|
||||
* line to the flyout edge are considered to be "drags toward the workspace."
|
||||
* Example:
|
||||
* Flyout Edge Workspace
|
||||
* [block] / <-within this angle, drags "toward workspace" |
|
||||
* [block] ---- orthogonal to flyout boundary ---- |
|
||||
* [block] \ |
|
||||
* The angle is given in degrees from the orthogonal.
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
Blockly.Flyout.prototype.dragAngleRange_ = 70;
|
||||
|
||||
/**
|
||||
* Creates the flyout's DOM. Only needs to be called once.
|
||||
* @return {!Element} The flyout's SVG group.
|
||||
@@ -679,17 +710,10 @@ Blockly.Flyout.prototype.clearOldBlocks_ = function() {
|
||||
* @private
|
||||
*/
|
||||
Blockly.Flyout.prototype.addBlockListeners_ = function(root, block, rect) {
|
||||
if (this.autoClose) {
|
||||
this.listeners_.push(Blockly.bindEvent_(root, 'mousedown', null,
|
||||
this.createBlockFunc_(block)));
|
||||
this.listeners_.push(Blockly.bindEvent_(rect, 'mousedown', null,
|
||||
this.createBlockFunc_(block)));
|
||||
} else {
|
||||
this.listeners_.push(Blockly.bindEvent_(root, 'mousedown', null,
|
||||
this.blockMouseDown_(block)));
|
||||
this.listeners_.push(Blockly.bindEvent_(rect, 'mousedown', null,
|
||||
this.blockMouseDown_(block)));
|
||||
}
|
||||
this.listeners_.push(Blockly.bindEvent_(root, 'mousedown', null,
|
||||
this.blockMouseDown_(block)));
|
||||
this.listeners_.push(Blockly.bindEvent_(rect, 'mousedown', null,
|
||||
this.blockMouseDown_(block)));
|
||||
this.listeners_.push(Blockly.bindEvent_(root, 'mouseover', block,
|
||||
block.addSelect));
|
||||
this.listeners_.push(Blockly.bindEvent_(root, 'mouseout', block,
|
||||
@@ -710,7 +734,7 @@ Blockly.Flyout.prototype.blockMouseDown_ = function(block) {
|
||||
var flyout = this;
|
||||
return function(e) {
|
||||
Blockly.terminateDrag_();
|
||||
Blockly.hideChaff();
|
||||
Blockly.hideChaff(true);
|
||||
if (Blockly.isRightButton(e)) {
|
||||
// Right-click.
|
||||
block.showContextMenu_(e);
|
||||
@@ -718,16 +742,19 @@ Blockly.Flyout.prototype.blockMouseDown_ = function(block) {
|
||||
// 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;
|
||||
Blockly.Flyout.startDownEvent_ = e;
|
||||
Blockly.Flyout.startBlock_ = block;
|
||||
Blockly.Flyout.startFlyout_ = flyout;
|
||||
Blockly.Flyout.onMouseUpWrapper_ = Blockly.bindEvent_(document,
|
||||
'mouseup', this, flyout.onMouseUp_);
|
||||
'mouseup', flyout, flyout.onMouseUp_);
|
||||
Blockly.Flyout.onMouseMoveBlockWrapper_ = Blockly.bindEvent_(document,
|
||||
'mousemove', this, flyout.onMouseMoveBlock_);
|
||||
'mousemove', flyout, flyout.onMouseMoveBlock_);
|
||||
}
|
||||
// This event has been handled. No need to bubble up to the document.
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
};
|
||||
};
|
||||
|
||||
@@ -741,7 +768,7 @@ Blockly.Flyout.prototype.onMouseDown_ = function(e) {
|
||||
return;
|
||||
}
|
||||
Blockly.hideChaff(true);
|
||||
Blockly.Flyout.terminateDrag_();
|
||||
this.dragMode_ = Blockly.DRAG_FREE;
|
||||
this.startDragMouseY_ = e.clientY;
|
||||
this.startDragMouseX_ = e.clientX;
|
||||
Blockly.Flyout.onMouseMoveWrapper_ = Blockly.bindEvent_(document, 'mousemove',
|
||||
@@ -761,10 +788,15 @@ Blockly.Flyout.prototype.onMouseDown_ = function(e) {
|
||||
* @private
|
||||
*/
|
||||
Blockly.Flyout.prototype.onMouseUp_ = function(e) {
|
||||
if (!this.workspace_.isDragging() && !Blockly.WidgetDiv.isVisible()) {
|
||||
Blockly.Events.fire(
|
||||
new Blockly.Events.Ui(Blockly.Flyout.startBlock_, 'click',
|
||||
undefined, undefined));
|
||||
if (!this.workspace_.isDragging()) {
|
||||
if (this.autoClose) {
|
||||
this.createBlockFunc_(Blockly.Flyout.startBlock_)(
|
||||
Blockly.Flyout.startDownEvent_);
|
||||
} else if (!Blockly.WidgetDiv.isVisible()) {
|
||||
Blockly.Events.fire(
|
||||
new Blockly.Events.Ui(Blockly.Flyout.startBlock_, 'click',
|
||||
undefined, undefined));
|
||||
}
|
||||
}
|
||||
Blockly.terminateDrag_();
|
||||
};
|
||||
@@ -817,12 +849,89 @@ Blockly.Flyout.prototype.onMouseMoveBlock_ = function(e) {
|
||||
}
|
||||
var dx = e.clientX - Blockly.Flyout.startDownEvent_.clientX;
|
||||
var dy = e.clientY - Blockly.Flyout.startDownEvent_.clientY;
|
||||
// Still dragging within the sticky DRAG_RADIUS.
|
||||
if (Math.sqrt(dx * dx + dy * dy) > Blockly.DRAG_RADIUS) {
|
||||
// Create the block.
|
||||
Blockly.Flyout.startFlyout_.createBlockFunc_(Blockly.Flyout.startBlock_)(
|
||||
|
||||
var createBlock = this.determineDragIntention_(dx, dy);
|
||||
if (createBlock) {
|
||||
this.createBlockFunc_(Blockly.Flyout.startBlock_)(
|
||||
Blockly.Flyout.startDownEvent_);
|
||||
} else if (this.dragMode_ == Blockly.DRAG_FREE) {
|
||||
// Do a scroll
|
||||
this.onMouseMove_(e);
|
||||
}
|
||||
e.stopPropagation();
|
||||
};
|
||||
|
||||
/**
|
||||
* Determine the intention of a drag.
|
||||
* Updates dragMode_ based on a drag delta and the current mode,
|
||||
* and returns true if we should create a new block.
|
||||
* @param {number} dx X delta of the drag
|
||||
* @param {number} dy Y delta of the drag
|
||||
* @return {boolean} True if a new block should be created.
|
||||
*/
|
||||
Blockly.Flyout.prototype.determineDragIntention_ = function(dx, dy) {
|
||||
if (this.dragMode_ == Blockly.DRAG_FREE) {
|
||||
// Once in free mode, always stay in free mode and never create a block.
|
||||
return false;
|
||||
}
|
||||
var dragDistance = Math.sqrt(dx * dx + dy * dy);
|
||||
if (dragDistance < this.DRAG_RADIUS) {
|
||||
// Still within the sticky drag radius
|
||||
this.dragMode_ = Blockly.DRAG_STICKY;
|
||||
return false;
|
||||
} else {
|
||||
if (this.isDragTowardWorkspace_(dx, dy) || !this.scrollbar_.isVisible()) {
|
||||
// Immediately create a block
|
||||
return true;
|
||||
} else {
|
||||
// Immediately move to free mode - the drag is away from the workspace.
|
||||
this.dragMode_ = Blockly.DRAG_FREE;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Determine if a drag delta is toward the workspace, based on the position
|
||||
* and orientation of the flyout. This is used in determineDragIntention_ to
|
||||
* determine if a new block should be created or if the flyout should scroll.
|
||||
* @param {number} dx X delta of the drag
|
||||
* @param {number} dy Y delta of the drag
|
||||
* @return {boolean} true if the drag is toward the workspace.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Flyout.prototype.isDragTowardWorkspace_ = function(dx, dy) {
|
||||
// Direction goes from -180 to 180, with 0 toward the right and 90 on top.
|
||||
var dragDirection = Math.atan2(dy, dx) / Math.PI * 180;
|
||||
|
||||
var draggingTowardWorkspace = false;
|
||||
var range = this.dragAngleRange_;
|
||||
if (this.horizontalLayout_) {
|
||||
if (this.toolboxPosition_ == Blockly.TOOLBOX_AT_TOP) {
|
||||
// Horizontal at top
|
||||
if (dragDirection < 90 + range && dragDirection > 90 - range ) {
|
||||
draggingTowardWorkspace = true;
|
||||
}
|
||||
} else {
|
||||
// Horizontal at bottom
|
||||
if (dragDirection > -90 - range && dragDirection < -90 + range) {
|
||||
draggingTowardWorkspace = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (this.toolboxPosition_ == Blockly.TOOLBOX_AT_LEFT) {
|
||||
// Vertical at left
|
||||
if (dragDirection < range && dragDirection > -range) {
|
||||
draggingTowardWorkspace = true;
|
||||
}
|
||||
} else {
|
||||
// Vertical at right
|
||||
if (dragDirection < -180 + range || dragDirection > 180 - range) {
|
||||
draggingTowardWorkspace = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return draggingTowardWorkspace;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -990,6 +1099,9 @@ Blockly.Flyout.prototype.getClientRect = function() {
|
||||
* @private
|
||||
*/
|
||||
Blockly.Flyout.terminateDrag_ = function() {
|
||||
if (Blockly.Flyout.startFlyout_) {
|
||||
Blockly.Flyout.startFlyout_.dragMode_ = Blockly.DRAG_NONE;
|
||||
}
|
||||
if (Blockly.Flyout.onMouseUpWrapper_) {
|
||||
Blockly.unbindEvent_(Blockly.Flyout.onMouseUpWrapper_);
|
||||
Blockly.Flyout.onMouseUpWrapper_ = null;
|
||||
|
||||
Reference in New Issue
Block a user