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:
parent
f068b1a67c
commit
f6cc33756f
13 changed files with 143 additions and 120 deletions
|
@ -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"
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
|
|
64
src/js/utils/initializeModalDialog.js
Normal file
64
src/js/utils/initializeModalDialog.js
Normal 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;
|
||||
}
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue