Skip to content

Commit 343c2f5

Browse files
authored
feat: Add support for toggling readonly mode. (#8750)
* feat: Add methods for toggling and inspecting the readonly state of a workspace. * refactor: Use the new readonly setters/getters in place of checking the injection options. * fix: Fix bug that allowed dragging blocks from a flyout onto a readonly workspace. * feat: Toggle a `blocklyReadOnly` class when readonly status is changed. * chore: Placate the linter. * chore: Placate the compiler.
1 parent c88ebf1 commit 343c2f5

File tree

11 files changed

+54
-21
lines changed

11 files changed

+54
-21
lines changed

core/block.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -795,7 +795,7 @@ export class Block implements IASTNodeLocation {
795795
this.deletable &&
796796
!this.shadow &&
797797
!this.isDeadOrDying() &&
798-
!this.workspace.options.readOnly
798+
!this.workspace.isReadOnly()
799799
);
800800
}
801801

@@ -828,7 +828,7 @@ export class Block implements IASTNodeLocation {
828828
this.movable &&
829829
!this.shadow &&
830830
!this.isDeadOrDying() &&
831-
!this.workspace.options.readOnly
831+
!this.workspace.isReadOnly()
832832
);
833833
}
834834

@@ -917,7 +917,7 @@ export class Block implements IASTNodeLocation {
917917
*/
918918
isEditable(): boolean {
919919
return (
920-
this.editable && !this.isDeadOrDying() && !this.workspace.options.readOnly
920+
this.editable && !this.isDeadOrDying() && !this.workspace.isReadOnly()
921921
);
922922
}
923923

core/block_svg.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ export class BlockSvg
231231
this.applyColour();
232232
this.pathObject.updateMovable(this.isMovable() || this.isInFlyout);
233233
const svg = this.getSvgRoot();
234-
if (!this.workspace.options.readOnly && svg) {
234+
if (svg) {
235235
browserEvents.conditionalBind(svg, 'pointerdown', this, this.onMouseDown);
236236
}
237237

@@ -585,6 +585,8 @@ export class BlockSvg
585585
* @param e Pointer down event.
586586
*/
587587
private onMouseDown(e: PointerEvent) {
588+
if (this.workspace.isReadOnly()) return;
589+
588590
const gesture = this.workspace.getGesture(e);
589591
if (gesture) {
590592
gesture.handleBlockStart(e, this);
@@ -612,7 +614,7 @@ export class BlockSvg
612614
protected generateContextMenu(): Array<
613615
ContextMenuOption | LegacyContextMenuOption
614616
> | null {
615-
if (this.workspace.options.readOnly || !this.contextMenu) {
617+
if (this.workspace.isReadOnly() || !this.contextMenu) {
616618
return null;
617619
}
618620
const menuOptions = ContextMenuRegistry.registry.getContextMenuOptions(

core/comments/workspace_comment.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ export class WorkspaceComment {
144144
* workspace is read-only.
145145
*/
146146
isEditable(): boolean {
147-
return this.isOwnEditable() && !this.workspace.options.readOnly;
147+
return this.isOwnEditable() && !this.workspace.isReadOnly();
148148
}
149149

150150
/**
@@ -165,7 +165,7 @@ export class WorkspaceComment {
165165
* workspace is read-only.
166166
*/
167167
isMovable() {
168-
return this.isOwnMovable() && !this.workspace.options.readOnly;
168+
return this.isOwnMovable() && !this.workspace.isReadOnly();
169169
}
170170

171171
/**
@@ -189,7 +189,7 @@ export class WorkspaceComment {
189189
return (
190190
this.isOwnDeletable() &&
191191
!this.isDeadOrDying() &&
192-
!this.workspace.options.readOnly
192+
!this.workspace.isReadOnly()
193193
);
194194
}
195195

core/dragging/block_drag_strategy.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ export class BlockDragStrategy implements IDragStrategy {
7878
return (
7979
this.block.isOwnMovable() &&
8080
!this.block.isDeadOrDying() &&
81-
!this.workspace.options.readOnly &&
81+
!this.workspace.isReadOnly() &&
8282
// We never drag blocks in the flyout, only create new blocks that are
8383
// dragged.
8484
!this.block.isInFlyout

core/dragging/comment_drag_strategy.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export class CommentDragStrategy implements IDragStrategy {
2929
return (
3030
this.comment.isOwnMovable() &&
3131
!this.comment.isDeadOrDying() &&
32-
!this.workspace.options.readOnly
32+
!this.workspace.isReadOnly()
3333
);
3434
}
3535

core/flyout_base.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -786,7 +786,7 @@ export abstract class Flyout
786786
* @internal
787787
*/
788788
isBlockCreatable(block: BlockSvg): boolean {
789-
return block.isEnabled();
789+
return block.isEnabled() && !this.getTargetWorkspace().isReadOnly();
790790
}
791791

792792
/**

core/gesture.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -894,7 +894,7 @@ export class Gesture {
894894
'Cannot do a block click because the target block is ' + 'undefined',
895895
);
896896
}
897-
if (this.targetBlock.isEnabled()) {
897+
if (this.flyout.isBlockCreatable(this.targetBlock)) {
898898
if (!eventUtils.getGroup()) {
899899
eventUtils.setGroup(true);
900900
}

core/shortcut_items.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export function registerEscape() {
4040
const escapeAction: KeyboardShortcut = {
4141
name: names.ESCAPE,
4242
preconditionFn(workspace) {
43-
return !workspace.options.readOnly;
43+
return !workspace.isReadOnly();
4444
},
4545
callback(workspace) {
4646
// AnyDuringMigration because: Property 'hideChaff' does not exist on
@@ -62,7 +62,7 @@ export function registerDelete() {
6262
preconditionFn(workspace) {
6363
const selected = common.getSelected();
6464
return (
65-
!workspace.options.readOnly &&
65+
!workspace.isReadOnly() &&
6666
selected != null &&
6767
isDeletable(selected) &&
6868
selected.isDeletable() &&
@@ -113,7 +113,7 @@ export function registerCopy() {
113113
preconditionFn(workspace) {
114114
const selected = common.getSelected();
115115
return (
116-
!workspace.options.readOnly &&
116+
!workspace.isReadOnly() &&
117117
!Gesture.inProgress() &&
118118
selected != null &&
119119
isDeletable(selected) &&
@@ -164,7 +164,7 @@ export function registerCut() {
164164
preconditionFn(workspace) {
165165
const selected = common.getSelected();
166166
return (
167-
!workspace.options.readOnly &&
167+
!workspace.isReadOnly() &&
168168
!Gesture.inProgress() &&
169169
selected != null &&
170170
isDeletable(selected) &&
@@ -221,7 +221,7 @@ export function registerPaste() {
221221
const pasteShortcut: KeyboardShortcut = {
222222
name: names.PASTE,
223223
preconditionFn(workspace) {
224-
return !workspace.options.readOnly && !Gesture.inProgress();
224+
return !workspace.isReadOnly() && !Gesture.inProgress();
225225
},
226226
callback() {
227227
if (!copyData || !copyWorkspace) return false;
@@ -269,7 +269,7 @@ export function registerUndo() {
269269
const undoShortcut: KeyboardShortcut = {
270270
name: names.UNDO,
271271
preconditionFn(workspace) {
272-
return !workspace.options.readOnly && !Gesture.inProgress();
272+
return !workspace.isReadOnly() && !Gesture.inProgress();
273273
},
274274
callback(workspace, e) {
275275
// 'z' for undo 'Z' is for redo.
@@ -308,7 +308,7 @@ export function registerRedo() {
308308
const redoShortcut: KeyboardShortcut = {
309309
name: names.REDO,
310310
preconditionFn(workspace) {
311-
return !Gesture.inProgress() && !workspace.options.readOnly;
311+
return !Gesture.inProgress() && !workspace.isReadOnly();
312312
},
313313
callback(workspace, e) {
314314
// 'z' for undo 'Z' is for redo.

core/workspace.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ export class Workspace implements IASTNodeLocation {
114114
private readonly typedBlocksDB = new Map<string, Block[]>();
115115
private variableMap: IVariableMap<IVariableModel<IVariableState>>;
116116
private procedureMap: IProcedureMap = new ObservableProcedureMap();
117+
private readOnly = false;
117118

118119
/**
119120
* Blocks in the flyout can refer to variables that don't exist in the main
@@ -153,6 +154,8 @@ export class Workspace implements IASTNodeLocation {
153154
*/
154155
const VariableMap = this.getVariableMapClass();
155156
this.variableMap = new VariableMap(this);
157+
158+
this.setIsReadOnly(this.options.readOnly);
156159
}
157160

158161
/**
@@ -947,4 +950,23 @@ export class Workspace implements IASTNodeLocation {
947950
}
948951
return VariableMap;
949952
}
953+
954+
/**
955+
* Returns whether or not this workspace is in readonly mode.
956+
*
957+
* @returns True if the workspace is readonly, otherwise false.
958+
*/
959+
isReadOnly(): boolean {
960+
return this.readOnly;
961+
}
962+
963+
/**
964+
* Sets whether or not this workspace is in readonly mode.
965+
*
966+
* @param readOnly True to make the workspace readonly, otherwise false.
967+
*/
968+
setIsReadOnly(readOnly: boolean) {
969+
this.readOnly = readOnly;
970+
this.options.readOnly = readOnly;
971+
}
950972
}

core/workspace_svg.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1703,7 +1703,7 @@ export class WorkspaceSvg extends Workspace implements IASTNodeLocationSvg {
17031703
* @internal
17041704
*/
17051705
showContextMenu(e: PointerEvent) {
1706-
if (this.options.readOnly || this.isFlyout) {
1706+
if (this.isReadOnly() || this.isFlyout) {
17071707
return;
17081708
}
17091709
const menuOptions = ContextMenuRegistry.registry.getContextMenuOptions(
@@ -2532,6 +2532,15 @@ export class WorkspaceSvg extends Workspace implements IASTNodeLocationSvg {
25322532
dom.removeClass(this.injectionDiv, className);
25332533
}
25342534
}
2535+
2536+
override setIsReadOnly(readOnly: boolean) {
2537+
super.setIsReadOnly(readOnly);
2538+
if (readOnly) {
2539+
this.addClass('blocklyReadOnly');
2540+
} else {
2541+
this.removeClass('blocklyReadOnly');
2542+
}
2543+
}
25352544
}
25362545

25372546
/**

0 commit comments

Comments
 (0)