From f6cc33756fa7de30cbbc29b7ee20b104d4561c60 Mon Sep 17 00:00:00 2001 From: David Anson Date: Mon, 19 May 2025 05:01:58 +0000 Subject: [PATCH] Replace all 4 instances of jBox-style modal dialog boxes with HTML dialog element MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Notes: - The Power & Battery (2), OSD, and CLI tabs have been updated accordingly - HTML default control behavior was used whereever possible - HTML indent for the dialog tag is deliberately off to minimize diff noise in GitHub - Layout is not 100% identical, but spiratually the same - in most cases no changes were needed - OSD’s Font Manager dialog didn’t transition cleanly, so includes some slight restyling - OSD Font Manager previously had a green background/color for the graphic - that “just works” now - Specific cleanup (i.e., calling destroy()) does not seem necessary and was removed - Removal of jBox from setup.js and global scope seems not to affect jBox tooltips - Replacement of single quotes with double in main.js was done automatically by Prettier --- locales/en/messages.json | 4 ++ src/css/main.less | 7 +++ src/css/tabs/cli.less | 23 +++++----- src/css/tabs/osd.less | 29 +++++------- src/js/main.js | 1 - src/js/tabs/cli.js | 26 ++++------- src/js/tabs/osd.js | 17 ++----- src/js/tabs/power.js | 59 +++++++----------------- src/js/utils/initializeModalDialog.js | 64 +++++++++++++++++++++++++++ src/tabs/cli.html | 6 ++- src/tabs/osd.html | 17 +++---- src/tabs/power.html | 8 +++- test/setup.js | 2 - 13 files changed, 143 insertions(+), 120 deletions(-) create mode 100644 src/js/utils/initializeModalDialog.js diff --git a/locales/en/messages.json b/locales/en/messages.json index 74fe055a..f34d1d6d 100755 --- a/locales/en/messages.json +++ b/locales/en/messages.json @@ -5320,6 +5320,10 @@ "message": "Font", "description": "Content of the selector for the OSD Font in the preview" }, + "osdSetupFontManagerTitle": { + "message": "OSD Font Manager", + "description": "Dialog title" + }, "osdSetupFontTypeDefault": { "message": "Default", "description": "Font Default" diff --git a/src/css/main.less b/src/css/main.less index 866c76e4..791d48b9 100644 --- a/src/css/main.less +++ b/src/css/main.less @@ -41,6 +41,13 @@ a.disabled { cursor: default; color: #999; } +.html-dialog { + border-color: var(--primary-500); + padding: 0px; +} +.html-dialog-content { + padding: 15px 15px; +} .background_paper { background-color: var(--surface-200); background-image: diff --git a/src/css/tabs/cli.less b/src/css/tabs/cli.less index 413177f4..0f6ecafe 100644 --- a/src/css/tabs/cli.less +++ b/src/css/tabs/cli.less @@ -75,18 +75,17 @@ color: white; } } -.jBox-container { - textarea#preview { - background-color: rgba(0, 0, 0, 0.75); - width: 100%; - resize: none; - overflow-y: scroll; - overflow-x: hidden; - font-family: monospace; - color: white; - padding: 5px; - margin-bottom: 5px; - } +textarea#preview { + background-color: rgba(0, 0, 0, 0.75); + width: 100%; + resize: none; + overflow-y: scroll; + overflow-x: hidden; + font-family: monospace; + color: white; + box-sizing: border-box; + padding: 5px; + margin-bottom: 5px; } .cli-textcomplete-dropdown { border: 1px solid var(--surface-500); diff --git a/src/css/tabs/osd.less b/src/css/tabs/osd.less index 067bc64b..3845833e 100644 --- a/src/css/tabs/osd.less +++ b/src/css/tabs/osd.less @@ -2,17 +2,14 @@ --context-menu-z-index: 10001; .info { - margin: 10px 0 0 0; position: relative; width: 100%; .progressLabel { position: absolute; width: 100%; height: 26px; - top: 0; - left: 0; + margin-top: -22px; text-align: center; - line-height: 24px; color: white; font-weight: bold; a { @@ -68,12 +65,6 @@ width: 18px; height: 18px; } - ul { - li { - list-style: circle; - margin-left: 30px; - } - } .options { position: relative; margin-bottom: 10px; @@ -382,13 +373,14 @@ font-weight: normal; } } - .grid-col { - margin: 0px; + #font-logo { + display: flex; + margin-bottom: 2em; } #font-logo-preview-container { background: rgba(0, 255, 0, 0.4); margin-bottom: 10px; - box-sizing: border-box; + padding: 10px; } #font-logo-preview { background: rgba(0, 255, 0, 1); @@ -396,7 +388,8 @@ margin: auto; } #font-logo-info { - font-size: 125%; + flex: 1; + margin-left: 2em; line-height: 150%; h3 { margin-bottom: 0.2em; @@ -431,11 +424,11 @@ font-size: 9pt !important; cursor: pointer; } + .font-preview { + padding-bottom: 1.25rem; + } .fontpresets_wrapper { - display: inline-block; - position: absolute; - right: 1.2em; - top: 0.8em; + padding: 1rem 0; } .fontpresets { background: var(--surface-200); diff --git a/src/js/main.js b/src/js/main.js index ca34a4db..7ef8d245 100644 --- a/src/js/main.js +++ b/src/js/main.js @@ -1,6 +1,5 @@ import "./jqueryPlugins"; import $ from "jquery"; -import "jbox"; import "../components/init.js"; import { gui_log } from "./gui_log.js"; // same, msp seems to be everywhere used from global scope diff --git a/src/js/tabs/cli.js b/src/js/tabs/cli.js index a0252786..778b3b4f 100644 --- a/src/js/tabs/cli.js +++ b/src/js/tabs/cli.js @@ -8,11 +8,11 @@ import { reinitializeConnection } from "../serial_backend"; import CONFIGURATOR from "../data_storage"; import CliAutoComplete from "../CliAutoComplete"; import { gui_log } from "../gui_log"; -import jBox from "jbox"; import $ from "jquery"; import { serial } from "../serial"; import FileSystem from "../FileSystem"; import { ispConnected } from "../utils/connection"; +import { initializeModalDialog } from "../utils/initializeModalDialog"; const cli = { lineDelayMs: 5, @@ -151,20 +151,16 @@ cli.initialize = function (callback) { function previewCommands(result, fileName) { if (!self.GUI.snippetPreviewWindow) { - self.GUI.snippetPreviewWindow = new jBox("Modal", { - id: "snippetPreviewWindow", - width: "auto", - height: "auto", - closeButton: "title", - animation: false, - isolateScroll: false, - title: i18n.getMessage("cliConfirmSnippetDialogTitle", { fileName: fileName }), - content: $("#snippetpreviewcontent"), - onCreated: () => $("#snippetpreviewcontent a.confirm").click(() => executeSnippet(fileName)), - }); + self.GUI.snippetPreviewWindow = initializeModalDialog( + null, + "#snippetpreviewdialog", + "cliConfirmSnippetDialogTitle", + { fileName: fileName }, + ); + $("#snippetpreviewcontent a.confirm").click(() => executeSnippet(fileName)); } previewArea.val(result); - self.GUI.snippetPreviewWindow.open(); + self.GUI.snippetPreviewWindow.showModal(); } const file = await FileSystem.pickOpenFile(i18n.getMessage("fileSystemPickerFiles", { typeof: "TXT" }), ".txt"); @@ -530,10 +526,6 @@ cli.supportWarningDialog = function (onAccept) { }; cli.cleanup = function (callback) { - if (TABS.cli.GUI.snippetPreviewWindow) { - TABS.cli.GUI.snippetPreviewWindow.destroy(); - TABS.cli.GUI.snippetPreviewWindow = null; - } if (!(CONFIGURATOR.connectionValid && CONFIGURATOR.cliValid && CONFIGURATOR.cliActive)) { if (callback) { callback(); diff --git a/src/js/tabs/osd.js b/src/js/tabs/osd.js index 90d9d823..02550cd8 100644 --- a/src/js/tabs/osd.js +++ b/src/js/tabs/osd.js @@ -16,6 +16,7 @@ import debounce from "lodash.debounce"; import $ from "jquery"; import FileSystem from "../FileSystem"; import { have_sensor } from "../sensor_helpers"; +import { initializeModalDialog } from "../utils/initializeModalDialog"; const FONT = {}; const SYM = {}; @@ -3254,16 +3255,8 @@ osd.initialize = function (callback) { $(".display-layout .preview").css("zoom", previewZoom); } - // Open modal window - OSD.GUI.fontManager = new jBox("Modal", { - width: 750, - height: 455, - closeButton: "title", - animation: false, - attach: $("#fontmanager"), - title: "OSD Font Manager", - content: $("#fontmanagercontent"), - }); + // Enable font manager dialog + OSD.GUI.fontManager = initializeModalDialog("#fontmanager", "#fontmanagerdialog", "osdSetupFontManagerTitle"); $(".elements-container div.cf_tip").attr("title", i18n.getMessage("osdSectionHelpElements")); $(".videomode-container div.cf_tip").attr("title", i18n.getMessage("osdSectionHelpVideoMode")); @@ -4093,10 +4086,6 @@ osd.initialize = function (callback) { }; osd.cleanup = function (callback) { - if (OSD.GUI.fontManager) { - OSD.GUI.fontManager.destroy(); - } - // unbind "global" events $(document).unbind("keypress"); $(document).off("click", "span.progressLabel a"); diff --git a/src/js/tabs/power.js b/src/js/tabs/power.js index bde52346..aea823fc 100644 --- a/src/js/tabs/power.js +++ b/src/js/tabs/power.js @@ -5,8 +5,8 @@ import { mspHelper } from "../msp/MSPHelper"; import FC from "../fc"; import MSP from "../msp"; import MSPCodes from "../msp/MSPCodes"; -import jBox from "jbox"; import $ from "jquery"; +import { initializeModalDialog } from "../utils/initializeModalDialog"; const power = { supported: false, @@ -20,13 +20,6 @@ power.initialize = function (callback) { GUI.active_tab = "power"; } - if (GUI.calibrationManager) { - GUI.calibrationManager.destroy(); - } - if (GUI.calibrationManagerConfirmation) { - GUI.calibrationManagerConfirmation.destroy(); - } - function load_status() { MSP.send_message(MSPCodes.MSP_STATUS, false, false, load_voltage_meters); } @@ -223,9 +216,6 @@ power.initialize = function (callback) { } $(".tab-power").addClass("supported"); - $("#calibrationmanagercontent").hide(); - $("#calibrationmanagerconfirmcontent").hide(); - // battery const templateBatteryState = $("#tab-power-templates .battery-state .battery-state"); const destinationBatteryState = $(".tab-power .battery-state"); @@ -347,33 +337,21 @@ power.initialize = function (callback) { //calibration manager let calibrationconfirmed = false; - GUI.calibrationManager = new jBox("Modal", { - width: 400, - height: 230, - closeButton: "title", - animation: false, - attach: $("#calibrationmanager"), - title: i18n.getMessage("powerCalibrationManagerTitle"), - content: $("#calibrationmanagercontent"), - onCloseComplete: function () { - if (!calibrationconfirmed) { - TABS.power.initialize(); - } - }, - }); + GUI.calibrationManager = initializeModalDialog( + "#calibrationmanager", + "#calibrationmanagerdialog", + "powerCalibrationManagerTitle", + null, + () => calibrationconfirmed || TABS.power.initialize(), + ); - GUI.calibrationManagerConfirmation = new jBox("Modal", { - width: 400, - height: 230, - closeButton: "title", - animation: false, - attach: $("#calibrate"), - title: i18n.getMessage("powerCalibrationManagerConfirmationTitle"), - content: $("#calibrationmanagerconfirmcontent"), - onCloseComplete: function () { - GUI.calibrationManager.close(); - }, - }); + GUI.calibrationManagerConfirmation = initializeModalDialog( + "#calibrate", + "#calibrationmanagerconfirmdialog", + "powerCalibrationManagerConfirmationTitle", + null, + () => GUI.calibrationManager.close(), + ); $("a.calibrationmanager").click(function () { if (FC.BATTERY_CONFIG.voltageMeterSource == 1 && FC.BATTERY_STATE.voltage > 0.1) { @@ -564,13 +542,6 @@ power.initialize = function (callback) { power.cleanup = function (callback) { if (callback) callback(); - - if (GUI.calibrationManager) { - GUI.calibrationManager.destroy(); - } - if (GUI.calibrationManagerConfirmation) { - GUI.calibrationManagerConfirmation.destroy(); - } }; TABS.power = power; diff --git a/src/js/utils/initializeModalDialog.js b/src/js/utils/initializeModalDialog.js new file mode 100644 index 00000000..d45dbb9e --- /dev/null +++ b/src/js/utils/initializeModalDialog.js @@ -0,0 +1,64 @@ +import $ from "jquery"; +import { i18n } from "../localization"; + +/** + * Gets the title bar for a modal dialog. + * @param {string} messageId Localized message identifier. + * @param {object} [messageParameters] Localized message parameters + * @param {() => void} onClose Function invoked by the close button. + * @returns {JQuery} Dialog title bar. + */ +function getDialogTitleBar(messageId, messageParameters, onClose) { + // HTML structure + const dialogTitleBar = $(` +
+
+
${i18n.getMessage(messageId, messageParameters || undefined)}
+
+
+ + + + +
+
+ `); + // Handle close button + dialogTitleBar.find("#dialogclose").on("click", onClose); + // Return title bar + return dialogTitleBar; +} + +/** + * Initializes a modal dialog from an HTML dialog element. + * @param {JQuery.Selector|null} activationSelector JQuery selector for the activation element. + * @param {JQuery.Selector} dialogSelector JQuery selector for the dialog element. + * @param {string} messageId Localized message identifier. + * @param {object} [messageParameters] Localized message parameters + * @param {() => void} [onClose] Function invoked when the dialog is closed. + * @returns {HTMLDialogElement} HTML dialog element. + */ +export function initializeModalDialog(activationSelector, dialogSelector, messageId, messageParameters, onClose) { + // Get dialog references + const dialog = $(dialogSelector); + const dialogElement = dialog.get(0); + const dialogContainerElement = dialog.children().first().get(0); + // Add dialog title bar + dialog.prepend( + getDialogTitleBar(messageId, messageParameters, () => { + dialogElement.close(); + }), + ); + // Handle close event + dialogElement.addEventListener("close", () => { + onClose && onClose(); + }); + // Handle activation button click + $(activationSelector).on("click", () => { + dialogElement.showModal(); + // Reset any previous scrolling + dialogContainerElement.scroll(0, 0); + }); + // Return dialog element + return dialogElement; +} diff --git a/src/tabs/cli.html b/src/tabs/cli.html index 03e0d01b..14e52117 100644 --- a/src/tabs/cli.html +++ b/src/tabs/cli.html @@ -13,15 +13,17 @@ - - diff --git a/src/tabs/power.html b/src/tabs/power.html index 3b8b6859..990f75a7 100644 --- a/src/tabs/power.html +++ b/src/tabs/power.html @@ -197,7 +197,8 @@ -
+ +

@@ -228,8 +229,10 @@
+ -
+ +

@@ -257,3 +260,4 @@
+ diff --git a/test/setup.js b/test/setup.js index a6ee77dc..849eab88 100644 --- a/test/setup.js +++ b/test/setup.js @@ -1,14 +1,12 @@ import { JSDOM } from "jsdom"; import $ from "jquery"; import { vi } from "vitest"; -import jBox from "jbox"; // Note: this can go away once jquery is used as module everywhere const { window } = new JSDOM(""); $(window); globalThis.$ = $; globalThis.jQuery = $; -globalThis.jBox = jBox; Object.defineProperty(window, "matchMedia", { writable: true,