|
@@ -1,11 +1,10 @@
|
|
-import { compress, decompress, debounce, isScrollable } from "@sv443-network/userutils";
|
|
|
|
-import { defaultData, getFeatures, migrations, setFeatures, setDefaultFeatures } from "../config";
|
|
|
|
-import { buildNumber, compressionFormat, host, mode, scriptInfo } from "../constants";
|
|
|
|
|
|
+import { debounce, isScrollable } from "@sv443-network/userutils";
|
|
|
|
+import { defaultData, getFeatures, setFeatures, setDefaultFeatures } from "../config";
|
|
|
|
+import { buildNumber, host, mode, scriptInfo } from "../constants";
|
|
import { featInfo, disableBeforeUnload } from "../features/index";
|
|
import { featInfo, disableBeforeUnload } from "../features/index";
|
|
-import { error, getResourceUrl, info, log, resourceToHTMLString, warn, getLocale, hasKey, initTranslations, setLocale, t, compressionSupported, arrayWithSeparators, tp, type TrKey, onInteraction } from "../utils";
|
|
|
|
-import { formatVersion } from "../config";
|
|
|
|
-import { emitSiteEvent, siteEvents } from "../siteEvents";
|
|
|
|
-import { getChangelogDialog, getFeatHelpDialog } from "../dialogs";
|
|
|
|
|
|
+import { error, getResourceUrl, info, log, resourceToHTMLString, getLocale, hasKey, initTranslations, setLocale, t, arrayWithSeparators, tp, type TrKey, onInteraction } from "../utils";
|
|
|
|
+import { siteEvents } from "../siteEvents";
|
|
|
|
+import { getChangelogDialog, getExportDialog, getFeatHelpDialog, getImportDialog } from "../dialogs";
|
|
import type { FeatureCategory, FeatureKey, FeatureConfig, HotkeyObj, FeatureInfo } from "../types";
|
|
import type { FeatureCategory, FeatureKey, FeatureConfig, HotkeyObj, FeatureInfo } from "../types";
|
|
import "./menu_old.css";
|
|
import "./menu_old.css";
|
|
import { createHotkeyInput, createToggleInput } from "../components";
|
|
import { createHotkeyInput, createToggleInput } from "../components";
|
|
@@ -188,16 +187,22 @@ async function addCfgMenu() {
|
|
exportElem.ariaLabel = exportElem.title = t("export_tooltip");
|
|
exportElem.ariaLabel = exportElem.title = t("export_tooltip");
|
|
exportElem.textContent = t("export");
|
|
exportElem.textContent = t("export");
|
|
exportElem.addEventListener("click", async () => {
|
|
exportElem.addEventListener("click", async () => {
|
|
- await openExportMenu();
|
|
|
|
|
|
+ const dlg = await getExportDialog();
|
|
|
|
+ dlg.on("close", openCfgMenu);
|
|
|
|
+ await dlg.mount();
|
|
closeCfgMenu(undefined, false);
|
|
closeCfgMenu(undefined, false);
|
|
|
|
+ await dlg.open();
|
|
});
|
|
});
|
|
const importElem = document.createElement("button");
|
|
const importElem = document.createElement("button");
|
|
importElem.classList.add("bytm-btn");
|
|
importElem.classList.add("bytm-btn");
|
|
importElem.ariaLabel = importElem.title = t("import_tooltip");
|
|
importElem.ariaLabel = importElem.title = t("import_tooltip");
|
|
importElem.textContent = t("import");
|
|
importElem.textContent = t("import");
|
|
importElem.addEventListener("click", async () => {
|
|
importElem.addEventListener("click", async () => {
|
|
- await openImportMenu();
|
|
|
|
|
|
+ const dlg = await getImportDialog();
|
|
|
|
+ dlg.on("close", openCfgMenu);
|
|
|
|
+ await dlg.mount();
|
|
closeCfgMenu(undefined, false);
|
|
closeCfgMenu(undefined, false);
|
|
|
|
+ await dlg.open();
|
|
});
|
|
});
|
|
|
|
|
|
const buttonsCont = document.createElement("div");
|
|
const buttonsCont = document.createElement("div");
|
|
@@ -797,411 +802,3 @@ function checkToggleScrollIndicator() {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
-
|
|
|
|
-//#MARKER export menu
|
|
|
|
-
|
|
|
|
-let isExportMenuAdded = false;
|
|
|
|
-let isExportMenuOpen = false;
|
|
|
|
-let copiedTxtTimeout: number | undefined = undefined;
|
|
|
|
-let lastUncompressedCfgString: string | undefined;
|
|
|
|
-
|
|
|
|
-/** Adds a menu to copy the current configuration as compressed (if supported) or uncompressed JSON (hidden by default) */
|
|
|
|
-async function addExportMenu() {
|
|
|
|
- const canCompress = await compressionSupported();
|
|
|
|
-
|
|
|
|
- const menuBgElem = document.createElement("div");
|
|
|
|
- menuBgElem.id = "bytm-export-menu-bg";
|
|
|
|
- menuBgElem.classList.add("bytm-menu-bg");
|
|
|
|
- menuBgElem.ariaLabel = menuBgElem.title = t("close_menu_tooltip");
|
|
|
|
- menuBgElem.style.visibility = "hidden";
|
|
|
|
- menuBgElem.style.display = "none";
|
|
|
|
- menuBgElem.addEventListener("click", (e) => {
|
|
|
|
- if(isExportMenuOpen && (e.target as HTMLElement)?.id === "bytm-export-menu-bg") {
|
|
|
|
- closeExportMenu(e);
|
|
|
|
- openCfgMenu();
|
|
|
|
- }
|
|
|
|
- });
|
|
|
|
- document.body.addEventListener("keydown", (e) => {
|
|
|
|
- if(isExportMenuOpen && e.key === "Escape") {
|
|
|
|
- closeExportMenu(e);
|
|
|
|
- openCfgMenu();
|
|
|
|
- }
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
- const menuContainer = document.createElement("div");
|
|
|
|
- menuContainer.ariaLabel = menuContainer.title = ""; // prevent bg title from propagating downwards
|
|
|
|
- menuContainer.classList.add("bytm-menu");
|
|
|
|
- menuContainer.id = "bytm-export-menu";
|
|
|
|
-
|
|
|
|
- //#SECTION title bar
|
|
|
|
- const headerElem = document.createElement("div");
|
|
|
|
- headerElem.classList.add("bytm-menu-header");
|
|
|
|
-
|
|
|
|
- const titleCont = document.createElement("div");
|
|
|
|
- titleCont.className = "bytm-menu-titlecont";
|
|
|
|
- titleCont.role = "heading";
|
|
|
|
- titleCont.ariaLevel = "1";
|
|
|
|
-
|
|
|
|
- const titleElem = document.createElement("h2");
|
|
|
|
- titleElem.className = "bytm-menu-title";
|
|
|
|
- titleElem.textContent = t("export_menu_title", scriptInfo.name);
|
|
|
|
-
|
|
|
|
- const closeElem = document.createElement("img");
|
|
|
|
- closeElem.classList.add("bytm-menu-close");
|
|
|
|
- closeElem.role = "button";
|
|
|
|
- closeElem.tabIndex = 0;
|
|
|
|
- closeElem.src = await getResourceUrl("img-close");
|
|
|
|
- closeElem.ariaLabel = closeElem.title = t("close_menu_tooltip");
|
|
|
|
- onInteraction(closeElem, (e: MouseEvent | KeyboardEvent) => {
|
|
|
|
- closeExportMenu(e);
|
|
|
|
- openCfgMenu();
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
- titleCont.appendChild(titleElem);
|
|
|
|
-
|
|
|
|
- headerElem.appendChild(titleCont);
|
|
|
|
- headerElem.appendChild(closeElem);
|
|
|
|
-
|
|
|
|
- //#SECTION body
|
|
|
|
-
|
|
|
|
- const menuBodyElem = document.createElement("div");
|
|
|
|
- menuBodyElem.classList.add("bytm-menu-body");
|
|
|
|
-
|
|
|
|
- const textElem = document.createElement("div");
|
|
|
|
- textElem.id = "bytm-export-menu-text";
|
|
|
|
- textElem.textContent = t("export_hint");
|
|
|
|
-
|
|
|
|
- const textAreaElem = document.createElement("textarea");
|
|
|
|
- textAreaElem.id = "bytm-export-menu-textarea";
|
|
|
|
- textAreaElem.readOnly = true;
|
|
|
|
- lastUncompressedCfgString = JSON.stringify({ formatVersion, data: getFeatures() }, undefined, 2);
|
|
|
|
- textAreaElem.value = t("click_to_reveal_sensitive_info");
|
|
|
|
- textAreaElem.setAttribute("revealed", "false");
|
|
|
|
-
|
|
|
|
- const textAreaInteraction = async () => {
|
|
|
|
- const cfgString = JSON.stringify({ formatVersion, data: getFeatures() });
|
|
|
|
- lastUncompressedCfgString = JSON.stringify({ formatVersion, data: getFeatures() }, undefined, 2);
|
|
|
|
- textAreaElem.value = canCompress ? await compress(cfgString, compressionFormat, "string") : cfgString;
|
|
|
|
- textAreaElem.setAttribute("revealed", "true");
|
|
|
|
- };
|
|
|
|
-
|
|
|
|
- onInteraction(textAreaElem, textAreaInteraction);
|
|
|
|
-
|
|
|
|
- siteEvents.on("configChanged", async (data) => {
|
|
|
|
- const textAreaElem = document.querySelector<HTMLTextAreaElement>("#bytm-export-menu-textarea");
|
|
|
|
- const cfgString = JSON.stringify({ formatVersion, data });
|
|
|
|
- lastUncompressedCfgString = JSON.stringify({ formatVersion, data }, undefined, 2);
|
|
|
|
- if(textAreaElem) {
|
|
|
|
- if(textAreaElem.getAttribute("revealed") !== "true")
|
|
|
|
- return;
|
|
|
|
- textAreaElem.value = canCompress ? await compress(cfgString, compressionFormat, "string") : cfgString;
|
|
|
|
- }
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
- //#SECTION footer
|
|
|
|
- const footerElem = document.createElement("div");
|
|
|
|
- footerElem.classList.add("bytm-menu-footer-right");
|
|
|
|
-
|
|
|
|
- const copyBtnElem = document.createElement("button");
|
|
|
|
- copyBtnElem.classList.add("bytm-btn");
|
|
|
|
- copyBtnElem.textContent = t("copy_to_clipboard");
|
|
|
|
- copyBtnElem.ariaLabel = copyBtnElem.title = t("copy_config_tooltip");
|
|
|
|
-
|
|
|
|
- const copiedTextElem = document.createElement("span");
|
|
|
|
- copiedTextElem.id = "bytm-export-menu-copied-txt";
|
|
|
|
- copiedTextElem.role = "status";
|
|
|
|
- copiedTextElem.classList.add("bytm-menu-footer-copied");
|
|
|
|
- copiedTextElem.textContent = t("copied");
|
|
|
|
- copiedTextElem.style.display = "none";
|
|
|
|
-
|
|
|
|
- onInteraction(copyBtnElem, async (evt: MouseEvent | KeyboardEvent) => {
|
|
|
|
- evt?.bubbles && evt.stopPropagation();
|
|
|
|
- GM.setClipboard(String(evt?.shiftKey || evt?.ctrlKey ? lastUncompressedCfgString : await compress(JSON.stringify({ formatVersion, data: getFeatures() }), compressionFormat, "string")));
|
|
|
|
- copiedTextElem.style.display = "inline-block";
|
|
|
|
- if(typeof copiedTxtTimeout === "undefined") {
|
|
|
|
- copiedTxtTimeout = setTimeout(() => {
|
|
|
|
- copiedTextElem.style.display = "none";
|
|
|
|
- copiedTxtTimeout = undefined;
|
|
|
|
- }, 3000) as unknown as number;
|
|
|
|
- }
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
- // flex-direction is row-reverse
|
|
|
|
- footerElem.appendChild(copyBtnElem);
|
|
|
|
- footerElem.appendChild(copiedTextElem);
|
|
|
|
-
|
|
|
|
- //#SECTION finalize
|
|
|
|
-
|
|
|
|
- menuBodyElem.appendChild(textElem);
|
|
|
|
- menuBodyElem.appendChild(textAreaElem);
|
|
|
|
- menuBodyElem.appendChild(footerElem);
|
|
|
|
-
|
|
|
|
- menuContainer.appendChild(headerElem);
|
|
|
|
- menuContainer.appendChild(menuBodyElem);
|
|
|
|
-
|
|
|
|
- menuBgElem.appendChild(menuContainer);
|
|
|
|
-
|
|
|
|
- document.body.appendChild(menuBgElem);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/** Closes the export menu if it is open. If a bubbling event is passed, its propagation will be prevented. */
|
|
|
|
-function closeExportMenu(evt: MouseEvent | KeyboardEvent) {
|
|
|
|
- if(!isExportMenuOpen)
|
|
|
|
- return;
|
|
|
|
- isExportMenuOpen = false;
|
|
|
|
- evt?.bubbles && evt.stopPropagation();
|
|
|
|
-
|
|
|
|
- const menuBg = document.querySelector<HTMLElement>("#bytm-export-menu-bg");
|
|
|
|
-
|
|
|
|
- if(!menuBg)
|
|
|
|
- return warn("Couldn't find export menu background element");
|
|
|
|
-
|
|
|
|
- menuBg.style.visibility = "hidden";
|
|
|
|
- menuBg.style.display = "none";
|
|
|
|
-
|
|
|
|
- const textAreaElem = menuBg.querySelector<HTMLTextAreaElement>("#bytm-export-menu-textarea");
|
|
|
|
- if(textAreaElem) {
|
|
|
|
- textAreaElem.value = t("click_to_reveal_sensitive_info");
|
|
|
|
- textAreaElem.setAttribute("revealed", "false");
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- const copiedTxtElem = document.querySelector<HTMLElement>("#bytm-export-menu-copied-txt");
|
|
|
|
- if(copiedTxtElem) {
|
|
|
|
- copiedTxtElem.style.display = "none";
|
|
|
|
- if(typeof copiedTxtTimeout === "number") {
|
|
|
|
- clearTimeout(copiedTxtTimeout);
|
|
|
|
- copiedTxtTimeout = undefined;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/** Opens the export menu if it is closed */
|
|
|
|
-async function openExportMenu() {
|
|
|
|
- if(!isExportMenuAdded)
|
|
|
|
- await addExportMenu();
|
|
|
|
- isExportMenuAdded = true;
|
|
|
|
-
|
|
|
|
- if(isExportMenuOpen)
|
|
|
|
- return;
|
|
|
|
- isExportMenuOpen = true;
|
|
|
|
-
|
|
|
|
- document.body.classList.add("bytm-disable-scroll");
|
|
|
|
- document.querySelector("ytmusic-app")?.setAttribute("inert", "true");
|
|
|
|
- const menuBg = document.querySelector<HTMLElement>("#bytm-export-menu-bg");
|
|
|
|
-
|
|
|
|
- if(!menuBg)
|
|
|
|
- return warn("Couldn't find export menu background element");
|
|
|
|
-
|
|
|
|
- menuBg.style.visibility = "visible";
|
|
|
|
- menuBg.style.display = "block";
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-//#MARKER import menu
|
|
|
|
-
|
|
|
|
-let isImportMenuAdded = false;
|
|
|
|
-let isImportMenuOpen = false;
|
|
|
|
-
|
|
|
|
-/** Adds a menu to import a configuration from compressed or uncompressed JSON (hidden by default) */
|
|
|
|
-async function addImportMenu() {
|
|
|
|
- const menuBgElem = document.createElement("div");
|
|
|
|
- menuBgElem.id = "bytm-import-menu-bg";
|
|
|
|
- menuBgElem.classList.add("bytm-menu-bg");
|
|
|
|
- menuBgElem.ariaLabel = menuBgElem.title = t("close_menu_tooltip");
|
|
|
|
- menuBgElem.style.visibility = "hidden";
|
|
|
|
- menuBgElem.style.display = "none";
|
|
|
|
- menuBgElem.addEventListener("click", (e) => {
|
|
|
|
- if(isImportMenuOpen && (e.target as HTMLElement)?.id === "bytm-import-menu-bg") {
|
|
|
|
- closeImportMenu(e);
|
|
|
|
- openCfgMenu();
|
|
|
|
- }
|
|
|
|
- });
|
|
|
|
- document.body.addEventListener("keydown", (e) => {
|
|
|
|
- if(isImportMenuOpen && e.key === "Escape") {
|
|
|
|
- closeImportMenu(e);
|
|
|
|
- openCfgMenu();
|
|
|
|
- }
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
- const menuContainer = document.createElement("div");
|
|
|
|
- menuContainer.ariaLabel = menuContainer.title = ""; // prevent bg title from propagating downwards
|
|
|
|
- menuContainer.classList.add("bytm-menu");
|
|
|
|
- menuContainer.id = "bytm-import-menu";
|
|
|
|
-
|
|
|
|
- //#SECTION title bar
|
|
|
|
- const headerElem = document.createElement("div");
|
|
|
|
- headerElem.classList.add("bytm-menu-header");
|
|
|
|
-
|
|
|
|
- const titleCont = document.createElement("div");
|
|
|
|
- titleCont.className = "bytm-menu-titlecont";
|
|
|
|
- titleCont.role = "heading";
|
|
|
|
- titleCont.ariaLevel = "1";
|
|
|
|
-
|
|
|
|
- const titleElem = document.createElement("h2");
|
|
|
|
- titleElem.className = "bytm-menu-title";
|
|
|
|
- titleElem.textContent = t("import_menu_title", scriptInfo.name);
|
|
|
|
-
|
|
|
|
- const closeElem = document.createElement("img");
|
|
|
|
- closeElem.classList.add("bytm-menu-close");
|
|
|
|
- closeElem.role = "button";
|
|
|
|
- closeElem.tabIndex = 0;
|
|
|
|
- closeElem.src = await getResourceUrl("img-close");
|
|
|
|
- closeElem.ariaLabel = closeElem.title = t("close_menu_tooltip");
|
|
|
|
- onInteraction(closeElem, (e: MouseEvent | KeyboardEvent) => {
|
|
|
|
- closeImportMenu(e);
|
|
|
|
- openCfgMenu();
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
- titleCont.appendChild(titleElem);
|
|
|
|
-
|
|
|
|
- headerElem.appendChild(titleCont);
|
|
|
|
- headerElem.appendChild(closeElem);
|
|
|
|
-
|
|
|
|
- //#SECTION body
|
|
|
|
-
|
|
|
|
- const menuBodyElem = document.createElement("div");
|
|
|
|
- menuBodyElem.classList.add("bytm-menu-body");
|
|
|
|
-
|
|
|
|
- const textElem = document.createElement("div");
|
|
|
|
- textElem.id = "bytm-import-menu-text";
|
|
|
|
- textElem.textContent = t("import_hint");
|
|
|
|
-
|
|
|
|
- const textAreaElem = document.createElement("textarea");
|
|
|
|
- textAreaElem.id = "bytm-import-menu-textarea";
|
|
|
|
-
|
|
|
|
- //#SECTION footer
|
|
|
|
- const footerElem = document.createElement("div");
|
|
|
|
- footerElem.classList.add("bytm-menu-footer-right");
|
|
|
|
-
|
|
|
|
- const importBtnElem = document.createElement("button");
|
|
|
|
- importBtnElem.classList.add("bytm-btn");
|
|
|
|
- importBtnElem.textContent = t("import");
|
|
|
|
- importBtnElem.ariaLabel = importBtnElem.title = t("start_import_tooltip");
|
|
|
|
-
|
|
|
|
- importBtnElem.addEventListener("click", async (evt) => {
|
|
|
|
- evt?.bubbles && evt.stopPropagation();
|
|
|
|
- const textAreaElem = document.querySelector<HTMLTextAreaElement>("#bytm-import-menu-textarea");
|
|
|
|
- if(!textAreaElem)
|
|
|
|
- return warn("Couldn't find import menu textarea element");
|
|
|
|
- try {
|
|
|
|
- /** Tries to parse an uncompressed or compressed input string as a JSON object */
|
|
|
|
- const decode = async (input: string) => {
|
|
|
|
- try {
|
|
|
|
- return JSON.parse(input);
|
|
|
|
- }
|
|
|
|
- catch {
|
|
|
|
- try {
|
|
|
|
- return JSON.parse(await decompress(input, compressionFormat, "string"));
|
|
|
|
- }
|
|
|
|
- catch(err) {
|
|
|
|
- warn("Couldn't import configuration:", err);
|
|
|
|
- return null;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- };
|
|
|
|
- const parsed = await decode(textAreaElem.value.trim());
|
|
|
|
- if(typeof parsed !== "object")
|
|
|
|
- return alert(t("import_error_invalid"));
|
|
|
|
- if(typeof parsed.formatVersion !== "number")
|
|
|
|
- return alert(t("import_error_no_format_version"));
|
|
|
|
- if(typeof parsed.data !== "object" || parsed.data === null || Object.keys(parsed.data).length === 0)
|
|
|
|
- return alert(t("import_error_no_data"));
|
|
|
|
- if(parsed.formatVersion < formatVersion) {
|
|
|
|
- let newData = JSON.parse(JSON.stringify(parsed.data));
|
|
|
|
- const sortedMigrations = Object.entries(migrations)
|
|
|
|
- .sort(([a], [b]) => Number(a) - Number(b));
|
|
|
|
-
|
|
|
|
- let curFmtVer = Number(parsed.formatVersion);
|
|
|
|
-
|
|
|
|
- for(const [fmtVer, migrationFunc] of sortedMigrations) {
|
|
|
|
- const ver = Number(fmtVer);
|
|
|
|
- if(curFmtVer < formatVersion && curFmtVer < ver) {
|
|
|
|
- try {
|
|
|
|
- const migRes = JSON.parse(JSON.stringify(migrationFunc(newData)));
|
|
|
|
- newData = migRes instanceof Promise ? await migRes : migRes;
|
|
|
|
- curFmtVer = ver;
|
|
|
|
- }
|
|
|
|
- catch(err) {
|
|
|
|
- error(`Error while running migration function for format version ${fmtVer}:`, err);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- parsed.formatVersion = curFmtVer;
|
|
|
|
- parsed.data = newData;
|
|
|
|
- }
|
|
|
|
- else if(parsed.formatVersion !== formatVersion)
|
|
|
|
- return alert(t("import_error_wrong_format_version", formatVersion, parsed.formatVersion));
|
|
|
|
-
|
|
|
|
- await setFeatures({ ...getFeatures(), ...parsed.data });
|
|
|
|
-
|
|
|
|
- if(confirm(t("import_success_confirm_reload"))) {
|
|
|
|
- disableBeforeUnload();
|
|
|
|
- return location.reload();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- emitSiteEvent("rebuildCfgMenu", parsed.data);
|
|
|
|
-
|
|
|
|
- closeImportMenu();
|
|
|
|
- openCfgMenu();
|
|
|
|
- }
|
|
|
|
- catch(err) {
|
|
|
|
- warn("Couldn't import configuration:", err);
|
|
|
|
- alert(t("import_error_invalid"));
|
|
|
|
- }
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
- footerElem.appendChild(importBtnElem);
|
|
|
|
-
|
|
|
|
- //#SECTION finalize
|
|
|
|
-
|
|
|
|
- menuBodyElem.appendChild(textElem);
|
|
|
|
- menuBodyElem.appendChild(textAreaElem);
|
|
|
|
- menuBodyElem.appendChild(footerElem);
|
|
|
|
-
|
|
|
|
- menuContainer.appendChild(headerElem);
|
|
|
|
- menuContainer.appendChild(menuBodyElem);
|
|
|
|
-
|
|
|
|
- menuBgElem.appendChild(menuContainer);
|
|
|
|
-
|
|
|
|
- document.body.appendChild(menuBgElem);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/** Closes the import menu if it is open. If a bubbling event is passed, its propagation will be prevented. */
|
|
|
|
-function closeImportMenu(evt?: MouseEvent | KeyboardEvent) {
|
|
|
|
- if(!isImportMenuOpen)
|
|
|
|
- return;
|
|
|
|
- isImportMenuOpen = false;
|
|
|
|
- evt?.bubbles && evt.stopPropagation();
|
|
|
|
-
|
|
|
|
- const menuBg = document.querySelector<HTMLElement>("#bytm-import-menu-bg");
|
|
|
|
-
|
|
|
|
- const textAreaElem = document.querySelector<HTMLTextAreaElement>("#bytm-import-menu-textarea");
|
|
|
|
- if(textAreaElem)
|
|
|
|
- textAreaElem.value = "";
|
|
|
|
-
|
|
|
|
- if(!menuBg)
|
|
|
|
- return warn("Couldn't find import menu background element");
|
|
|
|
-
|
|
|
|
- menuBg.style.visibility = "hidden";
|
|
|
|
- menuBg.style.display = "none";
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/** Opens the import menu if it is closed */
|
|
|
|
-async function openImportMenu() {
|
|
|
|
- if(!isImportMenuAdded)
|
|
|
|
- await addImportMenu();
|
|
|
|
- isImportMenuAdded = true;
|
|
|
|
-
|
|
|
|
- if(isImportMenuOpen)
|
|
|
|
- return;
|
|
|
|
- isImportMenuOpen = true;
|
|
|
|
-
|
|
|
|
- document.body.classList.add("bytm-disable-scroll");
|
|
|
|
- document.querySelector("ytmusic-app")?.setAttribute("inert", "true");
|
|
|
|
- const menuBg = document.querySelector<HTMLElement>("#bytm-import-menu-bg");
|
|
|
|
-
|
|
|
|
- if(!menuBg)
|
|
|
|
- return warn("Couldn't find import menu background element");
|
|
|
|
-
|
|
|
|
- menuBg.style.visibility = "visible";
|
|
|
|
- menuBg.style.display = "block";
|
|
|
|
-}
|
|
|