From aa0a574364a750857ee2800e6e6697d076f6889f Mon Sep 17 00:00:00 2001 From: Noel Chou Date: Wed, 8 Apr 2026 19:44:40 -0400 Subject: [PATCH] BL-16069 Disable tools during Change Layout mode --- src/BloomBrowserUI/app/EditTabPane.tsx | 36 ++++++++++++++++++- .../bookEdit/js/AbovePageControls.tsx | 1 + src/BloomBrowserUI/bookEdit/js/origami.ts | 15 +++++--- src/BloomBrowserUI/bookEdit/workspaceRoot.ts | 22 ++++++++++++ 4 files changed, 69 insertions(+), 5 deletions(-) diff --git a/src/BloomBrowserUI/app/EditTabPane.tsx b/src/BloomBrowserUI/app/EditTabPane.tsx index 853d4a8ae50b..4cd2ce333044 100644 --- a/src/BloomBrowserUI/app/EditTabPane.tsx +++ b/src/BloomBrowserUI/app/EditTabPane.tsx @@ -1,6 +1,7 @@ import * as React from "react"; import { css } from "@emotion/react"; import { get } from "../utils/bloomApi"; +import { setToolboxEnabledHandler } from "../bookEdit/workspaceRoot"; interface IEditFrameSources { pageListSrc: string; @@ -22,6 +23,7 @@ export const EditTabPane: React.FunctionComponent<{ active: boolean }> = ( defaultEditFrameSources, ); const [toolboxIsShowing, setToolboxIsShowing] = React.useState(true); + const [toolboxIsEnabled, setToolboxIsEnabled] = React.useState(true); // Request edit-frame URLs from C# when edit mode becomes active so app.tsx controls iframe rendering. React.useEffect(() => { @@ -39,6 +41,22 @@ export const EditTabPane: React.FunctionComponent<{ active: boolean }> = ( }); }, [props.active]); + React.useEffect(() => { + // We will use this to disable and hide the toolbox when in Change Layout mode (BL-16069) + setToolboxEnabledHandler((enabled) => { + // per Devin, if in the future we want to read state values in here we should remember to useRef to + // avoid stale reads + setToolboxIsEnabled(enabled); + if (!enabled) { + setToolboxIsShowing(false); + } + }); + + return () => { + setToolboxEnabledHandler(undefined); + }; + }, []); + return (
= ( top: 3px; } + .pure-toggle-label.toolbox-disabled { + opacity: 0.45; + cursor: default; + } + + .pure-toggle-label.toolbox-disabled .pure-toggle-icon { + filter: grayscale(1); + } + .pure-drawer { position: absolute; top: 0; @@ -123,14 +150,21 @@ export const EditTabPane: React.FunctionComponent<{ active: boolean }> = ( id="pure-toggle-right" data-toggle="right" checked={toolboxIsShowing} + disabled={!toolboxIsEnabled} onChange={(event) => { + if (!toolboxIsEnabled) { + return; + } setToolboxIsShowing(event.currentTarget.checked); }} /> diff --git a/src/BloomBrowserUI/bookEdit/js/AbovePageControls.tsx b/src/BloomBrowserUI/bookEdit/js/AbovePageControls.tsx index dd0f7228bd33..616b05ed07a1 100644 --- a/src/BloomBrowserUI/bookEdit/js/AbovePageControls.tsx +++ b/src/BloomBrowserUI/bookEdit/js/AbovePageControls.tsx @@ -49,6 +49,7 @@ export function updateAbovePageControls( export function resetAbovePageControls(): void { currentState = defaultState; + getWorkspaceBundleExports().setToolboxEnabled(true); const container = document.getElementsByClassName( "above-page-control-container", diff --git a/src/BloomBrowserUI/bookEdit/js/origami.ts b/src/BloomBrowserUI/bookEdit/js/origami.ts index 6213cd12ac4f..cd2041b1fb23 100644 --- a/src/BloomBrowserUI/bookEdit/js/origami.ts +++ b/src/BloomBrowserUI/bookEdit/js/origami.ts @@ -10,6 +10,7 @@ import "../../lib/jquery.i18n.custom"; import { splitPane } from "../../lib/split-pane/split-pane"; import { kCanvasToolId } from "../toolbox/toolIds"; import { updateAbovePageControls } from "./AbovePageControls"; +import { getWorkspaceBundleExports } from "./workspaceFrames"; $(() => { splitPane($("div.split-pane")); @@ -32,15 +33,19 @@ export function setupOrigami() { )[0] as HTMLElement | undefined; if (bloomPage) { const showChangeLayoutModeControls = customPages.length > 0; + const isChangeLayoutMode = $(".marginBox").hasClass( + "origami-layout-mode", + ); updateAbovePageControls({ isGamePage: bloomPage?.getAttribute("data-tool-id") === "game", showChangeLayoutModeToggle: showChangeLayoutModeControls, - isChangeLayoutMode: $(".marginBox").hasClass( - "origami-layout-mode", - ), + isChangeLayoutMode, onChangeLayoutModeToggle: handleChangeLayoutModeToggle, }); + getWorkspaceBundleExports().setToolboxEnabled( + !isChangeLayoutMode, + ); } // I'm not clear why the rest of this needs to wait until we have // the two results, but none of the controls shows up if we leave it all @@ -190,9 +195,11 @@ function changeLayoutModeToggleClickHandler() { function handleChangeLayoutModeToggle() { changeLayoutModeToggleClickHandler(); + const isChangeLayoutMode = $(".marginBox").hasClass("origami-layout-mode"); updateAbovePageControls({ - isChangeLayoutMode: $(".marginBox").hasClass("origami-layout-mode"), + isChangeLayoutMode, }); + getWorkspaceBundleExports().setToolboxEnabled(!isChangeLayoutMode); } function GetTextBoxPropertiesDialog() { diff --git a/src/BloomBrowserUI/bookEdit/workspaceRoot.ts b/src/BloomBrowserUI/bookEdit/workspaceRoot.ts index 0332219fcf04..24f407266745 100644 --- a/src/BloomBrowserUI/bookEdit/workspaceRoot.ts +++ b/src/BloomBrowserUI/bookEdit/workspaceRoot.ts @@ -17,6 +17,7 @@ export interface IWorkspaceExports { options: JQueryUI.DialogOptions, ): JQuery; closeDialog(id: string): void; + setToolboxEnabled(enabled: boolean): void; toolboxIsShowing(): boolean; doWhenToolboxLoaded( task: (toolboxFrameExports: IToolboxFrameExports) => unknown, @@ -188,6 +189,25 @@ export function toolboxIsShowing() { return checkbox ? checkbox.checked : true; } +// The toolbox should be disabled whenever we are in Change Layout mode (BL-16069) +let toolboxEnabled = true; +let toolboxEnabledHandler: ((enabled: boolean) => void) | undefined; + +// Registers a handler that will be called whenever we want to enable/disable the toolbox +// We will use this handler to hide/show the toolbox and enable/disable its opening +export function setToolboxEnabledHandler( + handler: ((enabled: boolean) => void) | undefined, +): void { + toolboxEnabledHandler = handler; + toolboxEnabledHandler?.(toolboxEnabled); +} + +// Enables or disables the toolbox toggle; used to hide the toolbox during Change Layout mode (BL-16069) +export function setToolboxEnabled(enabled: boolean): void { + toolboxEnabled = enabled; + toolboxEnabledHandler?.(enabled); +} + // Do this task when the toolbox is loaded. If it isn't already, we set a timeout and do it when we can. // (The value passed to the task function will be the value from getToolboxBundleExports(). Unfortunately we // haven't yet managed to declare a type for that, so I can't easily specify it here.) @@ -359,6 +379,7 @@ interface WorkspaceBundleApi { switchContentPage: typeof switchContentPage; showDialog: typeof showDialog; closeDialog: typeof closeDialog; + setToolboxEnabled: typeof setToolboxEnabled; toolboxIsShowing: typeof toolboxIsShowing; doWhenToolboxLoaded: typeof doWhenToolboxLoaded; canUndo: typeof canUndo; @@ -399,6 +420,7 @@ window.workspaceBundle = { switchContentPage, showDialog, closeDialog, + setToolboxEnabled, toolboxIsShowing, doWhenToolboxLoaded, canUndo,