Web Frame: URL editing uses window.prompt — replace with a proper modal #80

Open
opened 2026-04-27 13:13:24 +00:00 by AhmedHanafy725 · 3 comments
Member

Bug

Double-clicking a Web Frame on the board to change its URL pops a window.prompt(...) dialog, which:

  • Looks out of place next to the rest of the app (every other text-edit flow on the board uses an in-page modal or contenteditable overlay).
  • Cannot be styled with the app's theme (dark/light) so it visually breaks the board context.
  • Is blocked by some browser settings and tab-modal flags, and disappears the moment the user interacts with anything else.
  • Doesn't validate the input, doesn't show errors inline, and doesn't allow keyboard accelerators consistent with the rest of the app.

Reproduction

  1. Open a board.
  2. Place a Web Frame.
  3. Double-click it.

Observed: a native browser prompt opens.

Expected: an in-page modal styled like the app's other modals (rename board, new board, new workspace) opens with a URL input, Cancel and Save buttons, and Enter/Escape keyboard support.

Root cause

crates/hero_whiteboard_ui/static/web/js/whiteboard/webframe.js:255-281 -- the promptUrl(group) function:

function promptUrl(group) {
    var state = group._wfState;
    var newUrl = prompt('Enter URL:', state.url);
    if (newUrl && newUrl !== state.url) {
        if (!/^https?:\/\//i.test(newUrl)) {
            newUrl = 'https://' + newUrl;
        }
        state.url = newUrl;
        ...
    }
}

It's invoked from the webframe's dblclick dbltap handler at webframe.js:80-83. There is no other caller -- it's a private helper inside the IIFE module.

Affected files

  • crates/hero_whiteboard_ui/static/web/js/whiteboard/webframe.js -- replace the prompt call with a modal flow; keep all the existing post-update side effects (label text, iframe src, objStore.url, layer redraw, sync).
  • crates/hero_whiteboard_ui/templates/web/board.html -- add the modal markup so it lives in the board template (web frames only exist on board pages, not on the home page).

No server / SDK / openrpc / DB changes -- this is a pure UI refactor. The board's eventual sync still goes through WhiteboardSync.onUpdate like today.

Expected behavior

Double-clicking a Web Frame opens an in-page modal that:

  • Shows a URL text input pre-filled with the current URL.
  • Auto-prepends https:// if no protocol is given (matches the existing logic at webframe.js:260-262).
  • Has Cancel and Save buttons; Enter submits, Escape cancels.
  • Surfaces empty-URL errors inline (no second alert popup).
  • Is themed with the app's CSS variables (var(--wb-surface), var(--wb-bg), var(--wb-border), var(--wb-text), var(--wb-text-muted), var(--wb-error)) so it matches dark/light mode like the existing rename/new-board modals.
  • On Save, performs the same downstream updates the current promptUrl does: update state.url, label text, iframe src, fallback link href, objStore[id].url, layer batchDraw, and WhiteboardSync.onUpdate(group) (the existing helper already calls it via the surrounding flow -- if not, the modal flow must trigger sync explicitly so the change propagates to other windows).

Reference modals to match

  • Rename Board modal: crates/hero_whiteboard_ui/templates/web/home.html (the inline <div id="rename-modal"> block).
  • New Board modal and New Workspace modal: same file -- recently introduced patterns with display:block labels, box-sizing:border-box inputs, inline error region, Cancel + Create buttons, Enter/Escape keyboard handlers, and var(--wb-...) theming.

The Web Frame URL modal should follow the same conventions for visual consistency.

Acceptance criteria

  • Double-clicking a Web Frame opens an in-page modal styled like the app's other modals (rename / new board / new workspace).
  • The modal pre-fills the input with the current URL.
  • Save performs the existing downstream updates (state, label, iframe src, fallback link, objStore, redraw) and triggers a sync update so other windows on the same board see the change.
  • Save with no protocol prepends https:// (current behavior preserved).
  • Save with an empty input shows an inline error inside the modal (no alert).
  • Cancel closes the modal without changing anything.
  • Enter submits the form; Escape cancels (matches the rest of the page's modals).
  • No regression in the iframe overlay positioning, drag/resize, or sync.
  • No window.prompt or window.alert calls remain in the Web Frame URL flow.
  • No changes outside webframe.js and templates/web/board.html (no server/SDK/openrpc edits).

Notes

  • Keep the existing promptUrl(group) entry point (just have it open the modal and pass the group), so the call from webframe.js:82 (the dblclick handler) doesn't need to change -- this keeps the diff small and local.
  • Consider also offering an inline-edit affordance from the right-side property panel (properties.js:83) in a follow-up; out of scope for this issue.
## Bug Double-clicking a Web Frame on the board to change its URL pops a `window.prompt(...)` dialog, which: - Looks out of place next to the rest of the app (every other text-edit flow on the board uses an in-page modal or contenteditable overlay). - Cannot be styled with the app's theme (dark/light) so it visually breaks the board context. - Is blocked by some browser settings and tab-modal flags, and disappears the moment the user interacts with anything else. - Doesn't validate the input, doesn't show errors inline, and doesn't allow keyboard accelerators consistent with the rest of the app. ## Reproduction 1. Open a board. 2. Place a Web Frame. 3. Double-click it. Observed: a native browser `prompt` opens. Expected: an in-page modal styled like the app's other modals (rename board, new board, new workspace) opens with a URL input, Cancel and Save buttons, and Enter/Escape keyboard support. ## Root cause `crates/hero_whiteboard_ui/static/web/js/whiteboard/webframe.js:255-281` -- the `promptUrl(group)` function: ```js function promptUrl(group) { var state = group._wfState; var newUrl = prompt('Enter URL:', state.url); if (newUrl && newUrl !== state.url) { if (!/^https?:\/\//i.test(newUrl)) { newUrl = 'https://' + newUrl; } state.url = newUrl; ... } } ``` It's invoked from the webframe's `dblclick dbltap` handler at `webframe.js:80-83`. There is no other caller -- it's a private helper inside the IIFE module. ## Affected files - `crates/hero_whiteboard_ui/static/web/js/whiteboard/webframe.js` -- replace the `prompt` call with a modal flow; keep all the existing post-update side effects (label text, iframe `src`, `objStore.url`, layer redraw, sync). - `crates/hero_whiteboard_ui/templates/web/board.html` -- add the modal markup so it lives in the board template (web frames only exist on board pages, not on the home page). No server / SDK / openrpc / DB changes -- this is a pure UI refactor. The board's eventual sync still goes through `WhiteboardSync.onUpdate` like today. ## Expected behavior Double-clicking a Web Frame opens an in-page modal that: - Shows a `URL` text input pre-filled with the current URL. - Auto-prepends `https://` if no protocol is given (matches the existing logic at `webframe.js:260-262`). - Has Cancel and Save buttons; Enter submits, Escape cancels. - Surfaces empty-URL errors inline (no second `alert` popup). - Is themed with the app's CSS variables (`var(--wb-surface)`, `var(--wb-bg)`, `var(--wb-border)`, `var(--wb-text)`, `var(--wb-text-muted)`, `var(--wb-error)`) so it matches dark/light mode like the existing rename/new-board modals. - On Save, performs the same downstream updates the current `promptUrl` does: update `state.url`, label text, iframe `src`, `fallback` link `href`, `objStore[id].url`, layer batchDraw, and `WhiteboardSync.onUpdate(group)` (the existing helper already calls it via the surrounding flow -- if not, the modal flow must trigger sync explicitly so the change propagates to other windows). ## Reference modals to match - Rename Board modal: `crates/hero_whiteboard_ui/templates/web/home.html` (the inline `<div id="rename-modal">` block). - New Board modal and New Workspace modal: same file -- recently introduced patterns with `display:block` labels, `box-sizing:border-box` inputs, inline error region, Cancel + Create buttons, Enter/Escape keyboard handlers, and `var(--wb-...)` theming. The Web Frame URL modal should follow the same conventions for visual consistency. ## Acceptance criteria - [ ] Double-clicking a Web Frame opens an in-page modal styled like the app's other modals (rename / new board / new workspace). - [ ] The modal pre-fills the input with the current URL. - [ ] Save performs the existing downstream updates (state, label, iframe src, fallback link, objStore, redraw) and triggers a sync update so other windows on the same board see the change. - [ ] Save with no protocol prepends `https://` (current behavior preserved). - [ ] Save with an empty input shows an inline error inside the modal (no `alert`). - [ ] Cancel closes the modal without changing anything. - [ ] Enter submits the form; Escape cancels (matches the rest of the page's modals). - [ ] No regression in the iframe overlay positioning, drag/resize, or sync. - [ ] No `window.prompt` or `window.alert` calls remain in the Web Frame URL flow. - [ ] No changes outside `webframe.js` and `templates/web/board.html` (no server/SDK/openrpc edits). ## Notes - Keep the existing `promptUrl(group)` entry point (just have it open the modal and pass the group), so the call from `webframe.js:82` (the dblclick handler) doesn't need to change -- this keeps the diff small and local. - Consider also offering an inline-edit affordance from the right-side property panel (`properties.js:83`) in a follow-up; out of scope for this issue.
Author
Member

Implementation Spec for Issue #80

Objective

Replace window.prompt in the Web Frame URL-edit flow with an in-page modal styled like the existing home-page modals (rename / new board / new workspace), preserving every existing downstream side effect (state, label, iframe src, fallback link, objStore, layer redraw, sync).

Requirements

  • Double-clicking a Web Frame opens an in-page modal with a URL input pre-filled to the current value.
  • Save: applies the same auto-prepend https:// rule the current code uses, updates state.url, label text, iframe src, fallback <a> href, objStore[id].url, calls WhiteboardCanvas.getObjectLayer().batchDraw(), and calls WhiteboardSync.onUpdate(group) so the change syncs to other windows.
  • Empty input shows an inline error inside the modal (no alert).
  • Cancel closes the modal without changes.
  • Enter submits, Escape cancels.
  • Modal uses var(--wb-...) CSS variables so it matches dark/light themes.
  • No window.prompt / window.alert calls remain in the Web Frame URL flow.
  • Diff stays inside crates/hero_whiteboard_ui/static/web/js/whiteboard/webframe.js and crates/hero_whiteboard_ui/templates/web/board.html.

Files to Modify

  • crates/hero_whiteboard_ui/templates/web/board.html — add modal markup and a top-level keydown handler for Enter/Escape (matches the home page's pattern).
  • crates/hero_whiteboard_ui/static/web/js/whiteboard/webframe.js — rewrite promptUrl(group) to drive the modal asynchronously (or via a queued callback). Keep the function name and its single internal caller (webframe.js:80-83) unchanged so the dblclick flow is preserved.

No server / SDK / openrpc / DB changes.

Implementation Plan

Step 1: Add the modal markup + keydown handler to board.html

Files: crates/hero_whiteboard_ui/templates/web/board.html

  • Add a <div id="webframe-url-modal"> block inside {% block content %} styled like the home-page modals: fullscreen overlay, centered card with padding: 24px; width: 400px; max-width: 90vw;. Inside the card:
    • <h3> Edit Web Frame URL.
    • A wrapper <div> containing a display:block <label> URL and a box-sizing:border-box; width:100% <input id="webframe-url-input" type="text">.
    • An inline <div id="webframe-url-error"> for empty/error messaging, styled with var(--wb-error) and hidden by default.
    • A button row with Cancel (closes modal) and Save (submits).
  • In {% block scripts %}, add a small <script> that wires:
    • WhiteboardWebframe.openUrlModal(group) — exposed by webframe.js (Step 2). The modal is opened by webframe.js, not by board.html. The <script> block here only adds the keydown handler that listens for Enter/Escape while the modal is visible: Enter calls window.__webframeUrlModalSubmit && window.__webframeUrlModalSubmit(), Escape calls window.__webframeUrlModalCancel && window.__webframeUrlModalCancel().
    • These two callbacks are set by webframe.js when the modal opens, and cleared on close, so the modal logic stays in webframe.js (no global state in board.html beyond the event hookup).

Dependencies: none.

Step 2: Rewire promptUrl to drive the modal in webframe.js

Files: crates/hero_whiteboard_ui/static/web/js/whiteboard/webframe.js

  • Replace the body of promptUrl(group) with logic that:
    1. Reads var state = group._wfState;.
    2. Looks up var modal = document.getElementById('webframe-url-modal'); — if absent (e.g. embed/share view that doesn't render the modal), fall back to prompt(...) with the existing logic so the feature still works.
    3. Otherwise: pre-fills webframe-url-input with state.url, hides webframe-url-error, shows the modal (display:flex), focuses+selects the input, and assigns window.__webframeUrlModalSubmit and window.__webframeUrlModalCancel callbacks.
    4. On submit: validate the input (trim; if empty, show inline error and bail). Auto-prepend https:// if no protocol. If unchanged from state.url, just close the modal. Otherwise update state.url, label text via truncateUrl(newUrl, 50), iframe src, fallback link href, and objStore[id].url. Call WhiteboardCanvas.getObjectLayer().batchDraw() and WhiteboardSync.onUpdate(group). Close the modal.
    5. On cancel: close the modal, clear the global callbacks.
  • Add a small helper closeUrlModal() inside the IIFE that hides the modal and clears the global callbacks.
  • Wire the modal's onclick Save and Cancel buttons (declared in board.html) to call exported helpers via the global window callbacks. To avoid leaking globals, consider exposing WhiteboardWebframe.submitUrlModal and WhiteboardWebframe.cancelUrlModal and using onclick="WhiteboardWebframe.submitUrlModal()" in board.html. (Either pattern is acceptable; pick the one that matches existing code style.)
  • Verify there's still no other caller of promptUrl outside the dblclick handler at line 80-83 (grep -rn promptUrl crates/hero_whiteboard_ui confirms it).

Dependencies: Step 1 (modal markup must exist for the modal path to take effect).

Acceptance Criteria

  • Double-click a Web Frame: an in-page modal opens, themed via var(--wb-...).
  • Modal pre-fills the input with the current URL.
  • Save updates the webframe (state, label, iframe src, fallback link, objStore, redraw) and triggers a sync update so other windows see the change.
  • Save with no protocol prepends https://.
  • Save with empty input shows inline error in the modal (no alert).
  • Cancel closes the modal with no changes.
  • Enter submits; Escape cancels.
  • No regression in iframe overlay positioning, drag, resize, or sync.
  • No window.prompt / window.alert calls remain in the Web Frame URL flow.
  • Diff is contained to webframe.js and templates/web/board.html.

Notes

  • The fallback to prompt(...) when the modal element isn't present is a safety net for embed/share routes that may render board.html differently (e.g. templates/web/embed.html). If grepping shows the embed view also renders board.html ({% extends "web/board.html" %}-style), the modal will be present and the fallback never runs — but it's a cheap safety guard.
  • Match the dark/light theming convention used in home.html's recent modals: display:block labels, box-sizing:border-box inputs, inline var(--wb-error) text region, Cancel + Save buttons (btn-sm + btn-sm btn-primary).
  • Don't change truncateUrl, the iframe overlay positioning, or any other webframe internals.
## Implementation Spec for Issue #80 ### Objective Replace `window.prompt` in the Web Frame URL-edit flow with an in-page modal styled like the existing home-page modals (rename / new board / new workspace), preserving every existing downstream side effect (state, label, iframe `src`, fallback link, objStore, layer redraw, sync). ### Requirements - Double-clicking a Web Frame opens an in-page modal with a URL input pre-filled to the current value. - Save: applies the same auto-prepend `https://` rule the current code uses, updates `state.url`, label text, iframe `src`, fallback `<a>` `href`, `objStore[id].url`, calls `WhiteboardCanvas.getObjectLayer().batchDraw()`, and calls `WhiteboardSync.onUpdate(group)` so the change syncs to other windows. - Empty input shows an inline error inside the modal (no `alert`). - Cancel closes the modal without changes. - Enter submits, Escape cancels. - Modal uses `var(--wb-...)` CSS variables so it matches dark/light themes. - No `window.prompt` / `window.alert` calls remain in the Web Frame URL flow. - Diff stays inside `crates/hero_whiteboard_ui/static/web/js/whiteboard/webframe.js` and `crates/hero_whiteboard_ui/templates/web/board.html`. ### Files to Modify - `crates/hero_whiteboard_ui/templates/web/board.html` — add modal markup and a top-level keydown handler for Enter/Escape (matches the home page's pattern). - `crates/hero_whiteboard_ui/static/web/js/whiteboard/webframe.js` — rewrite `promptUrl(group)` to drive the modal asynchronously (or via a queued callback). Keep the function name and its single internal caller (`webframe.js:80-83`) unchanged so the dblclick flow is preserved. No server / SDK / openrpc / DB changes. ### Implementation Plan #### Step 1: Add the modal markup + keydown handler to board.html Files: `crates/hero_whiteboard_ui/templates/web/board.html` - Add a `<div id="webframe-url-modal">` block inside `{% block content %}` styled like the home-page modals: fullscreen overlay, centered card with `padding: 24px; width: 400px; max-width: 90vw;`. Inside the card: - `<h3>` `Edit Web Frame URL`. - A wrapper `<div>` containing a `display:block` `<label>` `URL` and a `box-sizing:border-box; width:100%` `<input id="webframe-url-input" type="text">`. - An inline `<div id="webframe-url-error">` for empty/error messaging, styled with `var(--wb-error)` and hidden by default. - A button row with `Cancel` (closes modal) and `Save` (submits). - In `{% block scripts %}`, add a small `<script>` that wires: - `WhiteboardWebframe.openUrlModal(group)` — exposed by webframe.js (Step 2). The modal is opened by webframe.js, not by board.html. The `<script>` block here only adds the keydown handler that listens for Enter/Escape while the modal is visible: Enter calls `window.__webframeUrlModalSubmit && window.__webframeUrlModalSubmit()`, Escape calls `window.__webframeUrlModalCancel && window.__webframeUrlModalCancel()`. - These two callbacks are set by webframe.js when the modal opens, and cleared on close, so the modal logic stays in webframe.js (no global state in board.html beyond the event hookup). Dependencies: none. #### Step 2: Rewire `promptUrl` to drive the modal in webframe.js Files: `crates/hero_whiteboard_ui/static/web/js/whiteboard/webframe.js` - Replace the body of `promptUrl(group)` with logic that: 1. Reads `var state = group._wfState;`. 2. Looks up `var modal = document.getElementById('webframe-url-modal');` — if absent (e.g. embed/share view that doesn't render the modal), fall back to `prompt(...)` with the existing logic so the feature still works. 3. Otherwise: pre-fills `webframe-url-input` with `state.url`, hides `webframe-url-error`, shows the modal (`display:flex`), focuses+selects the input, and assigns `window.__webframeUrlModalSubmit` and `window.__webframeUrlModalCancel` callbacks. 4. On submit: validate the input (trim; if empty, show inline error and bail). Auto-prepend `https://` if no protocol. If unchanged from `state.url`, just close the modal. Otherwise update `state.url`, label text via `truncateUrl(newUrl, 50)`, iframe `src`, fallback link `href`, and `objStore[id].url`. Call `WhiteboardCanvas.getObjectLayer().batchDraw()` and `WhiteboardSync.onUpdate(group)`. Close the modal. 5. On cancel: close the modal, clear the global callbacks. - Add a small helper `closeUrlModal()` inside the IIFE that hides the modal and clears the global callbacks. - Wire the modal's `onclick` Save and Cancel buttons (declared in board.html) to call exported helpers via the global window callbacks. To avoid leaking globals, consider exposing `WhiteboardWebframe.submitUrlModal` and `WhiteboardWebframe.cancelUrlModal` and using `onclick="WhiteboardWebframe.submitUrlModal()"` in board.html. (Either pattern is acceptable; pick the one that matches existing code style.) - Verify there's still no other caller of `promptUrl` outside the dblclick handler at line 80-83 (`grep -rn promptUrl crates/hero_whiteboard_ui` confirms it). Dependencies: Step 1 (modal markup must exist for the modal path to take effect). ### Acceptance Criteria - [ ] Double-click a Web Frame: an in-page modal opens, themed via `var(--wb-...)`. - [ ] Modal pre-fills the input with the current URL. - [ ] Save updates the webframe (state, label, iframe src, fallback link, objStore, redraw) and triggers a sync update so other windows see the change. - [ ] Save with no protocol prepends `https://`. - [ ] Save with empty input shows inline error in the modal (no `alert`). - [ ] Cancel closes the modal with no changes. - [ ] Enter submits; Escape cancels. - [ ] No regression in iframe overlay positioning, drag, resize, or sync. - [ ] No `window.prompt` / `window.alert` calls remain in the Web Frame URL flow. - [ ] Diff is contained to `webframe.js` and `templates/web/board.html`. ### Notes - The fallback to `prompt(...)` when the modal element isn't present is a safety net for embed/share routes that may render `board.html` differently (e.g. `templates/web/embed.html`). If grepping shows the embed view also renders `board.html` (`{% extends "web/board.html" %}`-style), the modal will be present and the fallback never runs — but it's a cheap safety guard. - Match the dark/light theming convention used in `home.html`'s recent modals: `display:block` labels, `box-sizing:border-box` inputs, inline `var(--wb-error)` text region, Cancel + Save buttons (`btn-sm` + `btn-sm btn-primary`). - Don't change `truncateUrl`, the iframe overlay positioning, or any other webframe internals.
Author
Member

Test Results

  • cargo test --workspace --lib: 4 lib targets, 0 tests / 0 passed / 0 failed each.
  • cargo clippy --workspace -- -D warnings: clean.
  • cargo check --workspace: clean.
  • node --check webframe.js: parses cleanly.

This is a UI-only change (HTML template + JS). Manual verification recommended:

  1. Open a board, place a Web Frame, double-click it. Confirm a themed modal appears (not a browser prompt).
  2. Save with example.com (no protocol). Confirm the iframe navigates to https://example.com and the label updates.
  3. Save with empty input. Confirm an inline error appears in the modal (no alert).
  4. Cancel — confirm nothing changes.
  5. Open the same board in a second window. Save a new URL in window A. Confirm window B's iframe and label sync.
  6. Press Enter while focused in the input — submits. Press Escape — cancels.
## Test Results - `cargo test --workspace --lib`: 4 lib targets, 0 tests / 0 passed / 0 failed each. - `cargo clippy --workspace -- -D warnings`: clean. - `cargo check --workspace`: clean. - `node --check webframe.js`: parses cleanly. This is a UI-only change (HTML template + JS). Manual verification recommended: 1. Open a board, place a Web Frame, double-click it. Confirm a themed modal appears (not a browser prompt). 2. Save with `example.com` (no protocol). Confirm the iframe navigates to `https://example.com` and the label updates. 3. Save with empty input. Confirm an inline error appears in the modal (no `alert`). 4. Cancel — confirm nothing changes. 5. Open the same board in a second window. Save a new URL in window A. Confirm window B's iframe and label sync. 6. Press Enter while focused in the input — submits. Press Escape — cancels.
Author
Member

Implementation Summary

Changes

  • crates/hero_whiteboard_ui/templates/web/board.html (+34 / -0)
    • Added a <div id="webframe-url-modal"> block matching the home page's modal styling: themed via var(--wb-...) CSS variables, display:block label, box-sizing:border-box input, inline error region, Cancel + Save buttons.
    • Added a keydown handler at the document level that routes Enter/Escape to WhiteboardWebframe.submitUrlModal / cancelUrlModal while the modal is visible.
  • crates/hero_whiteboard_ui/static/web/js/whiteboard/webframe.js (+82 / -21)
    • Replaced promptUrl(group)'s body. It now opens the in-page modal (when present) and pre-fills the input with the current URL.
    • Extracted the post-edit side effects into applyNewUrl(group, rawUrl) — handles trim, https:// auto-prepend, state update, label retext (truncateUrl(newUrl, 50)), iframe src, fallback link href, objStore[id].url, layer batchDraw, and WhiteboardSync.onUpdate(group) to propagate to other windows.
    • Added submitUrlModal (validates the input, shows inline error on empty, calls applyNewUrl, closes the modal) and cancelUrlModal (just closes), exposed via the module's public surface for the template's onclick and keydown handlers.
    • Kept a fallback to native prompt(...) when the modal element isn't rendered (defensive — covers any view that loads webframe.js without including the modal markup).

Why the fix is local to two files

The legacy prompt was a private helper inside the webframe IIFE with a single internal caller (the dblclick handler at webframe.js:80-83). The new module exports + the modal markup live where the user-facing flow happens. No server / SDK / openrpc / DB changes; no other JS module touched.

Verification

  • cargo test --workspace --lib passes (4 lib targets, 0 tests).
  • cargo clippy --workspace -- -D warnings: clean.
  • node --check webframe.js: parses cleanly.

Notes / caveats

  • applyNewUrl now explicitly calls WhiteboardSync.onUpdate(group), where the legacy promptUrl relied on neighbouring code paths. The early-return when the new URL equals the old URL preserves the legacy no-op behavior so this isn't a redundant sync.
  • The \uD83C\uDF10 globe glyph used in the label is preserved verbatim from the original code.
  • Minimum diff: kept promptUrl(group) as the function called from the dblclick handler (webframe.js:80-83), so the call site needed no edit.
  • Manual testing should confirm: dark+light themes, single-window save, two-window sync, Enter/Escape, empty-input inline error.
## Implementation Summary ### Changes - `crates/hero_whiteboard_ui/templates/web/board.html` (+34 / -0) - Added a `<div id="webframe-url-modal">` block matching the home page's modal styling: themed via `var(--wb-...)` CSS variables, `display:block` label, `box-sizing:border-box` input, inline error region, Cancel + Save buttons. - Added a `keydown` handler at the document level that routes Enter/Escape to `WhiteboardWebframe.submitUrlModal` / `cancelUrlModal` while the modal is visible. - `crates/hero_whiteboard_ui/static/web/js/whiteboard/webframe.js` (+82 / -21) - Replaced `promptUrl(group)`'s body. It now opens the in-page modal (when present) and pre-fills the input with the current URL. - Extracted the post-edit side effects into `applyNewUrl(group, rawUrl)` — handles trim, https:// auto-prepend, state update, label retext (`truncateUrl(newUrl, 50)`), iframe `src`, fallback link `href`, `objStore[id].url`, layer batchDraw, and `WhiteboardSync.onUpdate(group)` to propagate to other windows. - Added `submitUrlModal` (validates the input, shows inline error on empty, calls `applyNewUrl`, closes the modal) and `cancelUrlModal` (just closes), exposed via the module's public surface for the template's `onclick` and keydown handlers. - Kept a fallback to native `prompt(...)` when the modal element isn't rendered (defensive — covers any view that loads `webframe.js` without including the modal markup). ### Why the fix is local to two files The legacy `prompt` was a private helper inside the webframe IIFE with a single internal caller (the dblclick handler at `webframe.js:80-83`). The new module exports + the modal markup live where the user-facing flow happens. No server / SDK / openrpc / DB changes; no other JS module touched. ### Verification - `cargo test --workspace --lib` passes (4 lib targets, 0 tests). - `cargo clippy --workspace -- -D warnings`: clean. - `node --check webframe.js`: parses cleanly. ### Notes / caveats - `applyNewUrl` now explicitly calls `WhiteboardSync.onUpdate(group)`, where the legacy `promptUrl` relied on neighbouring code paths. The early-return when the new URL equals the old URL preserves the legacy no-op behavior so this isn't a redundant sync. - The `\uD83C\uDF10` globe glyph used in the label is preserved verbatim from the original code. - Minimum diff: kept `promptUrl(group)` as the function called from the dblclick handler (`webframe.js:80-83`), so the call site needed no edit. - Manual testing should confirm: dark+light themes, single-window save, two-window sync, Enter/Escape, empty-input inline error.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
lhumina_code/hero_whiteboard#80
No description provided.