From b110ff3639a0f092ff3d64776f8828792111dda5 Mon Sep 17 00:00:00 2001 From: Mark Haslinghuis Date: Tue, 30 Sep 2025 19:29:45 +0200 Subject: [PATCH 1/2] Fix intermittent invalid state error in loadfile (cli) --- src/js/tabs/cli.js | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/src/js/tabs/cli.js b/src/js/tabs/cli.js index e7f2a8955e..d2f0363ed8 100644 --- a/src/js/tabs/cli.js +++ b/src/js/tabs/cli.js @@ -11,7 +11,6 @@ import $ from "jquery"; import { serial } from "../serial"; import FileSystem from "../FileSystem"; import { ispConnected } from "../utils/connection"; -import { initializeModalDialog } from "../utils/initializeModalDialog"; import { get as getConfig } from "../ConfigStorage"; const cli = { @@ -146,21 +145,37 @@ cli.initialize = function (callback) { function executeSnippet(fileName) { const commands = previewArea.val(); executeCommands(commands); - self.GUI.snippetPreviewWindow.close(); + + // Get the dialog element directly and close it + const snippetDialog = $("#snippetpreviewdialog")[0]; + if (snippetDialog) { + snippetDialog.close(); + } } function previewCommands(result, fileName) { + const snippetDialog = $("#snippetpreviewdialog")[0]; + if (!snippetDialog) { + console.error("Snippet dialog element not found in DOM"); + return; + } + + // Always update the click handler with the current fileName + $("#snippetpreviewcontent a.confirm") + .off("click") + .on("click", () => executeSnippet(fileName)); + + // Mark as initialized after first use if (!self.GUI.snippetPreviewWindow) { - self.GUI.snippetPreviewWindow = initializeModalDialog( - null, - "#snippetpreviewdialog", - "cliConfirmSnippetDialogTitle", - { fileName: fileName }, - ); - $("#snippetpreviewcontent a.confirm").click(() => executeSnippet(fileName)); + self.GUI.snippetPreviewWindow = snippetDialog; } + previewArea.val(result); - self.GUI.snippetPreviewWindow.showModal(); + + // Show the modal directly + if (!snippetDialog.hasAttribute("open")) { + snippetDialog.showModal(); + } } const file = await FileSystem.pickOpenFile(i18n.getMessage("fileSystemPickerFiles", { typeof: "TXT" }), ".txt"); From 5b3b79c525e2cb5d2625a35aefd0f8e209b4119a Mon Sep 17 00:00:00 2001 From: Mark Haslinghuis Date: Wed, 1 Oct 2025 17:17:52 +0200 Subject: [PATCH 2/2] Found the rootcause --- src/js/tabs/cli.js | 37 ++++++++++----------------- src/js/utils/initializeModalDialog.js | 14 ++++++---- 2 files changed, 22 insertions(+), 29 deletions(-) diff --git a/src/js/tabs/cli.js b/src/js/tabs/cli.js index d2f0363ed8..ea6ec1ab7c 100644 --- a/src/js/tabs/cli.js +++ b/src/js/tabs/cli.js @@ -11,6 +11,7 @@ import $ from "jquery"; import { serial } from "../serial"; import FileSystem from "../FileSystem"; import { ispConnected } from "../utils/connection"; +import { initializeModalDialog } from "../utils/initializeModalDialog"; import { get as getConfig } from "../ConfigStorage"; const cli = { @@ -99,6 +100,9 @@ cli.initialize = function (callback) { self.cliBuffer = ""; self.startProcessing = false; + // Reset modal dialog reference since DOM gets rebuilt on tab switch + self.GUI.snippetPreviewWindow = null; + const enterKeyCode = 13; function clearHistory() { @@ -145,37 +149,22 @@ cli.initialize = function (callback) { function executeSnippet(fileName) { const commands = previewArea.val(); executeCommands(commands); - - // Get the dialog element directly and close it - const snippetDialog = $("#snippetpreviewdialog")[0]; - if (snippetDialog) { - snippetDialog.close(); - } + self.GUI.snippetPreviewWindow.close(); } function previewCommands(result, fileName) { - const snippetDialog = $("#snippetpreviewdialog")[0]; - if (!snippetDialog) { - console.error("Snippet dialog element not found in DOM"); - return; - } - - // Always update the click handler with the current fileName - $("#snippetpreviewcontent a.confirm") - .off("click") - .on("click", () => executeSnippet(fileName)); - - // Mark as initialized after first use if (!self.GUI.snippetPreviewWindow) { - self.GUI.snippetPreviewWindow = snippetDialog; + self.GUI.snippetPreviewWindow = initializeModalDialog( + null, + "#snippetpreviewdialog", + "cliConfirmSnippetDialogTitle", + { fileName: fileName }, + ); + $("#snippetpreviewcontent a.confirm").click(() => executeSnippet(fileName)); } previewArea.val(result); - - // Show the modal directly - if (!snippetDialog.hasAttribute("open")) { - snippetDialog.showModal(); - } + self.GUI.snippetPreviewWindow.showModal(); } const file = await FileSystem.pickOpenFile(i18n.getMessage("fileSystemPickerFiles", { typeof: "TXT" }), ".txt"); diff --git a/src/js/utils/initializeModalDialog.js b/src/js/utils/initializeModalDialog.js index d45dbb9e75..bc7a8fb5c8 100644 --- a/src/js/utils/initializeModalDialog.js +++ b/src/js/utils/initializeModalDialog.js @@ -54,11 +54,15 @@ export function initializeModalDialog(activationSelector, dialogSelector, messag onClose && onClose(); }); // Handle activation button click - $(activationSelector).on("click", () => { - dialogElement.showModal(); - // Reset any previous scrolling - dialogContainerElement.scroll(0, 0); - }); + if (activationSelector) { + $(activationSelector).on("click", () => { + dialogElement.showModal(); + // Reset any previous scrolling + if (dialogContainerElement) { + dialogContainerElement.scroll(0, 0); + } + }); + } // Return dialog element return dialogElement; }