@@ -219,7 +219,9 @@ Blockly.BlockSvg.terminateDrag_ = function() {
219
219
if ( selected ) {
220
220
if ( selected . ghostBlock_ ) {
221
221
Blockly . Events . disable ( ) ;
222
- selected . ghostBlock_ . unplug ( true /* healStack */ ) ;
222
+ if ( Blockly . localGhostConnection_ ) {
223
+ selected . disconnectGhost ( ) ;
224
+ }
223
225
selected . ghostBlock_ . dispose ( ) ;
224
226
selected . ghostBlock_ = null ;
225
227
Blockly . Events . enable ( ) ;
@@ -594,7 +596,6 @@ Blockly.BlockSvg.prototype.onMouseUp_ = function(e) {
594
596
Blockly . fireUiEvent ( window , 'resize' ) ;
595
597
}
596
598
if ( Blockly . highlightedConnection_ ) {
597
- Blockly . highlightedConnection_ . unhighlight ( ) ;
598
599
Blockly . highlightedConnection_ = null ;
599
600
}
600
601
Blockly . Css . setCursor ( Blockly . Css . Cursor . OPEN ) ;
@@ -814,50 +815,128 @@ Blockly.BlockSvg.prototype.onMouseMove_ = function(e) {
814
815
}
815
816
}
816
817
817
- // Remove connection highlighting if needed.
818
- if ( Blockly . highlightedConnection_ &&
819
- Blockly . highlightedConnection_ != closestConnection ) {
820
- if ( this . ghostBlock_ ) {
821
- // Don't fire events for ghost block creation or movement.
822
- Blockly . Events . disable ( ) ;
823
- this . ghostBlock_ . unplug ( true /* healStack */ ) ;
824
- this . ghostBlock_ . dispose ( ) ;
825
- this . ghostBlock_ = null ;
826
- Blockly . Events . enable ( ) ;
827
- }
828
- Blockly . highlightedConnection_ . unhighlight ( ) ;
829
- Blockly . highlightedConnection_ = null ;
830
- Blockly . localConnection_ = null ;
818
+ this . updatePreviews ( closestConnection , localConnection , radiusConnection ,
819
+ e , newXY . x - this . dragStartXY_ . x , newXY . y - this . dragStartXY_ . y ) ;
820
+ }
821
+ // This event has been handled. No need to bubble up to the document.
822
+ e . stopPropagation ( ) ;
823
+ } ;
824
+
825
+ /**
826
+ * Preview the results of the drag if the mouse is released immediately.
827
+ * @param {Blockly.Connection } closestConnection The closest connection found
828
+ * during the search
829
+ * @param {Blockly.Connection } localConnection The connection on the moving
830
+ * block.
831
+ * @param {number } radiusConnection The distance between closestConnection and
832
+ * localConnection.
833
+ * @param {!Event } e Mouse move event.
834
+ * @param {number } dx The x distance the block has moved onscreen up to this
835
+ * point in the drag.
836
+ * @param {number } dy The y distance the block has moved onscreen up to this
837
+ * point in the drag.
838
+ */
839
+ Blockly . BlockSvg . prototype . updatePreviews = function ( closestConnection ,
840
+ localConnection , radiusConnection , e , dx , dy ) {
841
+ // Don't fire events for ghost block creation or movement.
842
+ Blockly . Events . disable ( ) ;
843
+ // Remove a ghost if needed. For Scratch-Blockly we are using ghosts instead
844
+ // of highlighting the connection; for compatibility with Web Blockly the
845
+ // name "highlightedConnection" will still be used.
846
+ if ( Blockly . highlightedConnection_ &&
847
+ Blockly . highlightedConnection_ != closestConnection ) {
848
+ if ( this . ghostBlock_ && Blockly . localGhostConnection_ ) {
849
+ this . disconnectGhost ( ) ;
831
850
}
832
- // Add connection highlighting if needed.
833
- if ( closestConnection &&
834
- closestConnection != Blockly . highlightedConnection_ ) {
835
- closestConnection . highlight ( ) ;
836
- Blockly . highlightedConnection_ = closestConnection ;
837
- Blockly . localConnection_ = localConnection ;
838
- Blockly . Events . disable ( ) ;
839
- if ( ! this . ghostBlock_ ) {
840
- this . ghostBlock_ = this . workspace . newBlock ( this . type ) ;
841
- this . ghostBlock_ . setGhost ( true ) ;
842
- this . ghostBlock_ . moveConnections_ ( radiusConnection ) ;
851
+ Blockly . highlightedConnection_ = null ;
852
+ Blockly . localConnection_ = null ;
853
+ }
854
+
855
+ // Add a ghost if needed.
856
+ if ( closestConnection &&
857
+ closestConnection != Blockly . highlightedConnection_ &&
858
+ ! closestConnection . sourceBlock_ . isGhost ( ) ) {
859
+ Blockly . highlightedConnection_ = closestConnection ;
860
+ Blockly . localConnection_ = localConnection ;
861
+ if ( ! this . ghostBlock_ ) {
862
+ this . ghostBlock_ = this . workspace . newBlock ( this . type ) ;
863
+ this . ghostBlock_ . setGhost ( true ) ;
864
+ this . ghostBlock_ . initSvg ( ) ;
865
+ }
866
+
867
+ var ghostBlock = this . ghostBlock_ ;
868
+ var localGhostConnection = ghostBlock . getMatchingConnection ( this ,
869
+ localConnection ) ;
870
+ if ( localGhostConnection != Blockly . localGhostConnection_ ) {
871
+ ghostBlock . getSvgRoot ( ) . setAttribute ( 'visibility' , 'visible' ) ;
872
+ ghostBlock . rendered = true ;
873
+ // Move the preview to the correct location before the existing block.
874
+ if ( localGhostConnection . type == Blockly . NEXT_STATEMENT ) {
875
+ var relativeXy = this . getRelativeToSurfaceXY ( ) ;
876
+ var connectionOffsetX = ( localConnection . x_ - ( relativeXy . x - dx ) ) ;
877
+ var connectionOffsetY = ( localConnection . y_ - ( relativeXy . y - dy ) ) ;
878
+ var newX = closestConnection . x_ - connectionOffsetX ;
879
+ var newY = closestConnection . y_ - connectionOffsetY ;
880
+ var ghostPosition = ghostBlock . getRelativeToSurfaceXY ( ) ;
881
+ ghostBlock . moveBy ( newX - ghostPosition . x , newY - ghostPosition . y , true ) ;
882
+
843
883
}
844
- if ( Blockly . localConnection_ == this . previousConnection ) {
845
- // Setting the block to rendered will actually change the connection
846
- // behaviour :/
847
- this . ghostBlock_ . rendered = true ;
848
- this . ghostBlock_ . previousConnection . connect ( closestConnection ) ;
884
+ if ( localGhostConnection . type == Blockly . PREVIOUS_STATEMENT &&
885
+ ! ghostBlock . nextConnection ) {
886
+ Blockly . bumpedConnection_ = closestConnection . targetConnection ;
849
887
}
850
- this . ghostBlock_ . render ( true ) ;
851
- Blockly . Events . enable ( ) ;
888
+ // Renders ghost.
889
+ localGhostConnection . connect ( closestConnection ) ;
890
+ // Render dragging block so it appears on top.
891
+ this . workspace . getCanvas ( ) . appendChild ( this . getSvgRoot ( ) ) ;
892
+ Blockly . localGhostConnection_ = localGhostConnection ;
852
893
}
853
- // Provide visual indication of whether the block will be deleted if
854
- // dropped here.
855
- if ( this . isDeletable ( ) ) {
856
- this . workspace . isDeleteArea ( e ) ;
894
+ }
895
+ // Reenable events.
896
+ Blockly . Events . enable ( ) ;
897
+
898
+ // Provide visual indication of whether the block will be deleted if
899
+ // dropped here.
900
+ if ( this . isDeletable ( ) ) {
901
+ this . workspace . isDeleteArea ( e ) ;
902
+ }
903
+ } ;
904
+
905
+ /**
906
+ * Disconnect the current ghost block from the stack, and heal the stack to its
907
+ * previous state.
908
+ */
909
+ Blockly . BlockSvg . prototype . disconnectGhost = function ( ) {
910
+ // The ghost block is the first block in a stack, either because it doesn't
911
+ // have a previous connection or because the previous connection is not
912
+ // connection. Unplug won't do anything in that case. Instead, unplug the
913
+ // following block.
914
+ if ( Blockly . localGhostConnection_ == this . ghostBlock_ . nextConnection &&
915
+ ( ! this . ghostBlock_ . previousConnection ||
916
+ ! this . ghostBlock_ . previousConnection . targetConnection ) ) {
917
+ Blockly . localGhostConnection_ . targetBlock ( ) . unplug ( false ) ;
918
+ }
919
+ // Inside of a C-block, first statement connection.
920
+ else if ( Blockly . localGhostConnection_ . type == Blockly . NEXT_STATEMENT &&
921
+ Blockly . localGhostConnection_ != this . ghostBlock_ . nextConnection ) {
922
+ var innerConnection = Blockly . localGhostConnection_ . targetConnection ;
923
+ innerConnection . sourceBlock_ . unplug ( false ) ;
924
+ var previousBlockNextConnection =
925
+ this . ghostBlock_ . previousConnection . targetConnection ;
926
+ this . ghostBlock_ . unplug ( true ) ;
927
+ if ( previousBlockNextConnection ) {
928
+ previousBlockNextConnection . connect ( innerConnection ) ;
857
929
}
858
930
}
859
- // This event has been handled. No need to bubble up to the document.
860
- e . stopPropagation ( ) ;
931
+ else {
932
+ this . ghostBlock_ . unplug ( true /* healStack */ ) ;
933
+ }
934
+
935
+ if ( Blockly . localGhostConnection_ . targetConnection ) {
936
+ throw 'LocalGhostConnection still connected at the end of disconnectGhost' ;
937
+ }
938
+ Blockly . localGhostConnection_ = null ;
939
+ this . ghostBlock_ . getSvgRoot ( ) . setAttribute ( 'visibility' , 'hidden' ) ;
861
940
} ;
862
941
863
942
/**
0 commit comments