@@ -74,7 +74,8 @@ export class LineCursor extends Marker {
7474 const markerManager = this . workspace . getMarkerManager ( ) ;
7575 this . oldCursor = markerManager . getCursor ( ) ;
7676 markerManager . setCursor ( this ) ;
77- if ( this . oldCursor ) this . setCurNode ( this . oldCursor . getCurNode ( ) ) ;
77+ const oldCursorNode = this . oldCursor ?. getCurNode ( ) ;
78+ if ( oldCursorNode ) this . setCurNode ( oldCursorNode ) ;
7879 this . workspace . addChangeListener ( this . selectListener ) ;
7980 this . installed = true ;
8081 }
@@ -402,7 +403,7 @@ export class LineCursor extends Marker {
402403 preDelete ( deletedBlock : Blockly . Block ) {
403404 const curNode = this . getCurNode ( ) ;
404405
405- const nodes : Blockly . ASTNode [ ] = [ curNode ] ;
406+ const nodes : Blockly . ASTNode [ ] = curNode ? [ curNode ] : [ ] ;
406407 // The connection to which the deleted block is attached.
407408 const parentConnection =
408409 deletedBlock . previousConnection ?. targetConnection ??
@@ -425,7 +426,7 @@ export class LineCursor extends Marker {
425426 }
426427 // A location on the workspace beneath the deleted block.
427428 // Move to the workspace.
428- const curBlock = curNode . getSourceBlock ( ) ;
429+ const curBlock = curNode ? .getSourceBlock ( ) ;
429430 if ( curBlock ) {
430431 const workspaceNode = Blockly . ASTNode . createWorkspaceNode (
431432 this . workspace ,
@@ -475,7 +476,7 @@ export class LineCursor extends Marker {
475476 *
476477 * @returns The current field, connection, or block the cursor is on.
477478 */
478- override getCurNode ( ) : ASTNode {
479+ override getCurNode ( ) : ASTNode | null {
479480 const curNode = super . getCurNode ( ) ;
480481 const selected = Blockly . common . getSelected ( ) ;
481482 if ( selected ?. workspace !== this . workspace ) return curNode ;
@@ -494,6 +495,40 @@ export class LineCursor extends Marker {
494495 return newNode ;
495496 }
496497
498+ /**
499+ * Sets the object in charge of drawing the marker.
500+ *
501+ * We want to customize drawing, so rather than directly setting the given
502+ * object, we instead set a wrapper proxy object that passes through all
503+ * method calls and property accesses except for draw(), which it delegates
504+ * to the drawMarker() method in this class.
505+ *
506+ * @param drawer The object ~in charge of drawing the marker.
507+ */
508+ override setDrawer ( drawer : Blockly . blockRendering . MarkerSvg ) {
509+ const altDraw = function (
510+ this : LineCursor ,
511+ oldNode : ASTNode | null ,
512+ curNode : ASTNode | null ,
513+ ) {
514+ // Pass the unproxied, raw drawer object so that drawMarker can call its
515+ // `draw()` method without triggering infinite recursion.
516+ this . drawMarker ( oldNode , curNode , drawer ) ;
517+ } . bind ( this ) ;
518+
519+ super . setDrawer (
520+ new Proxy ( drawer , {
521+ get ( target : typeof drawer , prop : keyof typeof drawer ) {
522+ if ( prop === 'draw' ) {
523+ return altDraw ;
524+ }
525+
526+ return target [ prop ] ;
527+ } ,
528+ } ) ,
529+ ) ;
530+ }
531+
497532 /**
498533 * Set the location of the cursor and draw it.
499534 *
@@ -503,17 +538,7 @@ export class LineCursor extends Marker {
503538 * @param newNode The new location of the cursor.
504539 */
505540 override setCurNode ( newNode : ASTNode ) {
506- const oldNode = super . getCurNode ( ) ;
507- // Kludge: we can't set this.curNode directly, so we have to call
508- // super.setCurNode(...) to do it for us - but that would call
509- // this.drawer.draw(...), so prevent that by temporarily setting
510- // this.drawer to null (which we also can't do directly!)
511- const drawer = this . getDrawer ( ) ;
512- this . setDrawer ( null as any ) ; // Cast required since param is not nullable.
513541 super . setCurNode ( newNode ) ;
514- this . setDrawer ( drawer ) ;
515- // Draw this marker the way we want to.
516- this . drawMarker ( oldNode , newNode ) ;
517542 // Try to scroll cursor into view.
518543 if ( newNode ?. getType ( ) === ASTNode . types . BLOCK ) {
519544 const block = newNode . getLocation ( ) as Blockly . BlockSvg ;
@@ -540,21 +565,6 @@ export class LineCursor extends Marker {
540565 }
541566 }
542567
543- /**
544- * Redraw the current marker.
545- *
546- * Overrides normal Marker drawing logic to use this.drawMarker()
547- * instead of this.drawer.draw() directly.
548- *
549- * This hooks the method used by the renderer to draw the marker,
550- * preventing the marker drawer from showing a marker if we don't
551- * want it to.
552- */
553- override draw ( ) {
554- const curNode = super . getCurNode ( ) ;
555- this . drawMarker ( curNode , curNode ) ;
556- }
557-
558568 /**
559569 * Draw this cursor's marker.
560570 *
@@ -579,7 +589,11 @@ export class LineCursor extends Marker {
579589 * @param oldNode The previous node.
580590 * @param curNode The current node.
581591 */
582- private drawMarker ( oldNode : ASTNode , curNode : ASTNode ) {
592+ private drawMarker (
593+ oldNode : ASTNode | null ,
594+ curNode : ASTNode | null ,
595+ realDrawer : Blockly . blockRendering . MarkerSvg ,
596+ ) {
583597 // If old node was a block, unselect it or remove fake selection.
584598 if ( oldNode ?. getType ( ) === ASTNode . types . BLOCK ) {
585599 const block = oldNode . getLocation ( ) as Blockly . BlockSvg ;
@@ -592,13 +606,13 @@ export class LineCursor extends Marker {
592606
593607 // If curNode node is not block, just use the drawer.
594608 if ( curNode ?. getType ( ) !== ASTNode . types . BLOCK ) {
595- this . getDrawer ( ) ? .draw ( oldNode , curNode ) ;
609+ realDrawer . draw ( oldNode , curNode ) ;
596610 return ;
597611 }
598612
599613 // curNode is a block. Hide any visible marker SVG and instead
600614 // select the block or make it look selected.
601- super . hide ( ) ; // Calls this.drawer?.hide().
615+ realDrawer . hide ( ) ;
602616 const block = curNode . getLocation ( ) as Blockly . BlockSvg ;
603617 if ( ! block . isShadow ( ) ) {
604618 Blockly . common . setSelected ( block ) ;
@@ -608,7 +622,7 @@ export class LineCursor extends Marker {
608622
609623 // Call MarkerSvg.prototype.fireMarkerEvent like
610624 // MarkerSvg.prototype.draw would (even though it's private).
611- ( this . getDrawer ( ) as any ) ?. fireMarkerEvent ?.( oldNode , curNode ) ;
625+ ( realDrawer as any ) ?. fireMarkerEvent ?.( oldNode , curNode ) ;
612626 }
613627
614628 /**
0 commit comments