1
0
Fork 0
mirror of https://github.com/betaflight/betaflight-configurator.git synced 2025-07-24 16:55:24 +03:00

Replace all 4 instances of jBox-style modal dialog boxes with HTML dialog element

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
This commit is contained in:
David Anson 2025-05-19 05:01:58 +00:00
parent f068b1a67c
commit f6cc33756f
13 changed files with 143 additions and 120 deletions

View file

@ -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"

View file

@ -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:

View file

@ -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);

View file

@ -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);

View file

@ -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

View file

@ -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();

View file

@ -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");

View file

@ -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;

View file

@ -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<HTMLElement>} Dialog title bar.
*/
function getDialogTitleBar(messageId, messageParameters, onClose) {
// HTML structure
const dialogTitleBar = $(`
<div style="display: flex; height: 47px; background: var(--surface-300); border-bottom: 1px solid var(--surface-950);">
<div style="flex: 1; display: flex; align-items: center;">
<div style="padding: 15px;">${i18n.getMessage(messageId, messageParameters || undefined)}</div>
</div>
<div id="dialogclose" style="flex: 0 0 47px; display: flex; align-items: center; justify-content: center; cursor: pointer;">
<svg width="10" height="10" version="1.1" xmlns="http://www.w3.org/2000/svg">
<line x1="0" y1="0" x2="10" y2="10" stroke="var(--surface-950)" stroke-width="2"/>
<line x1="0" y1="10" x2="10" y2="0" stroke="var(--surface-950)" stroke-width="2"/>
</svg>
</div>
</div>
`);
// 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;
}

View file

@ -13,15 +13,17 @@
</div>
<!-- Snippet preview dialog -->
<div id="snippetpreviewcontent" style="display: none">
<dialog closedby="any" id="snippetpreviewdialog" class="html-dialog">
<div id="snippetpreviewcontent" class="html-dialog-content">
<div class="note">
<p i18n="cliConfirmSnippetNote"></p>
</div>
<textarea id="preview" cols="120" rows="20"></textarea>
<textarea id="preview" rows="20"></textarea>
<div class="default_btn">
<a class="confirm" href="#" i18n="cliConfirmSnippetBtn"></a>
</div>
</div>
</dialog>
<dialog class="supportWarningDialog">
<h3 i18n="supportWarningDialogTitle"></h3>

View file

@ -151,7 +151,8 @@
</div>
<!-- Font Manager dialog -->
<div id="fontmanagercontent" style="display:none; width:720px;">
<dialog closedby="any" id="fontmanagerdialog" class="html-dialog" style="width: 750px;">
<div class="html-dialog-content" style="height: 430px; overflow-y: scroll;">
<div class="font-picker" style="margin-bottom: 10px;">
<h1 class="tab_title" i18n="osdSetupFontPresets"></h1>
<!-- Font preview and list -->
@ -167,13 +168,13 @@
</div>
<!-- Boot logo setup -->
<h1 class="tab_title" i18n="osdSetupCustomLogoTitle"></h1>
<div class="grid-row">
<div id="font-logo-preview-container" class="content_wrapper grid-col col6">
<div id="font-logo">
<div id="font-logo-preview-container">
<div id="font-logo-preview">
<!-- this will be resized at runtime -->
</div>
</div>
<div id="font-logo-info grid-col col6">
<div id="font-logo-info">
<h3 i18n="osdSetupCustomLogoInfoTitle"></h3>
<ul>
<li id="font-logo-info-size" i18n="osdSetupCustomLogoInfoImageSize"></li>
@ -183,22 +184,22 @@
</div>
</div>
<!-- Replace logo button -->
<div class="default_btn" style="width:100%; float:left;">
<div class="default_btn">
<a class="replace_logo" i18n="osdSetupCustomLogoOpenImageButton"></a>
</div>
<!-- Upload progress bar -->
<div class="info">
<a name="progressbar"></a>
<progress class="progress" value="0" min="0" max="100"></progress>
<div class="progressLabel" style="margin-top: -21px; width: 95%; text-align: center; position: absolute;"></div>
<div class="progressLabel"></div>
</div>
</div>
<!-- Upload button -->
<div class="default_btn green" style="width:100%; float:left;
">
<div class="default_btn green">
<a class="flash_font active" i18n="osdSetupUploadFont"></a>
</div>
</div>
</dialog>
</div>
</div>

View file

@ -197,7 +197,8 @@
</div>
</div>
<div class="tab-power" id="calibrationmanagercontent">
<dialog closedby="any" id="calibrationmanagerdialog" class="html-dialog">
<div id="calibrationmanagercontent" class="html-dialog-content">
<div class = "note">
<p i18n="powerCalibrationManagerHelp"></p>
</div>
@ -228,8 +229,10 @@
<a class="calibrate" id="calibrate" href="#" i18n="powerCalibrationSave"></a>
</div>
</div>
</dialog>
<div class="tab-power" id="calibrationmanagerconfirmcontent">
<dialog closedby="any" id="calibrationmanagerconfirmdialog" class="html-dialog">
<div id="calibrationmanagerconfirmcontent" class="html-dialog-content">
<div class = "note">
<p i18n="powerCalibrationConfirmHelp"></p>
</div>
@ -257,3 +260,4 @@
<a class="discardcalibration" id="discardcalibration" href="#" i18n="powerCalibrationDiscard"></a>
</div>
</div>
</dialog>

View file

@ -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,