@@ -22,11 +22,49 @@ import {ASTNode, Marker} from 'blockly/core';
22
22
export class LineCursor extends Marker {
23
23
override type = 'cursor' ;
24
24
25
+ /** Has the cursor been installed in a workspace's marker manager? */
26
+ private installed = false ;
27
+
28
+ /** Old Cursor instance, saved during installation. */
29
+ private oldCursor : Blockly . Cursor | null = null ;
30
+
25
31
/**
26
- * Constructor for a line cursor.
32
+ * @param workspace The workspace this cursor belongs to .
27
33
*/
28
- constructor ( ) {
34
+ constructor ( public readonly workspace : Blockly . WorkspaceSvg ) {
29
35
super ( ) ;
36
+ // Bind selectListener to facilitate future install/uninstall.
37
+ this . selectListener = this . selectListener . bind ( this ) ;
38
+ }
39
+
40
+ /**
41
+ * Install this LineCursor in its workspace's marker manager and set
42
+ * up the select listener. The original cursor (if any) is saved
43
+ * for future use by .uninstall(), and its location is used to set
44
+ * this one's.
45
+ */
46
+ install ( ) {
47
+ if ( this . installed ) throw new Error ( 'LineCursor already installed' ) ;
48
+ const markerManager = this . workspace . getMarkerManager ( ) ;
49
+ this . oldCursor = markerManager . getCursor ( ) ;
50
+ markerManager . setCursor ( this ) ;
51
+ if ( this . oldCursor ) this . setCurNode ( this . oldCursor . getCurNode ( ) ) ;
52
+ this . workspace . addChangeListener ( this . selectListener ) ;
53
+ this . installed = true ;
54
+ }
55
+
56
+ /**
57
+ * Remove the select listener and uninstall this LineCursor from its
58
+ * workspace's marker manager, restoring any previously-existing
59
+ * cursor. Does not attempt to adjust original cursor's location.
60
+ */
61
+ uninstall ( ) {
62
+ if ( ! this . installed ) throw new Error ( 'LineCursor not yet installed' ) ;
63
+ this . workspace . removeChangeListener ( this . selectListener . bind ( this ) ) ;
64
+ if ( this . oldCursor ) {
65
+ this . workspace . getMarkerManager ( ) . setCursor ( this . oldCursor ) ;
66
+ }
67
+ this . installed = false ;
30
68
}
31
69
32
70
/**
@@ -410,25 +448,24 @@ export class LineCursor extends Marker {
410
448
* if so, update the cursor location (and any highlighting) to
411
449
* match.
412
450
*
413
- * This works reasonably well but has some glitches, most notably
414
- * that if the cursor is not on a block (e.g. it is on a connection
415
- * or the workspace) then it will remain visible in its previous
416
- * location until a cursor key is pressed.
451
+ * Doing this only when getCurNode would naturally be called works
452
+ * reasonably well but has some glitches, most notably that if the
453
+ * cursor was not on a block (e.g. it was on a connection or the
454
+ * workspace) when the user selected a block then it will remain
455
+ * visible in its previous location until some keyboard navigation occurs.
456
+ *
457
+ * To ameliorate this, the LineCursor constructor adds an event
458
+ * listener that calls getCurNode in response to SELECTED events.
417
459
*
418
- * TODO(#97): Remove this hack once Blockly is modified to update
419
- * the cursor/focus itself.
460
+ * Remove this hack once Blockly is modified to update the
461
+ * cursor/focus itself.
420
462
*
421
463
* @returns The current field, connection, or block the cursor is on.
422
464
*/
423
465
override getCurNode ( ) : ASTNode {
424
466
const curNode = super . getCurNode ( ) ;
425
467
const selected = Blockly . common . getSelected ( ) ;
426
- if (
427
- ( selected ?. workspace as Blockly . WorkspaceSvg )
428
- ?. getMarkerManager ( )
429
- . getCursor ( ) !== this
430
- )
431
- return curNode ;
468
+ if ( selected ?. workspace !== this . workspace ) return curNode ;
432
469
433
470
// Selected item is on workspace that this cursor belongs to.
434
471
const curLocation = curNode ?. getLocation ( ) ;
@@ -511,6 +548,17 @@ export class LineCursor extends Marker {
511
548
512
549
drawer . draw ( oldNode , newNode ) ;
513
550
}
551
+
552
+ /**
553
+ * Event listener that syncs the cursor location to the selected
554
+ * block on SELECTED events.
555
+ */
556
+ private selectListener ( event : Blockly . Events . Abstract ) {
557
+ if ( event . type !== Blockly . Events . SELECTED ) return ;
558
+ const selectedEvent = event as Blockly . Events . Selected ;
559
+ if ( selectedEvent . workspaceId !== this . workspace . id ) return ;
560
+ this . getCurNode ( ) ;
561
+ }
514
562
}
515
563
516
564
export const registrationName = 'LineCursor' ;
@@ -521,18 +569,3 @@ Blockly.registry.register(registrationType, registrationName, LineCursor);
521
569
export const pluginInfo = {
522
570
[ registrationType . toString ( ) ] : registrationName ,
523
571
} ;
524
-
525
- /**
526
- * Install this cursor on the marker manager in the same position as
527
- * the previous cursor.
528
- *
529
- * @param markerManager The currently active marker manager.
530
- */
531
- export function installCursor ( markerManager : Blockly . MarkerManager ) {
532
- const oldCurNode = markerManager . getCursor ( ) ?. getCurNode ( ) ;
533
- const lineCursor = new LineCursor ( ) ;
534
- markerManager . setCursor ( lineCursor ) ;
535
- if ( oldCurNode ) {
536
- markerManager . getCursor ( ) ?. setCurNode ( oldCurNode ) ;
537
- }
538
- }
0 commit comments