mirror of
https://github.com/BetterSEQTA/BetterSEQTA-Plus.git
synced 2026-06-13 07:04:39 +00:00
format: run prettify
This commit is contained in:
@@ -1,36 +1,40 @@
|
||||
import { changeSettingsClicked, closeExtensionPopup, SettingsClicked } from "../Closers/closeExtensionPopup"
|
||||
import renderSvelte from "@/interface/main"
|
||||
import { SettingsResizer } from "@/seqta/ui/SettingsResizer"
|
||||
import Settings from "@/interface/pages/settings.svelte"
|
||||
import {
|
||||
changeSettingsClicked,
|
||||
closeExtensionPopup,
|
||||
SettingsClicked,
|
||||
} from "../Closers/closeExtensionPopup";
|
||||
import renderSvelte from "@/interface/main";
|
||||
import { SettingsResizer } from "@/seqta/ui/SettingsResizer";
|
||||
import Settings from "@/interface/pages/settings.svelte";
|
||||
|
||||
export function addExtensionSettings() {
|
||||
const extensionPopup = document.createElement("div")
|
||||
extensionPopup.classList.add("outside-container", "hide")
|
||||
extensionPopup.id = "ExtensionPopup"
|
||||
|
||||
const extensionContainer = document.querySelector(
|
||||
"#container",
|
||||
) as HTMLDivElement
|
||||
if (extensionContainer) extensionContainer.appendChild(extensionPopup)
|
||||
|
||||
// create shadow dom and render svelte app
|
||||
try {
|
||||
const shadow = extensionPopup.attachShadow({ mode: "open" })
|
||||
requestIdleCallback(() => renderSvelte(Settings, shadow))
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
const extensionPopup = document.createElement("div");
|
||||
extensionPopup.classList.add("outside-container", "hide");
|
||||
extensionPopup.id = "ExtensionPopup";
|
||||
|
||||
const extensionContainer = document.querySelector(
|
||||
"#container",
|
||||
) as HTMLDivElement;
|
||||
if (extensionContainer) extensionContainer.appendChild(extensionPopup);
|
||||
|
||||
// create shadow dom and render svelte app
|
||||
try {
|
||||
const shadow = extensionPopup.attachShadow({ mode: "open" });
|
||||
requestIdleCallback(() => renderSvelte(Settings, shadow));
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
|
||||
const container = document.getElementById("container");
|
||||
|
||||
new SettingsResizer();
|
||||
|
||||
container!.onclick = (event) => {
|
||||
if (!SettingsClicked) return;
|
||||
|
||||
if (!(event.target as HTMLElement).closest("#AddedSettings")) {
|
||||
if (event.target == extensionPopup) return;
|
||||
changeSettingsClicked(closeExtensionPopup());
|
||||
}
|
||||
|
||||
const container = document.getElementById("container")
|
||||
|
||||
new SettingsResizer()
|
||||
|
||||
container!.onclick = (event) => {
|
||||
if (!SettingsClicked) return
|
||||
|
||||
if (!(event.target as HTMLElement).closest("#AddedSettings")) {
|
||||
if (event.target == extensionPopup) return
|
||||
changeSettingsClicked(closeExtensionPopup())
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
import ShortcutLinks from "@/seqta/content/links.json"
|
||||
import stringToHTML from "../stringToHTML"
|
||||
import ShortcutLinks from "@/seqta/content/links.json";
|
||||
import stringToHTML from "../stringToHTML";
|
||||
|
||||
export function addShortcuts(shortcuts: any) {
|
||||
for (let i = 0; i < shortcuts.length; i++) {
|
||||
const currentShortcut = shortcuts[i]
|
||||
const currentShortcut = shortcuts[i];
|
||||
|
||||
if (currentShortcut?.enabled) {
|
||||
const Itemname = (currentShortcut?.name ?? "").replace(/\s/g, "")
|
||||
const Itemname = (currentShortcut?.name ?? "").replace(/\s/g, "");
|
||||
|
||||
const linkDetails =
|
||||
ShortcutLinks?.[Itemname as keyof typeof ShortcutLinks]
|
||||
ShortcutLinks?.[Itemname as keyof typeof ShortcutLinks];
|
||||
if (linkDetails) {
|
||||
createNewShortcut(
|
||||
linkDetails.link,
|
||||
linkDetails.icon,
|
||||
linkDetails.viewBox,
|
||||
currentShortcut?.name,
|
||||
)
|
||||
);
|
||||
} else {
|
||||
console.warn(`No link details found for '${Itemname}'`)
|
||||
console.warn(`No link details found for '${Itemname}'`);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,21 +26,21 @@ export function addShortcuts(shortcuts: any) {
|
||||
|
||||
function createNewShortcut(link: any, icon: any, viewBox: any, title: any) {
|
||||
// Creates the stucture and element information for each seperate shortcut
|
||||
let shortcut = document.createElement("a")
|
||||
shortcut.setAttribute("href", link)
|
||||
shortcut.setAttribute("target", "_blank")
|
||||
let shortcutdiv = document.createElement("div")
|
||||
shortcutdiv.classList.add("shortcut")
|
||||
let shortcut = document.createElement("a");
|
||||
shortcut.setAttribute("href", link);
|
||||
shortcut.setAttribute("target", "_blank");
|
||||
let shortcutdiv = document.createElement("div");
|
||||
shortcutdiv.classList.add("shortcut");
|
||||
|
||||
let image = stringToHTML(
|
||||
`<svg style="width:39px;height:39px" viewBox="${viewBox}"><path fill="currentColor" d="${icon}" /></svg>`,
|
||||
).firstChild
|
||||
;(image! as HTMLElement).classList.add("shortcuticondiv")
|
||||
let text = document.createElement("p")
|
||||
text.textContent = title
|
||||
shortcutdiv.append(image as HTMLElement)
|
||||
shortcutdiv.append(text)
|
||||
shortcut.append(shortcutdiv)
|
||||
).firstChild;
|
||||
(image! as HTMLElement).classList.add("shortcuticondiv");
|
||||
let text = document.createElement("p");
|
||||
text.textContent = title;
|
||||
shortcutdiv.append(image as HTMLElement);
|
||||
shortcutdiv.append(text);
|
||||
shortcut.append(shortcutdiv);
|
||||
|
||||
document.getElementById("shortcuts")!.appendChild(shortcut)
|
||||
}
|
||||
document.getElementById("shortcuts")!.appendChild(shortcut);
|
||||
}
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
import { settingsState } from "@/seqta/utils/listeners/SettingsState";
|
||||
import { animate } from "motion"
|
||||
import { animate } from "motion";
|
||||
|
||||
import { settingsPopup } from "@/interface/hooks/SettingsPopup"
|
||||
import { settingsPopup } from "@/interface/hooks/SettingsPopup";
|
||||
|
||||
export let SettingsClicked = false
|
||||
export let SettingsClicked = false;
|
||||
|
||||
export const closeExtensionPopup = (extensionPopup?: HTMLElement) => {
|
||||
if (!extensionPopup)
|
||||
extensionPopup = document.getElementById("ExtensionPopup")!
|
||||
|
||||
extensionPopup.classList.add("hide")
|
||||
if (settingsState.animations) {
|
||||
animate(1, 0, {
|
||||
onUpdate: (progress) => {
|
||||
extensionPopup.style.opacity = Math.max(0, progress).toString()
|
||||
extensionPopup.style.transform = `scale(${Math.max(0, progress)})`
|
||||
},
|
||||
type: "spring",
|
||||
stiffness: 520,
|
||||
damping: 20,
|
||||
})
|
||||
} else {
|
||||
extensionPopup.style.opacity = "0"
|
||||
extensionPopup.style.transform = "scale(0)"
|
||||
}
|
||||
|
||||
settingsPopup.triggerClose()
|
||||
return SettingsClicked = false
|
||||
if (!extensionPopup)
|
||||
extensionPopup = document.getElementById("ExtensionPopup")!;
|
||||
|
||||
extensionPopup.classList.add("hide");
|
||||
if (settingsState.animations) {
|
||||
animate(1, 0, {
|
||||
onUpdate: (progress) => {
|
||||
extensionPopup.style.opacity = Math.max(0, progress).toString();
|
||||
extensionPopup.style.transform = `scale(${Math.max(0, progress)})`;
|
||||
},
|
||||
type: "spring",
|
||||
stiffness: 520,
|
||||
damping: 20,
|
||||
});
|
||||
} else {
|
||||
extensionPopup.style.opacity = "0";
|
||||
extensionPopup.style.transform = "scale(0)";
|
||||
}
|
||||
|
||||
export function changeSettingsClicked(newVal: boolean) {
|
||||
SettingsClicked = newVal
|
||||
}
|
||||
settingsPopup.triggerClose();
|
||||
return (SettingsClicked = false);
|
||||
};
|
||||
|
||||
export function changeSettingsClicked(newVal: boolean) {
|
||||
SettingsClicked = newVal;
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import stringToHTML from "../stringToHTML"
|
||||
import stringToHTML from "../stringToHTML";
|
||||
|
||||
export function CreateCustomShortcutDiv(element: any) {
|
||||
// Creates the stucture and element information for each seperate shortcut
|
||||
var shortcut = document.createElement("a")
|
||||
shortcut.setAttribute("href", element.url)
|
||||
shortcut.setAttribute("target", "_blank")
|
||||
var shortcutdiv = document.createElement("div")
|
||||
shortcutdiv.classList.add("shortcut")
|
||||
shortcutdiv.classList.add("customshortcut")
|
||||
var shortcut = document.createElement("a");
|
||||
shortcut.setAttribute("href", element.url);
|
||||
shortcut.setAttribute("target", "_blank");
|
||||
var shortcutdiv = document.createElement("div");
|
||||
shortcutdiv.classList.add("shortcut");
|
||||
shortcutdiv.classList.add("customshortcut");
|
||||
|
||||
let image = stringToHTML(
|
||||
`
|
||||
@@ -25,13 +25,13 @@ export function CreateCustomShortcutDiv(element: any) {
|
||||
</text>
|
||||
</svg>
|
||||
`,
|
||||
).firstChild
|
||||
;(image as HTMLElement).classList.add("shortcuticondiv")
|
||||
var text = document.createElement("p")
|
||||
text.textContent = element.name
|
||||
shortcutdiv.append(image!)
|
||||
shortcutdiv.append(text)
|
||||
shortcut.append(shortcutdiv)
|
||||
).firstChild;
|
||||
(image as HTMLElement).classList.add("shortcuticondiv");
|
||||
var text = document.createElement("p");
|
||||
text.textContent = element.name;
|
||||
shortcutdiv.append(image!);
|
||||
shortcutdiv.append(text);
|
||||
shortcut.append(shortcutdiv);
|
||||
|
||||
document.getElementById("shortcuts")!.append(shortcut)
|
||||
}
|
||||
document.getElementById("shortcuts")!.append(shortcut);
|
||||
}
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
export function CreateElement(
|
||||
type: string,
|
||||
class_?: any,
|
||||
id?: any,
|
||||
innerText?: string,
|
||||
innerHTML?: string,
|
||||
style?: string,
|
||||
) {
|
||||
let element = document.createElement(type)
|
||||
if (class_ !== undefined) {
|
||||
element.classList.add(class_)
|
||||
}
|
||||
if (id !== undefined) {
|
||||
element.id = id
|
||||
}
|
||||
if (innerText !== undefined) {
|
||||
element.innerText = innerText
|
||||
}
|
||||
if (innerHTML !== undefined) {
|
||||
element.innerHTML = innerHTML
|
||||
}
|
||||
if (style !== undefined) {
|
||||
element.style.cssText = style
|
||||
}
|
||||
return element
|
||||
}
|
||||
type: string,
|
||||
class_?: any,
|
||||
id?: any,
|
||||
innerText?: string,
|
||||
innerHTML?: string,
|
||||
style?: string,
|
||||
) {
|
||||
let element = document.createElement(type);
|
||||
if (class_ !== undefined) {
|
||||
element.classList.add(class_);
|
||||
}
|
||||
if (id !== undefined) {
|
||||
element.id = id;
|
||||
}
|
||||
if (innerText !== undefined) {
|
||||
element.innerText = innerText;
|
||||
}
|
||||
if (innerHTML !== undefined) {
|
||||
element.innerHTML = innerHTML;
|
||||
}
|
||||
if (style !== undefined) {
|
||||
element.style.cssText = style;
|
||||
}
|
||||
return element;
|
||||
}
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
export function RemoveShortcutDiv(elements: any) {
|
||||
if (elements.length === 0) return
|
||||
if (elements.length === 0) return;
|
||||
|
||||
elements.forEach((element: any) => {
|
||||
const shortcuts = document.querySelectorAll(".shortcut")
|
||||
const shortcuts = document.querySelectorAll(".shortcut");
|
||||
shortcuts.forEach((shortcut) => {
|
||||
const anchorElement = shortcut.parentElement // the <a> element is the parent
|
||||
const textElement = shortcut.querySelector("p") // <p> is a direct child of .shortcut
|
||||
const title = textElement ? textElement.textContent : ""
|
||||
const anchorElement = shortcut.parentElement; // the <a> element is the parent
|
||||
const textElement = shortcut.querySelector("p"); // <p> is a direct child of .shortcut
|
||||
const title = textElement ? textElement.textContent : "";
|
||||
|
||||
let shouldRemove = title === element.name
|
||||
let shouldRemove = title === element.name;
|
||||
|
||||
// Check href only if element.url exists
|
||||
if (element.url) {
|
||||
shouldRemove =
|
||||
shouldRemove && anchorElement!.getAttribute("href") === element.url
|
||||
shouldRemove && anchorElement!.getAttribute("href") === element.url;
|
||||
}
|
||||
|
||||
if (shouldRemove) {
|
||||
anchorElement!.remove()
|
||||
anchorElement!.remove();
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -19,25 +19,25 @@ export async function UploadImage(file: File): Promise<any> {
|
||||
|
||||
// Setting up the request options
|
||||
const requestOptions = {
|
||||
method: 'POST',
|
||||
method: "POST",
|
||||
headers: {
|
||||
'Cookie': cookies,
|
||||
'X-File-Name': fileName
|
||||
Cookie: cookies,
|
||||
"X-File-Name": fileName,
|
||||
},
|
||||
body: file // Binary file data
|
||||
body: file, // Binary file data
|
||||
};
|
||||
|
||||
// Making the fetch request and returning the promise
|
||||
return await fetch('/seqta/student/file/upload/xhr2', requestOptions)
|
||||
.then(async response => {
|
||||
return await fetch("/seqta/student/file/upload/xhr2", requestOptions)
|
||||
.then(async (response) => {
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! Status: ${response.status}`);
|
||||
}
|
||||
const json = await response.json();
|
||||
return `/seqta/student/load/file?type=message&file=${json.uuid}`;
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error during file upload:', error);
|
||||
.catch((error) => {
|
||||
console.error("Error during file upload:", error);
|
||||
throw error;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
import { CreateElement } from "@/seqta/utils/CreateEnable/CreateElement"
|
||||
import { CreateElement } from "@/seqta/utils/CreateEnable/CreateElement";
|
||||
|
||||
export function FilterUpcomingAssessments(subjectoptions: any) {
|
||||
for (var item in subjectoptions) {
|
||||
let subjectdivs = document.querySelectorAll(`[data-subject="${item}"]`)
|
||||
let subjectdivs = document.querySelectorAll(`[data-subject="${item}"]`);
|
||||
|
||||
for (let i = 0; i < subjectdivs.length; i++) {
|
||||
const element = subjectdivs[i]
|
||||
const element = subjectdivs[i];
|
||||
|
||||
if (!subjectoptions[item]) {
|
||||
element.classList.add("hidden")
|
||||
element.classList.add("hidden");
|
||||
}
|
||||
if (subjectoptions[item]) {
|
||||
element.classList.remove("hidden")
|
||||
element.classList.remove("hidden");
|
||||
}
|
||||
(element.parentNode! as HTMLElement).classList.remove("hidden")
|
||||
(element.parentNode! as HTMLElement).classList.remove("hidden");
|
||||
|
||||
let children = element.parentNode!.parentNode!.children
|
||||
let children = element.parentNode!.parentNode!.children;
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
const element = children[i]
|
||||
const element = children[i];
|
||||
if (element.hasAttribute("data-hidden")) {
|
||||
element.remove()
|
||||
element.remove();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,33 +35,33 @@ export function FilterUpcomingAssessments(subjectoptions: any) {
|
||||
) {
|
||||
(element.parentNode!.parentNode! as HTMLElement).classList.add(
|
||||
"hidden",
|
||||
)
|
||||
);
|
||||
} else {
|
||||
AddPlaceHolderToParent(
|
||||
element.parentNode!.parentNode,
|
||||
element.parentNode!.querySelectorAll(".hidden").length,
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
(element.parentNode!.parentNode! as HTMLElement).classList.remove(
|
||||
"hidden",
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function AddPlaceHolderToParent(parent: any, numberofassessments: any) {
|
||||
let textcontainer = CreateElement("div", "upcoming-blank")
|
||||
let textblank = CreateElement("p", "upcoming-hiddenassessment")
|
||||
let s = ""
|
||||
let textcontainer = CreateElement("div", "upcoming-blank");
|
||||
let textblank = CreateElement("p", "upcoming-hiddenassessment");
|
||||
let s = "";
|
||||
if (numberofassessments > 1) {
|
||||
s = "s"
|
||||
s = "s";
|
||||
}
|
||||
textblank.innerText = `${numberofassessments} hidden assessment${s} due`
|
||||
textcontainer.append(textblank)
|
||||
textcontainer.setAttribute("data-hidden", "true")
|
||||
textblank.innerText = `${numberofassessments} hidden assessment${s} due`;
|
||||
textcontainer.append(textblank);
|
||||
textcontainer.setAttribute("data-hidden", "true");
|
||||
|
||||
parent.append(textcontainer)
|
||||
}
|
||||
parent.append(textcontainer);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,26 +1,26 @@
|
||||
import stringToHTML from "../stringToHTML"
|
||||
import browser from "webextension-polyfill"
|
||||
import { settingsState } from "../listeners/SettingsState"
|
||||
import { animate, stagger } from "motion"
|
||||
import { DeleteWhatsNew } from "../Whatsnew"
|
||||
import stringToHTML from "../stringToHTML";
|
||||
import browser from "webextension-polyfill";
|
||||
import { settingsState } from "../listeners/SettingsState";
|
||||
import { animate, stagger } from "motion";
|
||||
import { DeleteWhatsNew } from "../Whatsnew";
|
||||
|
||||
export function OpenAboutPage() {
|
||||
const background = document.createElement("div")
|
||||
background.id = "whatsnewbk"
|
||||
background.classList.add("whatsnewBackground")
|
||||
|
||||
const container = document.createElement("div")
|
||||
container.classList.add("whatsnewContainer")
|
||||
|
||||
var header: any = stringToHTML(
|
||||
/* html */
|
||||
`<div class="whatsnewHeader">
|
||||
const background = document.createElement("div");
|
||||
background.id = "whatsnewbk";
|
||||
background.classList.add("whatsnewBackground");
|
||||
|
||||
const container = document.createElement("div");
|
||||
container.classList.add("whatsnewContainer");
|
||||
|
||||
var header: any = stringToHTML(
|
||||
/* html */
|
||||
`<div class="whatsnewHeader">
|
||||
<h1>About</h1>
|
||||
<p>BetterSEQTA+ V${browser.runtime.getManifest().version}</p>
|
||||
</div>`,
|
||||
).firstChild
|
||||
|
||||
let text = stringToHTML(/* html */ `
|
||||
).firstChild;
|
||||
|
||||
let text = stringToHTML(/* html */ `
|
||||
<div class="whatsnewTextContainer" style="overflow-y: scroll;">
|
||||
<img src="${settingsState.DarkMode ? "https://raw.githubusercontent.com/BetterSEQTA/BetterSEQTA-Plus/main/src/resources/branding/dark.jpg" : "https://raw.githubusercontent.com/BetterSEQTA/BetterSEQTA-Plus/main/src/resources/branding/light.jpg"}" class="aboutImg" />
|
||||
|
||||
@@ -29,9 +29,9 @@ export function OpenAboutPage() {
|
||||
<h1>Credits</h1>
|
||||
<p>Nulkem created the original extension, was ported to Manifest V3 by MEGA-Dawg68, and is under active development by Crazypersonalph and SethBurkart123.</p>
|
||||
</div>
|
||||
`).firstChild
|
||||
|
||||
let footer = stringToHTML(/* html */ `
|
||||
`).firstChild;
|
||||
|
||||
let footer = stringToHTML(/* html */ `
|
||||
<div class="whatsnewFooter">
|
||||
<div>
|
||||
Report bugs and feedback:
|
||||
@@ -52,56 +52,56 @@ export function OpenAboutPage() {
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
`).firstChild
|
||||
|
||||
let exitbutton = document.createElement("div")
|
||||
exitbutton.id = "whatsnewclosebutton"
|
||||
|
||||
container.append(header)
|
||||
container.append(text as ChildNode)
|
||||
container.append(footer as ChildNode)
|
||||
container.append(exitbutton)
|
||||
|
||||
background.append(container)
|
||||
|
||||
document.getElementById("container")!.append(background)
|
||||
|
||||
let bkelement = document.getElementById("whatsnewbk")
|
||||
let popup = document.getElementsByClassName("whatsnewContainer")[0]
|
||||
|
||||
if (settingsState.animations) {
|
||||
animate(
|
||||
[popup, bkelement as HTMLElement],
|
||||
{ scale: [0, 1] },
|
||||
{
|
||||
type: "spring",
|
||||
stiffness: 220,
|
||||
damping: 18,
|
||||
},
|
||||
)
|
||||
|
||||
animate(
|
||||
".whatsnewTextContainer *",
|
||||
{ opacity: [0, 1], y: [10, 0] },
|
||||
{
|
||||
delay: stagger(0.05, { startDelay: 0.1 }),
|
||||
duration: 0.5,
|
||||
ease: [0.22, 0.03, 0.26, 1],
|
||||
},
|
||||
)
|
||||
`).firstChild;
|
||||
|
||||
let exitbutton = document.createElement("div");
|
||||
exitbutton.id = "whatsnewclosebutton";
|
||||
|
||||
container.append(header);
|
||||
container.append(text as ChildNode);
|
||||
container.append(footer as ChildNode);
|
||||
container.append(exitbutton);
|
||||
|
||||
background.append(container);
|
||||
|
||||
document.getElementById("container")!.append(background);
|
||||
|
||||
let bkelement = document.getElementById("whatsnewbk");
|
||||
let popup = document.getElementsByClassName("whatsnewContainer")[0];
|
||||
|
||||
if (settingsState.animations) {
|
||||
animate(
|
||||
[popup, bkelement as HTMLElement],
|
||||
{ scale: [0, 1] },
|
||||
{
|
||||
type: "spring",
|
||||
stiffness: 220,
|
||||
damping: 18,
|
||||
},
|
||||
);
|
||||
|
||||
animate(
|
||||
".whatsnewTextContainer *",
|
||||
{ opacity: [0, 1], y: [10, 0] },
|
||||
{
|
||||
delay: stagger(0.05, { startDelay: 0.1 }),
|
||||
duration: 0.5,
|
||||
ease: [0.22, 0.03, 0.26, 1],
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
delete settingsState.justupdated;
|
||||
|
||||
bkelement!.addEventListener("click", function (event) {
|
||||
// Check if the click event originated from the element itself and not any of its children
|
||||
if (event.target === bkelement) {
|
||||
DeleteWhatsNew();
|
||||
}
|
||||
|
||||
delete settingsState.justupdated
|
||||
|
||||
bkelement!.addEventListener("click", function (event) {
|
||||
// Check if the click event originated from the element itself and not any of its children
|
||||
if (event.target === bkelement) {
|
||||
DeleteWhatsNew()
|
||||
}
|
||||
})
|
||||
|
||||
var closeelement = document.getElementById("whatsnewclosebutton")
|
||||
closeelement!.addEventListener("click", function () {
|
||||
DeleteWhatsNew()
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
var closeelement = document.getElementById("whatsnewclosebutton");
|
||||
closeelement!.addEventListener("click", function () {
|
||||
DeleteWhatsNew();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,259 +1,253 @@
|
||||
import type { SettingsState } from "@/types/storage";
|
||||
import { settingsState } from "../listeners/SettingsState";
|
||||
import stringToHTML from "../stringToHTML";
|
||||
import Sortable from "sortablejs";
|
||||
|
||||
import type { SettingsState } from "@/types/storage"
|
||||
import { settingsState } from "../listeners/SettingsState"
|
||||
import stringToHTML from "../stringToHTML"
|
||||
import Sortable from "sortablejs"
|
||||
|
||||
export let MenuOptionsOpen = false
|
||||
|
||||
export let MenuOptionsOpen = false;
|
||||
|
||||
export function OpenMenuOptions() {
|
||||
var container = document.getElementById("container")
|
||||
var menu = document.getElementById("menu")
|
||||
var container = document.getElementById("container");
|
||||
var menu = document.getElementById("menu");
|
||||
|
||||
if (settingsState.defaultmenuorder.length == 0) {
|
||||
let childnodes = menu!.firstChild!.childNodes
|
||||
let newdefaultmenuorder = []
|
||||
let childnodes = menu!.firstChild!.childNodes;
|
||||
let newdefaultmenuorder = [];
|
||||
for (let i = 0; i < childnodes.length; i++) {
|
||||
const element = childnodes[i]
|
||||
newdefaultmenuorder.push((element as HTMLElement).dataset.key)
|
||||
settingsState.defaultmenuorder = newdefaultmenuorder
|
||||
const element = childnodes[i];
|
||||
newdefaultmenuorder.push((element as HTMLElement).dataset.key);
|
||||
settingsState.defaultmenuorder = newdefaultmenuorder;
|
||||
}
|
||||
}
|
||||
let childnodes = menu!.firstChild!.childNodes
|
||||
let childnodes = menu!.firstChild!.childNodes;
|
||||
if (settingsState.defaultmenuorder.length != childnodes.length) {
|
||||
for (let i = 0; i < childnodes.length; i++) {
|
||||
const element = childnodes[i]
|
||||
const element = childnodes[i];
|
||||
if (
|
||||
!settingsState.defaultmenuorder.indexOf(
|
||||
(element as HTMLElement).dataset.key,
|
||||
)
|
||||
) {
|
||||
let newdefaultmenuorder = settingsState.defaultmenuorder
|
||||
newdefaultmenuorder.push((element as HTMLElement).dataset.key)
|
||||
settingsState.defaultmenuorder = newdefaultmenuorder
|
||||
let newdefaultmenuorder = settingsState.defaultmenuorder;
|
||||
newdefaultmenuorder.push((element as HTMLElement).dataset.key);
|
||||
settingsState.defaultmenuorder = newdefaultmenuorder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MenuOptionsOpen = true
|
||||
MenuOptionsOpen = true;
|
||||
|
||||
var cover = document.createElement("div")
|
||||
cover.classList.add("notMenuCover")
|
||||
menu!.style.zIndex = "20"
|
||||
menu!.style.setProperty("--menuHidden", "flex")
|
||||
container!.append(cover)
|
||||
var cover = document.createElement("div");
|
||||
cover.classList.add("notMenuCover");
|
||||
menu!.style.zIndex = "20";
|
||||
menu!.style.setProperty("--menuHidden", "flex");
|
||||
container!.append(cover);
|
||||
|
||||
var menusettings = document.createElement("div")
|
||||
menusettings.classList.add("editmenuoption-container")
|
||||
var menusettings = document.createElement("div");
|
||||
menusettings.classList.add("editmenuoption-container");
|
||||
|
||||
var defaultbutton = document.createElement("div")
|
||||
defaultbutton.classList.add("editmenuoption")
|
||||
defaultbutton.innerText = "Restore Default"
|
||||
defaultbutton.id = "restoredefaultoption"
|
||||
var defaultbutton = document.createElement("div");
|
||||
defaultbutton.classList.add("editmenuoption");
|
||||
defaultbutton.innerText = "Restore Default";
|
||||
defaultbutton.id = "restoredefaultoption";
|
||||
|
||||
var savebutton = document.createElement("div")
|
||||
savebutton.classList.add("editmenuoption")
|
||||
savebutton.innerText = "Save"
|
||||
savebutton.id = "restoredefaultoption"
|
||||
var savebutton = document.createElement("div");
|
||||
savebutton.classList.add("editmenuoption");
|
||||
savebutton.innerText = "Save";
|
||||
savebutton.id = "restoredefaultoption";
|
||||
|
||||
menusettings.appendChild(defaultbutton)
|
||||
menusettings.appendChild(savebutton)
|
||||
menusettings.appendChild(defaultbutton);
|
||||
menusettings.appendChild(savebutton);
|
||||
|
||||
menu!.appendChild(menusettings)
|
||||
menu!.appendChild(menusettings);
|
||||
|
||||
var ListItems = menu!.firstChild!.childNodes
|
||||
var ListItems = menu!.firstChild!.childNodes;
|
||||
for (let i = 0; i < ListItems.length; i++) {
|
||||
const element1 = ListItems[i]
|
||||
const element = element1 as HTMLElement
|
||||
const element1 = ListItems[i];
|
||||
const element = element1 as HTMLElement;
|
||||
|
||||
;(element as HTMLElement).classList.add("draggable")
|
||||
(element as HTMLElement).classList.add("draggable");
|
||||
if ((element as HTMLElement).classList.contains("hasChildren")) {
|
||||
(element as HTMLElement).classList.remove("active")
|
||||
;(element.firstChild as HTMLElement).classList.remove("noscroll")
|
||||
(element as HTMLElement).classList.remove("active");
|
||||
(element.firstChild as HTMLElement).classList.remove("noscroll");
|
||||
}
|
||||
|
||||
let MenuItemToggle = stringToHTML(
|
||||
`<div class="onoffswitch" style="margin: auto 0;"><input class="onoffswitch-checkbox notification menuitem" type="checkbox" id="${(element as HTMLElement).dataset.key}"><label for="${(element as HTMLElement).dataset.key}" class="onoffswitch-label"></label>`,
|
||||
).firstChild
|
||||
;(element as HTMLElement).append(MenuItemToggle!)
|
||||
).firstChild;
|
||||
(element as HTMLElement).append(MenuItemToggle!);
|
||||
|
||||
if (!element.dataset.betterseqta) {
|
||||
const a = document.createElement("section")
|
||||
a.innerHTML = element.innerHTML
|
||||
cloneAttributes(a, element)
|
||||
menu!.firstChild!.insertBefore(a, element)
|
||||
element.remove()
|
||||
const a = document.createElement("section");
|
||||
a.innerHTML = element.innerHTML;
|
||||
cloneAttributes(a, element);
|
||||
menu!.firstChild!.insertBefore(a, element);
|
||||
element.remove();
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.keys(settingsState.menuitems).length == 0) {
|
||||
menubuttons = menu!.firstChild!.childNodes
|
||||
let menuItems = {} as any
|
||||
menubuttons = menu!.firstChild!.childNodes;
|
||||
let menuItems = {} as any;
|
||||
for (var i = 0; i < menubuttons.length; i++) {
|
||||
var id = (menubuttons[i] as HTMLElement).dataset.key
|
||||
const element: any = {}
|
||||
element.toggle = true
|
||||
;(menuItems[id as keyof typeof menuItems] as any) = element
|
||||
var id = (menubuttons[i] as HTMLElement).dataset.key;
|
||||
const element: any = {};
|
||||
element.toggle = true;
|
||||
(menuItems[id as keyof typeof menuItems] as any) = element;
|
||||
}
|
||||
settingsState.menuitems = menuItems
|
||||
settingsState.menuitems = menuItems;
|
||||
}
|
||||
|
||||
var menubuttons: any = document.getElementsByClassName("menuitem")
|
||||
var menubuttons: any = document.getElementsByClassName("menuitem");
|
||||
|
||||
let menuItems = settingsState.menuitems as any
|
||||
let buttons = document.getElementsByClassName("menuitem")
|
||||
let menuItems = settingsState.menuitems as any;
|
||||
let buttons = document.getElementsByClassName("menuitem");
|
||||
for (let i = 0; i < buttons.length; i++) {
|
||||
let id = buttons[i].id as string | undefined
|
||||
let id = buttons[i].id as string | undefined;
|
||||
if (menuItems[id as keyof typeof menuItems]) {
|
||||
(buttons[i] as HTMLInputElement).checked =
|
||||
menuItems[id as keyof typeof menuItems].toggle
|
||||
menuItems[id as keyof typeof menuItems].toggle;
|
||||
} else {
|
||||
(buttons[i] as HTMLInputElement).checked = true
|
||||
(buttons[i] as HTMLInputElement).checked = true;
|
||||
}
|
||||
(buttons[i] as HTMLInputElement).checked = true
|
||||
(buttons[i] as HTMLInputElement).checked = true;
|
||||
}
|
||||
|
||||
try {
|
||||
var el = document.querySelector("#menu > ul")
|
||||
var el = document.querySelector("#menu > ul");
|
||||
var sortable = Sortable.create(el as HTMLElement, {
|
||||
draggable: ".draggable",
|
||||
dataIdAttr: "data-key",
|
||||
animation: 150,
|
||||
easing: "cubic-bezier(.5,0,.5,1)",
|
||||
onEnd: function () {
|
||||
saveNewOrder(sortable)
|
||||
saveNewOrder(sortable);
|
||||
},
|
||||
})
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
console.error(err);
|
||||
}
|
||||
|
||||
function changeDisplayProperty(element: any) {
|
||||
if (!element.checked) {
|
||||
element.parentNode.parentNode.style.display = "var(--menuHidden)"
|
||||
element.parentNode.parentNode.style.display = "var(--menuHidden)";
|
||||
}
|
||||
if (element.checked) {
|
||||
element.parentNode.parentNode.style.setProperty(
|
||||
"display",
|
||||
"flex",
|
||||
"important",
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function StoreMenuSettings() {
|
||||
let menu = document.getElementById("menu")
|
||||
const menuItems: any = {}
|
||||
let menubuttons = menu!.firstChild!.childNodes
|
||||
const button = document.getElementsByClassName("menuitem")
|
||||
let menu = document.getElementById("menu");
|
||||
const menuItems: any = {};
|
||||
let menubuttons = menu!.firstChild!.childNodes;
|
||||
const button = document.getElementsByClassName("menuitem");
|
||||
for (let i = 0; i < menubuttons.length; i++) {
|
||||
const id = (menubuttons[i] as HTMLElement).dataset.key
|
||||
const element: any = {}
|
||||
element.toggle = (button[i] as HTMLInputElement).checked
|
||||
const id = (menubuttons[i] as HTMLElement).dataset.key;
|
||||
const element: any = {};
|
||||
element.toggle = (button[i] as HTMLInputElement).checked;
|
||||
|
||||
menuItems[id as keyof typeof menuItems] = element
|
||||
menuItems[id as keyof typeof menuItems] = element;
|
||||
}
|
||||
settingsState.menuitems = menuItems
|
||||
settingsState.menuitems = menuItems;
|
||||
}
|
||||
|
||||
for (let i = 0; i < menubuttons.length; i++) {
|
||||
const element = menubuttons[i]
|
||||
const element = menubuttons[i];
|
||||
element.addEventListener("change", () => {
|
||||
element.parentElement.parentElement.getAttribute("data-key")
|
||||
StoreMenuSettings()
|
||||
changeDisplayProperty(element)
|
||||
})
|
||||
element.parentElement.parentElement.getAttribute("data-key");
|
||||
StoreMenuSettings();
|
||||
changeDisplayProperty(element);
|
||||
});
|
||||
}
|
||||
|
||||
function closeAll() {
|
||||
menusettings?.remove()
|
||||
cover?.remove()
|
||||
MenuOptionsOpen = false
|
||||
menu!.style.setProperty("--menuHidden", "none")
|
||||
menusettings?.remove();
|
||||
cover?.remove();
|
||||
MenuOptionsOpen = false;
|
||||
menu!.style.setProperty("--menuHidden", "none");
|
||||
|
||||
for (let i = 0; i < ListItems.length; i++) {
|
||||
const element1 = ListItems[i]
|
||||
const element = element1 as HTMLElement
|
||||
element.classList.remove("draggable")
|
||||
element.setAttribute("draggable", "false")
|
||||
const element1 = ListItems[i];
|
||||
const element = element1 as HTMLElement;
|
||||
element.classList.remove("draggable");
|
||||
element.setAttribute("draggable", "false");
|
||||
|
||||
if (!element.dataset.betterseqta) {
|
||||
const a = document.createElement("li")
|
||||
a.innerHTML = element.innerHTML
|
||||
cloneAttributes(a, element)
|
||||
menu!.firstChild!.insertBefore(a, element)
|
||||
element.remove()
|
||||
const a = document.createElement("li");
|
||||
a.innerHTML = element.innerHTML;
|
||||
cloneAttributes(a, element);
|
||||
menu!.firstChild!.insertBefore(a, element);
|
||||
element.remove();
|
||||
}
|
||||
}
|
||||
|
||||
let switches = menu!.querySelectorAll(".onoffswitch")
|
||||
let switches = menu!.querySelectorAll(".onoffswitch");
|
||||
for (let i = 0; i < switches.length; i++) {
|
||||
switches[i].remove()
|
||||
switches[i].remove();
|
||||
}
|
||||
}
|
||||
|
||||
cover?.addEventListener("click", closeAll)
|
||||
savebutton?.addEventListener("click", closeAll)
|
||||
cover?.addEventListener("click", closeAll);
|
||||
savebutton?.addEventListener("click", closeAll);
|
||||
|
||||
defaultbutton?.addEventListener("click", function () {
|
||||
const options = settingsState.defaultmenuorder
|
||||
settingsState.menuorder = options
|
||||
const options = settingsState.defaultmenuorder;
|
||||
settingsState.menuorder = options;
|
||||
|
||||
ChangeMenuItemPositions(options)
|
||||
ChangeMenuItemPositions(options);
|
||||
|
||||
for (let i = 0; i < menubuttons.length; i++) {
|
||||
const element = menubuttons[i]
|
||||
element.checked = true
|
||||
const element = menubuttons[i];
|
||||
element.checked = true;
|
||||
element.parentNode.parentNode.style.setProperty(
|
||||
"display",
|
||||
"flex",
|
||||
"important",
|
||||
)
|
||||
);
|
||||
}
|
||||
saveNewOrder(sortable)
|
||||
})
|
||||
saveNewOrder(sortable);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
function saveNewOrder(sortable: any) {
|
||||
var order = sortable.toArray()
|
||||
settingsState.menuorder = order
|
||||
var order = sortable.toArray();
|
||||
settingsState.menuorder = order;
|
||||
}
|
||||
|
||||
function cloneAttributes(target: any, source: any) {
|
||||
[...source.attributes].forEach((attr) => {
|
||||
target.setAttribute(attr.nodeName, attr.nodeValue)
|
||||
})
|
||||
target.setAttribute(attr.nodeName, attr.nodeValue);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
export function ChangeMenuItemPositions(menuorder: SettingsState["menuorder"]) {
|
||||
var menuList = document.querySelector("#menu")!.firstChild!.childNodes
|
||||
var menuList = document.querySelector("#menu")!.firstChild!.childNodes;
|
||||
|
||||
let listorder = []
|
||||
let listorder = [];
|
||||
for (let i = 0; i < menuList.length; i++) {
|
||||
const menu = menuList[i] as HTMLElement
|
||||
const menu = menuList[i] as HTMLElement;
|
||||
|
||||
let a = menuorder.indexOf(menu.dataset.key)
|
||||
let a = menuorder.indexOf(menu.dataset.key);
|
||||
|
||||
listorder.push(a)
|
||||
listorder.push(a);
|
||||
}
|
||||
|
||||
var newArr = []
|
||||
var newArr = [];
|
||||
for (var i = 0; i < listorder.length; i++) {
|
||||
newArr[listorder[i]] = menuList[i]
|
||||
newArr[listorder[i]] = menuList[i];
|
||||
}
|
||||
|
||||
let listItemsDOM = document.getElementById("menu")!.firstChild
|
||||
let listItemsDOM = document.getElementById("menu")!.firstChild;
|
||||
for (let i = 0; i < newArr.length; i++) {
|
||||
const element = newArr[i]
|
||||
const element = newArr[i];
|
||||
if (element) {
|
||||
const elem = element as HTMLElement
|
||||
elem.setAttribute("data-checked", "true")
|
||||
listItemsDOM!.appendChild(element)
|
||||
const elem = element as HTMLElement;
|
||||
elem.setAttribute("data-checked", "true");
|
||||
listItemsDOM!.appendChild(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,20 +3,26 @@ class ReactFiber {
|
||||
private debug: boolean;
|
||||
private messageIdCounter: number = 0; // Counter for unique message IDs
|
||||
|
||||
constructor(selector: string, options: {
|
||||
debug ? : boolean
|
||||
} = {}) {
|
||||
constructor(
|
||||
selector: string,
|
||||
options: {
|
||||
debug?: boolean;
|
||||
} = {},
|
||||
) {
|
||||
this.selector = selector;
|
||||
this.debug = options.debug || false;
|
||||
}
|
||||
|
||||
static find(selector: string, options: {
|
||||
debug ? : boolean
|
||||
} = {}) {
|
||||
static find(
|
||||
selector: string,
|
||||
options: {
|
||||
debug?: boolean;
|
||||
} = {},
|
||||
) {
|
||||
return new ReactFiber(selector, options);
|
||||
}
|
||||
|
||||
private async sendMessage(action: string, payload: any = {}): Promise < any > {
|
||||
private async sendMessage(action: string, payload: any = {}): Promise<any> {
|
||||
return new Promise((resolve, _) => {
|
||||
const messageId = this.messageIdCounter++;
|
||||
const message = {
|
||||
@@ -29,56 +35,58 @@ class ReactFiber {
|
||||
};
|
||||
|
||||
const listener = (response: any) => {
|
||||
if (response.data?.type === 'reactFiberResponse' && response.data?.messageId === messageId) {
|
||||
if (
|
||||
response.data?.type === "reactFiberResponse" &&
|
||||
response.data?.messageId === messageId
|
||||
) {
|
||||
if (this.debug) {
|
||||
console.log("Content Received Response:", response.data.response);
|
||||
}
|
||||
resolve(response.data.response);
|
||||
window.removeEventListener("message", listener)
|
||||
window.removeEventListener("message", listener);
|
||||
}
|
||||
};
|
||||
window.addEventListener('message', listener);
|
||||
window.addEventListener("message", listener);
|
||||
window.postMessage(message, "*");
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
async getState(key ? : string | string[]): Promise < any > {
|
||||
async getState(key?: string | string[]): Promise<any> {
|
||||
return this.sendMessage("getState", {
|
||||
key
|
||||
key,
|
||||
});
|
||||
}
|
||||
|
||||
async setState(update: any | ((prevState: any) => any)): Promise < ReactFiber > {
|
||||
const updateFnString = typeof update === 'function' ? update.toString() : null;
|
||||
const updateObject = typeof update !== 'function' ? update : null;
|
||||
async setState(update: any | ((prevState: any) => any)): Promise<ReactFiber> {
|
||||
const updateFnString =
|
||||
typeof update === "function" ? update.toString() : null;
|
||||
const updateObject = typeof update !== "function" ? update : null;
|
||||
|
||||
await this.sendMessage("setState", {
|
||||
updateFn: updateFnString,
|
||||
updateObject
|
||||
updateObject,
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
async getProps(propName ? : string): Promise < any > {
|
||||
async getProps(propName?: string): Promise<any> {
|
||||
return this.sendMessage("getProp", {
|
||||
propName
|
||||
propName,
|
||||
});
|
||||
}
|
||||
|
||||
async setProp(propName: string, value: any): Promise < ReactFiber > {
|
||||
async setProp(propName: string, value: any): Promise<ReactFiber> {
|
||||
await this.sendMessage("setProp", {
|
||||
propName,
|
||||
value
|
||||
value,
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
async forceUpdate(): Promise < ReactFiber > {
|
||||
async forceUpdate(): Promise<ReactFiber> {
|
||||
await this.sendMessage("forceUpdate");
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
export default ReactFiber;
|
||||
export default ReactFiber;
|
||||
|
||||
@@ -1,93 +1,93 @@
|
||||
import { AppendLoadingSymbol } from "@/seqta/ui/Loading"
|
||||
import stringToHTML from "./stringToHTML"
|
||||
import { delay } from "./delay"
|
||||
import { settingsState } from "./listeners/SettingsState"
|
||||
import browser from "webextension-polyfill"
|
||||
import LogoLightOutline from "@/resources/icons/betterseqta-light-outline.png"
|
||||
import { animate, stagger } from "motion"
|
||||
import { AppendLoadingSymbol } from "@/seqta/ui/Loading";
|
||||
import stringToHTML from "./stringToHTML";
|
||||
import { delay } from "./delay";
|
||||
import { settingsState } from "./listeners/SettingsState";
|
||||
import browser from "webextension-polyfill";
|
||||
import LogoLightOutline from "@/resources/icons/betterseqta-light-outline.png";
|
||||
import { animate, stagger } from "motion";
|
||||
|
||||
export async function SendNewsPage() {
|
||||
console.info("[BetterSEQTA+] Started Loading News Page")
|
||||
document.title = "News ― SEQTA Learn"
|
||||
await delay(100)
|
||||
console.info("[BetterSEQTA+] Started Loading News Page");
|
||||
document.title = "News ― SEQTA Learn";
|
||||
await delay(100);
|
||||
|
||||
const element = document.querySelector("[data-key=news]")
|
||||
element!.classList.add("active")
|
||||
const element = document.querySelector("[data-key=news]");
|
||||
element!.classList.add("active");
|
||||
|
||||
// Remove all current elements in the main div to add new elements
|
||||
const main = document.getElementById("main")
|
||||
main!.innerHTML = ""
|
||||
const main = document.getElementById("main");
|
||||
main!.innerHTML = "";
|
||||
|
||||
const html = stringToHTML(/* html */ `
|
||||
<div class="home-root">
|
||||
<div class="home-container" id="news-container">
|
||||
<h1 class="border">Latest Headlines in ${settingsState.newsSource ? settingsState.newsSource.charAt(0).toUpperCase() + settingsState.newsSource.slice(1) : "Australia"}</h1>
|
||||
</div>
|
||||
</div>`)
|
||||
</div>`);
|
||||
|
||||
main!.append(html.firstChild!)
|
||||
main!.append(html.firstChild!);
|
||||
|
||||
const titlediv = document.getElementById("title")!.firstChild
|
||||
;(titlediv! as HTMLElement).innerText = "News"
|
||||
AppendLoadingSymbol("newsloading", "#news-container")
|
||||
const titlediv = document.getElementById("title")!.firstChild;
|
||||
(titlediv! as HTMLElement).innerText = "News";
|
||||
AppendLoadingSymbol("newsloading", "#news-container");
|
||||
|
||||
const response = (await browser.runtime.sendMessage({
|
||||
type: "sendNews",
|
||||
source: settingsState.newsSource,
|
||||
})) as any
|
||||
const newscontainer = document.querySelector("#news-container")
|
||||
document.getElementById("newsloading")?.remove()
|
||||
})) as any;
|
||||
const newscontainer = document.querySelector("#news-container");
|
||||
document.getElementById("newsloading")?.remove();
|
||||
|
||||
// Create a document fragment to batch DOM operations
|
||||
const fragment = document.createDocumentFragment()
|
||||
const fragment = document.createDocumentFragment();
|
||||
|
||||
// Map over articles to create elements
|
||||
response.news.articles.forEach((article: any) => {
|
||||
const newsarticle = document.createElement("a")
|
||||
newsarticle.classList.add("NewsArticle")
|
||||
newsarticle.href = article.url
|
||||
newsarticle.target = "_blank"
|
||||
const newsarticle = document.createElement("a");
|
||||
newsarticle.classList.add("NewsArticle");
|
||||
newsarticle.href = article.url;
|
||||
newsarticle.target = "_blank";
|
||||
|
||||
const articleimage = document.createElement("div")
|
||||
articleimage.classList.add("articleimage")
|
||||
const articleimage = document.createElement("div");
|
||||
articleimage.classList.add("articleimage");
|
||||
|
||||
if (article.urlToImage == "null" || article.urlToImage == null) {
|
||||
articleimage.style.cssText = `
|
||||
background-image: url(${browser.runtime.getURL(LogoLightOutline)});
|
||||
width: 20%;
|
||||
margin: 0 7.5%;
|
||||
`
|
||||
`;
|
||||
} else {
|
||||
articleimage.style.backgroundImage = `url(${article.urlToImage})`
|
||||
articleimage.style.backgroundImage = `url(${article.urlToImage})`;
|
||||
}
|
||||
|
||||
const articletext = document.createElement("div")
|
||||
articletext.classList.add("ArticleText")
|
||||
const articletext = document.createElement("div");
|
||||
articletext.classList.add("ArticleText");
|
||||
|
||||
const title = document.createElement("a")
|
||||
title.innerText = article.title
|
||||
title.href = article.url
|
||||
title.target = "_blank"
|
||||
const title = document.createElement("a");
|
||||
title.innerText = article.title;
|
||||
title.href = article.url;
|
||||
title.target = "_blank";
|
||||
|
||||
const description = document.createElement("p")
|
||||
const description = document.createElement("p");
|
||||
|
||||
article.description =
|
||||
article.description.length > 400
|
||||
? article.description.substring(0, 400) + "..."
|
||||
: article.description
|
||||
description.innerHTML = article.description
|
||||
: article.description;
|
||||
description.innerHTML = article.description;
|
||||
|
||||
articletext.append(title, description)
|
||||
newsarticle.append(articleimage, articletext)
|
||||
fragment.append(newsarticle)
|
||||
})
|
||||
articletext.append(title, description);
|
||||
newsarticle.append(articleimage, articletext);
|
||||
fragment.append(newsarticle);
|
||||
});
|
||||
|
||||
// Single DOM update to append all articles
|
||||
newscontainer?.append(fragment)
|
||||
newscontainer?.append(fragment);
|
||||
|
||||
if (!settingsState.animations) return
|
||||
if (!settingsState.animations) return;
|
||||
|
||||
const articles = Array.from(document.querySelectorAll(".NewsArticle"))
|
||||
const articles = Array.from(document.querySelectorAll(".NewsArticle"));
|
||||
|
||||
animate(
|
||||
articles.slice(0, 20),
|
||||
@@ -99,5 +99,5 @@ export async function SendNewsPage() {
|
||||
damping: 20,
|
||||
mass: 1,
|
||||
},
|
||||
)
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
+101
-101
@@ -1,16 +1,16 @@
|
||||
import { settingsState } from "./listeners/SettingsState"
|
||||
import { animate, stagger } from "motion"
|
||||
import stringToHTML from "./stringToHTML"
|
||||
import browser from "webextension-polyfill"
|
||||
import kofi from "@/resources/kofi.png?base64"
|
||||
import { settingsState } from "./listeners/SettingsState";
|
||||
import { animate, stagger } from "motion";
|
||||
import stringToHTML from "./stringToHTML";
|
||||
import browser from "webextension-polyfill";
|
||||
import kofi from "@/resources/kofi.png?base64";
|
||||
|
||||
export async function DeleteWhatsNew() {
|
||||
const bkelement = document.getElementById("whatsnewbk")
|
||||
const popup = document.getElementsByClassName("whatsnewContainer")[0]
|
||||
const bkelement = document.getElementById("whatsnewbk");
|
||||
const popup = document.getElementsByClassName("whatsnewContainer")[0];
|
||||
|
||||
if (!settingsState.animations) {
|
||||
bkelement?.remove()
|
||||
return
|
||||
bkelement?.remove();
|
||||
return;
|
||||
}
|
||||
|
||||
animate(
|
||||
@@ -18,47 +18,47 @@ export async function DeleteWhatsNew() {
|
||||
{ opacity: [1, 0], scale: [1, 0] },
|
||||
{ ease: [0.22, 0.03, 0.26, 1] },
|
||||
).then(() => {
|
||||
bkelement?.remove()
|
||||
})
|
||||
bkelement?.remove();
|
||||
});
|
||||
}
|
||||
|
||||
export function OpenWhatsNewPopup() {
|
||||
const background = document.createElement("div")
|
||||
background.id = "whatsnewbk"
|
||||
background.classList.add("whatsnewBackground")
|
||||
|
||||
const container = document.createElement("div")
|
||||
container.classList.add("whatsnewContainer")
|
||||
|
||||
var header: any = stringToHTML(
|
||||
/* html */
|
||||
`<div class="whatsnewHeader">
|
||||
const background = document.createElement("div");
|
||||
background.id = "whatsnewbk";
|
||||
background.classList.add("whatsnewBackground");
|
||||
|
||||
const container = document.createElement("div");
|
||||
container.classList.add("whatsnewContainer");
|
||||
|
||||
var header: any = stringToHTML(
|
||||
/* html */
|
||||
`<div class="whatsnewHeader">
|
||||
<h1>What's New</h1>
|
||||
<p>BetterSEQTA+ V${browser.runtime.getManifest().version}</p>
|
||||
</div>`,
|
||||
).firstChild
|
||||
|
||||
let imagecont = document.createElement("div")
|
||||
imagecont.classList.add("whatsnewImgContainer")
|
||||
|
||||
let video = document.createElement("video")
|
||||
let source = document.createElement("source")
|
||||
|
||||
source.setAttribute(
|
||||
"src",
|
||||
"https://raw.githubusercontent.com/BetterSEQTA/BetterSEQTA-Plus/main/src/resources/update-video.mp4",
|
||||
)
|
||||
video.autoplay = true
|
||||
video.muted = true
|
||||
video.loop = true
|
||||
video.appendChild(source)
|
||||
video.classList.add("whatsnewImg")
|
||||
imagecont.appendChild(video)
|
||||
|
||||
let textcontainer = document.createElement("div")
|
||||
textcontainer.classList.add("whatsnewTextContainer")
|
||||
|
||||
let text = stringToHTML(/* html */ `
|
||||
).firstChild;
|
||||
|
||||
let imagecont = document.createElement("div");
|
||||
imagecont.classList.add("whatsnewImgContainer");
|
||||
|
||||
let video = document.createElement("video");
|
||||
let source = document.createElement("source");
|
||||
|
||||
source.setAttribute(
|
||||
"src",
|
||||
"https://raw.githubusercontent.com/BetterSEQTA/BetterSEQTA-Plus/main/src/resources/update-video.mp4",
|
||||
);
|
||||
video.autoplay = true;
|
||||
video.muted = true;
|
||||
video.loop = true;
|
||||
video.appendChild(source);
|
||||
video.classList.add("whatsnewImg");
|
||||
imagecont.appendChild(video);
|
||||
|
||||
let textcontainer = document.createElement("div");
|
||||
textcontainer.classList.add("whatsnewTextContainer");
|
||||
|
||||
let text = stringToHTML(/* html */ `
|
||||
<div class="whatsnewTextContainer" style="height: 50%;overflow-y: scroll;">
|
||||
<h1>3.4.6.1 - Hot patch!</h1>
|
||||
<li>Fixed storage not updating and sometimes being replaced with default values</li>
|
||||
@@ -238,9 +238,9 @@ export function OpenWhatsNewPopup() {
|
||||
<h1>Create Custom Shortcuts</h1>
|
||||
<li>Found in the BetterSEQTA+ Settings menu, custom shortcuts can now be created with a name and URL of your choice.</li>
|
||||
</div>
|
||||
`).firstChild
|
||||
|
||||
let footer = stringToHTML(/* html */ `
|
||||
`).firstChild;
|
||||
|
||||
let footer = stringToHTML(/* html */ `
|
||||
<div class="whatsnewFooter">
|
||||
<div>
|
||||
Report bugs and feedback:
|
||||
@@ -267,58 +267,58 @@ export function OpenWhatsNewPopup() {
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
`).firstChild
|
||||
|
||||
let exitbutton = document.createElement("div")
|
||||
exitbutton.id = "whatsnewclosebutton"
|
||||
|
||||
container.append(header)
|
||||
container.append(imagecont)
|
||||
container.append(textcontainer)
|
||||
container.append(text as ChildNode)
|
||||
container.append(footer as ChildNode)
|
||||
container.append(exitbutton)
|
||||
|
||||
background.append(container)
|
||||
|
||||
document.getElementById("container")!.append(background)
|
||||
|
||||
let bkelement = document.getElementById("whatsnewbk")
|
||||
let popup = document.getElementsByClassName("whatsnewContainer")[0]
|
||||
|
||||
if (settingsState.animations) {
|
||||
animate(
|
||||
[popup, bkelement as HTMLElement],
|
||||
{ scale: [0, 1] },
|
||||
{
|
||||
type: "spring",
|
||||
stiffness: 220,
|
||||
damping: 18,
|
||||
},
|
||||
)
|
||||
|
||||
animate(
|
||||
".whatsnewTextContainer *",
|
||||
{ opacity: [0, 1], y: [10, 0] },
|
||||
{
|
||||
delay: stagger(0.05, { startDelay: 0.1 }),
|
||||
duration: 0.5,
|
||||
ease: [0.22, 0.03, 0.26, 1],
|
||||
},
|
||||
)
|
||||
`).firstChild;
|
||||
|
||||
let exitbutton = document.createElement("div");
|
||||
exitbutton.id = "whatsnewclosebutton";
|
||||
|
||||
container.append(header);
|
||||
container.append(imagecont);
|
||||
container.append(textcontainer);
|
||||
container.append(text as ChildNode);
|
||||
container.append(footer as ChildNode);
|
||||
container.append(exitbutton);
|
||||
|
||||
background.append(container);
|
||||
|
||||
document.getElementById("container")!.append(background);
|
||||
|
||||
let bkelement = document.getElementById("whatsnewbk");
|
||||
let popup = document.getElementsByClassName("whatsnewContainer")[0];
|
||||
|
||||
if (settingsState.animations) {
|
||||
animate(
|
||||
[popup, bkelement as HTMLElement],
|
||||
{ scale: [0, 1] },
|
||||
{
|
||||
type: "spring",
|
||||
stiffness: 220,
|
||||
damping: 18,
|
||||
},
|
||||
);
|
||||
|
||||
animate(
|
||||
".whatsnewTextContainer *",
|
||||
{ opacity: [0, 1], y: [10, 0] },
|
||||
{
|
||||
delay: stagger(0.05, { startDelay: 0.1 }),
|
||||
duration: 0.5,
|
||||
ease: [0.22, 0.03, 0.26, 1],
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
delete settingsState.justupdated;
|
||||
|
||||
bkelement!.addEventListener("click", function (event) {
|
||||
// Check if the click event originated from the element itself and not any of its children
|
||||
if (event.target === bkelement) {
|
||||
DeleteWhatsNew();
|
||||
}
|
||||
|
||||
delete settingsState.justupdated
|
||||
|
||||
bkelement!.addEventListener("click", function (event) {
|
||||
// Check if the click event originated from the element itself and not any of its children
|
||||
if (event.target === bkelement) {
|
||||
DeleteWhatsNew()
|
||||
}
|
||||
})
|
||||
|
||||
var closeelement = document.getElementById("whatsnewclosebutton")
|
||||
closeelement!.addEventListener("click", function () {
|
||||
DeleteWhatsNew()
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
var closeelement = document.getElementById("whatsnewclosebutton");
|
||||
closeelement!.addEventListener("click", function () {
|
||||
DeleteWhatsNew();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const base64ToBlob = (base64: string, contentType: string = ''): Blob => {
|
||||
const base64ToBlob = (base64: string, contentType: string = ""): Blob => {
|
||||
const byteCharacters = atob(base64);
|
||||
const byteArrays: Uint8Array[] = [];
|
||||
|
||||
@@ -14,4 +14,4 @@ const base64ToBlob = (base64: string, contentType: string = ''): Blob => {
|
||||
return new Blob(byteArrays, { type: contentType });
|
||||
};
|
||||
|
||||
export default base64ToBlob;
|
||||
export default base64ToBlob;
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
export function convertTo12HourFormat(
|
||||
time: string,
|
||||
noMinutes: boolean = false,
|
||||
): string {
|
||||
let [hours, minutes] = time.split(":").map(Number)
|
||||
let period = "AM"
|
||||
|
||||
if (hours >= 12) {
|
||||
period = "PM"
|
||||
if (hours > 12) hours -= 12
|
||||
} else if (hours === 0) {
|
||||
hours = 12
|
||||
}
|
||||
|
||||
let hoursStr = hours.toString()
|
||||
if (hoursStr.length === 2 && hoursStr.startsWith("0")) {
|
||||
hoursStr = hoursStr.substring(1)
|
||||
}
|
||||
|
||||
return `${hoursStr}${noMinutes ? "" : `:${minutes.toString().padStart(2, "0")}`} ${period}`
|
||||
}
|
||||
time: string,
|
||||
noMinutes: boolean = false,
|
||||
): string {
|
||||
let [hours, minutes] = time.split(":").map(Number);
|
||||
let period = "AM";
|
||||
|
||||
if (hours >= 12) {
|
||||
period = "PM";
|
||||
if (hours > 12) hours -= 12;
|
||||
} else if (hours === 0) {
|
||||
hours = 12;
|
||||
}
|
||||
|
||||
let hoursStr = hours.toString();
|
||||
if (hoursStr.length === 2 && hoursStr.startsWith("0")) {
|
||||
hoursStr = hoursStr.substring(1);
|
||||
}
|
||||
|
||||
return `${hoursStr}${noMinutes ? "" : `:${minutes.toString().padStart(2, "0")}`} ${period}`;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
export default function debounce<T extends (...args: any[]) => void>(fn: T, delay: number): (...args: Parameters<T>) => void {
|
||||
export default function debounce<T extends (...args: any[]) => void>(
|
||||
fn: T,
|
||||
delay: number,
|
||||
): (...args: Parameters<T>) => void {
|
||||
let timeout: ReturnType<typeof setTimeout>;
|
||||
return function(this: ThisParameterType<T>, ...args: Parameters<T>) {
|
||||
return function (this: ThisParameterType<T>, ...args: Parameters<T>) {
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(() => fn.apply(this, args), delay);
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export function base64toblobURL(base64: string) {
|
||||
// Extract base64 data from the data URI
|
||||
const base64Index = base64.indexOf(',') + 1;
|
||||
const base64Index = base64.indexOf(",") + 1;
|
||||
const imageBase64 = base64.substring(base64Index);
|
||||
|
||||
// Convert base64 to blob
|
||||
@@ -10,10 +10,10 @@ export function base64toblobURL(base64: string) {
|
||||
byteNumbers[i] = byteCharacters.charCodeAt(i);
|
||||
}
|
||||
const byteArray = new Uint8Array(byteNumbers);
|
||||
const blob = new Blob([byteArray], { type: 'image/png' });
|
||||
const blob = new Blob([byteArray], { type: "image/png" });
|
||||
|
||||
// Convert blob to blob URL
|
||||
const imageUrl = URL.createObjectURL(blob);
|
||||
|
||||
return imageUrl;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,28 +1,37 @@
|
||||
import { waitForElm } from "@/seqta/utils/waitForElm"
|
||||
import { waitForElm } from "@/seqta/utils/waitForElm";
|
||||
import ReactFiber from "../ReactFiber";
|
||||
|
||||
const handleNotificationClick = async (target: HTMLElement) => {
|
||||
const notificationItem = target.closest('[class*="notifications__item___"]') as HTMLElement | null;
|
||||
const notificationItem = target.closest(
|
||||
'[class*="notifications__item___"]',
|
||||
) as HTMLElement | null;
|
||||
if (!notificationItem) return;
|
||||
|
||||
const buttonType = notificationItem.getAttribute('data-type');
|
||||
if (buttonType !== 'message') return;
|
||||
const buttonType = notificationItem.getAttribute("data-type");
|
||||
if (buttonType !== "message") return;
|
||||
|
||||
const notificationList = await ReactFiber.find('[class*="notifications__list___"]').getState();
|
||||
const buttonId = notificationItem.getAttribute('data-id');
|
||||
const notificationList = await ReactFiber.find(
|
||||
'[class*="notifications__list___"]',
|
||||
).getState();
|
||||
const buttonId = notificationItem.getAttribute("data-id");
|
||||
if (!buttonId) return;
|
||||
|
||||
const matchingNotification = notificationList.storeState.notifications.items.find(
|
||||
(item: any) => item.notificationID === parseInt(buttonId)
|
||||
);
|
||||
const matchingNotification =
|
||||
notificationList.storeState.notifications.items.find(
|
||||
(item: any) => item.notificationID === parseInt(buttonId),
|
||||
);
|
||||
|
||||
await waitForElm('[class*="Viewer__Viewer___"] > div', true, 20);
|
||||
|
||||
// Select the specific direct message
|
||||
ReactFiber.find('[class*="Viewer__Viewer___"] > div').setState({ selected: new Set([matchingNotification.message.messageID]) });
|
||||
ReactFiber.find('[class*="Viewer__Viewer___"] > div').setState({
|
||||
selected: new Set([matchingNotification.message.messageID]),
|
||||
});
|
||||
|
||||
// Close the notifications panel
|
||||
const notificationButton = document.querySelector('[class*="notifications__notifications___"] > button') as HTMLButtonElement | null;
|
||||
const notificationButton = document.querySelector(
|
||||
'[class*="notifications__notifications___"] > button',
|
||||
) as HTMLButtonElement | null;
|
||||
notificationButton?.click();
|
||||
};
|
||||
|
||||
@@ -33,10 +42,10 @@ const clickListeners = [
|
||||
},
|
||||
];
|
||||
|
||||
const registerClickListeners = () => {
|
||||
document.addEventListener('click', (e) => {
|
||||
const registerClickListeners = () => {
|
||||
document.addEventListener("click", (e) => {
|
||||
const target = e.target as HTMLElement;
|
||||
|
||||
|
||||
clickListeners.forEach(({ selector, handler }) => {
|
||||
if (target.closest(selector)) {
|
||||
handler(target);
|
||||
|
||||
@@ -39,28 +39,37 @@ class EventManager {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public register(event: string, options: EventListenerOptions, callback: (element: Element) => void): { unregister: () => void } {
|
||||
public register(
|
||||
event: string,
|
||||
options: EventListenerOptions,
|
||||
callback: (element: Element) => void,
|
||||
): { unregister: () => void } {
|
||||
const id = this.generateUniqueId();
|
||||
if (!this.listeners.has(event)) {
|
||||
this.listeners.set(event, []);
|
||||
}
|
||||
const unregister = () => this.unregisterById(event, id);
|
||||
this.listeners.get(event)!.push({ id, options, callback, unregister });
|
||||
|
||||
|
||||
this.scanExistingElements(options, callback);
|
||||
|
||||
|
||||
this.startObserving(options.parentElement);
|
||||
return { unregister };
|
||||
}
|
||||
|
||||
private async scanExistingElements(options: EventListenerOptions, callback: (element: Element) => void): Promise<void> {
|
||||
private async scanExistingElements(
|
||||
options: EventListenerOptions,
|
||||
callback: (element: Element) => void,
|
||||
): Promise<void> {
|
||||
const root = options.parentElement || document.documentElement;
|
||||
const elements = Array.from(root.getElementsByTagName('*'));
|
||||
const elements = Array.from(root.getElementsByTagName("*"));
|
||||
elements.unshift(root);
|
||||
|
||||
|
||||
for (let i = 0; i < elements.length; i += this.chunkSize) {
|
||||
const chunk = elements.slice(i, i + this.chunkSize);
|
||||
const filteredChunk = chunk.filter(element => this.matchesOptions(element, options));
|
||||
const filteredChunk = chunk.filter((element) =>
|
||||
this.matchesOptions(element, options),
|
||||
);
|
||||
for (const element of filteredChunk) {
|
||||
callback(element);
|
||||
}
|
||||
@@ -76,7 +85,10 @@ class EventManager {
|
||||
private unregisterById(event: string, id: string): void {
|
||||
if (this.listeners.has(event)) {
|
||||
const listeners = this.listeners.get(event)!;
|
||||
this.listeners.set(event, listeners.filter(listener => listener.id !== id));
|
||||
this.listeners.set(
|
||||
event,
|
||||
listeners.filter((listener) => listener.id !== id),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,9 +105,9 @@ class EventManager {
|
||||
}
|
||||
|
||||
private handleMutations(mutations: MutationRecord[]): void {
|
||||
mutations.forEach(mutation => {
|
||||
if (mutation.type === 'childList') {
|
||||
mutation.addedNodes.forEach(node => {
|
||||
mutations.forEach((mutation) => {
|
||||
if (mutation.type === "childList") {
|
||||
mutation.addedNodes.forEach((node) => {
|
||||
if (node.nodeType === Node.ELEMENT_NODE) {
|
||||
this.pendingElements.add(node as Element);
|
||||
}
|
||||
@@ -148,19 +160,29 @@ class EventManager {
|
||||
}
|
||||
}
|
||||
|
||||
private matchesOptions(element: Element, options: EventListenerOptions): boolean {
|
||||
if (options.elementType && element.tagName.toLowerCase() !== options.elementType.toLowerCase()) return false;
|
||||
if (options.textContent && element.textContent !== options.textContent) return false;
|
||||
if (options.className && !element.classList.contains(options.className)) return false;
|
||||
private matchesOptions(
|
||||
element: Element,
|
||||
options: EventListenerOptions,
|
||||
): boolean {
|
||||
if (
|
||||
options.elementType &&
|
||||
element.tagName.toLowerCase() !== options.elementType.toLowerCase()
|
||||
)
|
||||
return false;
|
||||
if (options.textContent && element.textContent !== options.textContent)
|
||||
return false;
|
||||
if (options.className && !element.classList.contains(options.className))
|
||||
return false;
|
||||
if (options.id && element.id !== options.id) return false;
|
||||
if (options.customCheck && !options.customCheck(element)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
private generateUniqueId(): string {
|
||||
return '_' + Math.random().toString(36).substr(2, 9);
|
||||
return "_" + Math.random().toString(36).substr(2, 9);
|
||||
}
|
||||
}
|
||||
|
||||
export const eventManager = EventManager.getInstance();
|
||||
export const initializeEventManager = async () => await EventManager.initialize();
|
||||
export const initializeEventManager = async () =>
|
||||
await EventManager.initialize();
|
||||
|
||||
@@ -1,12 +1,18 @@
|
||||
import browser from 'webextension-polyfill'
|
||||
import browser from "webextension-polyfill";
|
||||
|
||||
import { closeExtensionPopup } from "@/seqta/utils/Closers/closeExtensionPopup"
|
||||
import { MenuOptionsOpen, OpenMenuOptions } from "@/seqta/utils/Openers/OpenMenuOptions"
|
||||
import { closeExtensionPopup } from "@/seqta/utils/Closers/closeExtensionPopup";
|
||||
import {
|
||||
MenuOptionsOpen,
|
||||
OpenMenuOptions,
|
||||
} from "@/seqta/utils/Openers/OpenMenuOptions";
|
||||
|
||||
import { CloseThemeCreator, OpenThemeCreator } from '@/plugins/built-in/themes/ThemeCreator';
|
||||
import sendThemeUpdate from '@/seqta/utils/sendThemeUpdate';
|
||||
import hideSensitiveContent from '@/seqta/ui/dev/hideSensitiveContent';
|
||||
import { ThemeManager } from '@/plugins/built-in/themes/theme-manager';
|
||||
import {
|
||||
CloseThemeCreator,
|
||||
OpenThemeCreator,
|
||||
} from "@/plugins/built-in/themes/ThemeCreator";
|
||||
import sendThemeUpdate from "@/seqta/utils/sendThemeUpdate";
|
||||
import hideSensitiveContent from "@/seqta/ui/dev/hideSensitiveContent";
|
||||
import { ThemeManager } from "@/plugins/built-in/themes/theme-manager";
|
||||
|
||||
const themeManager = ThemeManager.getInstance();
|
||||
|
||||
@@ -16,93 +22,93 @@ export class MessageHandler {
|
||||
browser.runtime.onMessage.addListener(this.routeMessage.bind(this));
|
||||
}
|
||||
routeMessage(request: any, _sender: any, sendResponse: any) {
|
||||
console.debug('Message received:', request)
|
||||
|
||||
console.debug("Message received:", request);
|
||||
|
||||
switch (request.info) {
|
||||
case 'EditSidebar':
|
||||
case "EditSidebar":
|
||||
this.editSidebar();
|
||||
closeExtensionPopup();
|
||||
sendResponse({ status: 'success' });
|
||||
sendResponse({ status: "success" });
|
||||
break;
|
||||
|
||||
case 'UpdateThemePreview':
|
||||
|
||||
case "UpdateThemePreview":
|
||||
if (request?.save == true) {
|
||||
const save = async () => {
|
||||
await themeManager.saveTheme(request.body)
|
||||
await themeManager.saveTheme(request.body);
|
||||
if (request.body.enableTheme) {
|
||||
await themeManager.setTheme(request.body.id)
|
||||
await themeManager.setTheme(request.body.id);
|
||||
}
|
||||
sendResponse({ status: 'success' })
|
||||
sendThemeUpdate()
|
||||
}
|
||||
save()
|
||||
sendResponse({ status: "success" });
|
||||
sendThemeUpdate();
|
||||
};
|
||||
save();
|
||||
} else {
|
||||
themeManager.updatePreview(request.body);
|
||||
sendResponse({ status: 'success' });
|
||||
sendResponse({ status: "success" });
|
||||
}
|
||||
return true;
|
||||
|
||||
case 'GetTheme':
|
||||
|
||||
case "GetTheme":
|
||||
themeManager.getTheme(request.body.themeID).then((theme) => {
|
||||
sendResponse(theme);
|
||||
});
|
||||
return true;
|
||||
|
||||
case 'SetTheme':
|
||||
|
||||
case "SetTheme":
|
||||
themeManager.setTheme(request.body.themeID).then(() => {
|
||||
sendResponse({ status: 'success' });
|
||||
});
|
||||
break;
|
||||
|
||||
case 'DisableTheme':
|
||||
themeManager.disableTheme().then(() => {
|
||||
sendResponse({ status: 'success' });
|
||||
});
|
||||
break;
|
||||
|
||||
case 'DeleteTheme':
|
||||
themeManager.deleteTheme(request.body.themeID).then(() => {
|
||||
sendResponse({ status: 'success' });
|
||||
sendResponse({ status: "success" });
|
||||
});
|
||||
break;
|
||||
|
||||
case 'ListThemes':
|
||||
case "DisableTheme":
|
||||
themeManager.disableTheme().then(() => {
|
||||
sendResponse({ status: "success" });
|
||||
});
|
||||
break;
|
||||
|
||||
case "DeleteTheme":
|
||||
themeManager.deleteTheme(request.body.themeID).then(() => {
|
||||
sendResponse({ status: "success" });
|
||||
});
|
||||
break;
|
||||
|
||||
case "ListThemes":
|
||||
themeManager.getAvailableThemes().then((themes) => {
|
||||
sendResponse(themes);
|
||||
});
|
||||
return true;
|
||||
|
||||
case 'OpenThemeCreator':
|
||||
case "OpenThemeCreator":
|
||||
const themeID = request?.body?.themeID;
|
||||
OpenThemeCreator( themeID ? themeID : '' );
|
||||
OpenThemeCreator(themeID ? themeID : "");
|
||||
closeExtensionPopup();
|
||||
sendResponse({ status: 'success' });
|
||||
sendResponse({ status: "success" });
|
||||
break;
|
||||
|
||||
case 'ShareTheme':
|
||||
|
||||
case "ShareTheme":
|
||||
themeManager.shareTheme(request.body.themeID).then((id) => {
|
||||
sendResponse({ status: 'success', id });
|
||||
sendResponse({ status: "success", id });
|
||||
});
|
||||
return true;
|
||||
|
||||
case 'CloseThemeCreator':
|
||||
case "CloseThemeCreator":
|
||||
try {
|
||||
CloseThemeCreator();
|
||||
} catch (error) {
|
||||
console.error('Error closing theme creator:', error);
|
||||
sendResponse({ status: 'error' });
|
||||
console.error("Error closing theme creator:", error);
|
||||
sendResponse({ status: "error" });
|
||||
}
|
||||
sendResponse({ status: 'success' });
|
||||
sendResponse({ status: "success" });
|
||||
break;
|
||||
|
||||
case 'HideSensitive':
|
||||
case "HideSensitive":
|
||||
hideSensitiveContent();
|
||||
sendResponse({ status: 'success' });
|
||||
sendResponse({ status: "success" });
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
console.debug('Unknown request info:', request.info);
|
||||
}
|
||||
console.debug("Unknown request info:", request.info);
|
||||
}
|
||||
}
|
||||
|
||||
editSidebar() {
|
||||
@@ -110,4 +116,4 @@ export class MessageHandler {
|
||||
OpenMenuOptions();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import browser from 'webextension-polyfill';
|
||||
import type { SettingsState } from '@/types/storage';
|
||||
import type { Subscriber, Unsubscriber } from 'svelte/store';
|
||||
import browser from "webextension-polyfill";
|
||||
import type { SettingsState } from "@/types/storage";
|
||||
import type { Subscriber, Unsubscriber } from "svelte/store";
|
||||
|
||||
type ChangeListener = (newValue: any, oldValue: any) => void;
|
||||
type GlobalChangeListener = (newValue: any, oldValue: any, key: string) => void;
|
||||
@@ -19,7 +19,7 @@ class StorageManager {
|
||||
this.loadFromStorage();
|
||||
|
||||
const handler: ProxyHandler<StorageManager> = {
|
||||
get: (target, prop: keyof SettingsState | 'register' | 'initialize') => {
|
||||
get: (target, prop: keyof SettingsState | "register" | "initialize") => {
|
||||
if (prop in target) {
|
||||
return (target as any)[prop];
|
||||
}
|
||||
@@ -42,7 +42,7 @@ class StorageManager {
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
this.initStorageListener();
|
||||
@@ -63,7 +63,10 @@ class StorageManager {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public setKey<K extends keyof SettingsState>(key: K, value: SettingsState[K]): void {
|
||||
public setKey<K extends keyof SettingsState>(
|
||||
key: K,
|
||||
value: SettingsState[K],
|
||||
): void {
|
||||
this.data[key] = value;
|
||||
this.saveToStorage();
|
||||
}
|
||||
@@ -87,7 +90,7 @@ class StorageManager {
|
||||
|
||||
private initStorageListener(): void {
|
||||
browser.storage.onChanged.addListener((changes, areaName) => {
|
||||
if (areaName === 'local') {
|
||||
if (areaName === "local") {
|
||||
for (const [key, { oldValue, newValue }] of Object.entries(changes)) {
|
||||
if (newValue !== undefined) {
|
||||
(this.data as any)[key] = newValue;
|
||||
@@ -151,4 +154,5 @@ class StorageManager {
|
||||
}
|
||||
|
||||
export const settingsState = StorageManager.getInstance();
|
||||
export const initializeSettingsState = async () => await StorageManager.initialize();
|
||||
export const initializeSettingsState = async () =>
|
||||
await StorageManager.initialize();
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
import { settingsState } from './SettingsState';
|
||||
import { updateAllColors } from '@/seqta/ui/colors/Manager';
|
||||
|
||||
import { settingsState } from "./SettingsState";
|
||||
import { updateAllColors } from "@/seqta/ui/colors/Manager";
|
||||
|
||||
import { addShortcuts } from "@/seqta/utils/Adders/AddShortcuts";
|
||||
import { CreateCustomShortcutDiv } from "@/seqta/utils/CreateEnable/CreateCustomShortcutDiv";
|
||||
import { FilterUpcomingAssessments } from "@/seqta/utils/FilterUpcomingAssessments";
|
||||
import { RemoveShortcutDiv } from "@/seqta/utils/DisableRemove/RemoveShortcutDiv";
|
||||
|
||||
|
||||
import browser from 'webextension-polyfill';
|
||||
import type { CustomShortcut } from '@/types/storage';
|
||||
import browser from "webextension-polyfill";
|
||||
import type { CustomShortcut } from "@/types/storage";
|
||||
|
||||
export class StorageChangeHandler {
|
||||
constructor() {
|
||||
@@ -17,13 +15,22 @@ export class StorageChangeHandler {
|
||||
}
|
||||
|
||||
private registerHandlers() {
|
||||
settingsState.register('selectedColor', updateAllColors.bind(this));
|
||||
settingsState.register('DarkMode', this.handleDarkModeChange.bind(this));
|
||||
settingsState.register('onoff', this.handleOnOffChange.bind(this));
|
||||
settingsState.register('shortcuts', this.handleShortcutsChange.bind(this));
|
||||
settingsState.register('customshortcuts', this.handleCustomShortcutsChange.bind(this));
|
||||
settingsState.register('transparencyEffects', this.handleTransparencyEffectsChange.bind(this));
|
||||
settingsState.register('subjectfilters', FilterUpcomingAssessments.bind(this));
|
||||
settingsState.register("selectedColor", updateAllColors.bind(this));
|
||||
settingsState.register("DarkMode", this.handleDarkModeChange.bind(this));
|
||||
settingsState.register("onoff", this.handleOnOffChange.bind(this));
|
||||
settingsState.register("shortcuts", this.handleShortcutsChange.bind(this));
|
||||
settingsState.register(
|
||||
"customshortcuts",
|
||||
this.handleCustomShortcutsChange.bind(this),
|
||||
);
|
||||
settingsState.register(
|
||||
"transparencyEffects",
|
||||
this.handleTransparencyEffectsChange.bind(this),
|
||||
);
|
||||
settingsState.register(
|
||||
"subjectfilters",
|
||||
FilterUpcomingAssessments.bind(this),
|
||||
);
|
||||
}
|
||||
|
||||
private handleDarkModeChange() {
|
||||
@@ -32,16 +39,23 @@ export class StorageChangeHandler {
|
||||
|
||||
private handleOnOffChange(newValue: boolean) {
|
||||
if (newValue) return;
|
||||
browser.runtime.sendMessage({ type: 'reloadTabs' });
|
||||
browser.runtime.sendMessage({ type: "reloadTabs" });
|
||||
}
|
||||
|
||||
private handleCustomShortcutsChange(newValue: CustomShortcut[], oldValue: CustomShortcut[]) {
|
||||
private handleCustomShortcutsChange(
|
||||
newValue: CustomShortcut[],
|
||||
oldValue: CustomShortcut[],
|
||||
) {
|
||||
if (newValue) {
|
||||
if (newValue.length > oldValue.length) {
|
||||
CreateCustomShortcutDiv(newValue[oldValue.length]);
|
||||
} else if (newValue.length < oldValue.length) {
|
||||
const removedElement = oldValue.find(
|
||||
(oldItem: any) => !newValue.some((newItem: any) => JSON.stringify(oldItem) === JSON.stringify(newItem))
|
||||
(oldItem: any) =>
|
||||
!newValue.some(
|
||||
(newItem: any) =>
|
||||
JSON.stringify(oldItem) === JSON.stringify(newItem),
|
||||
),
|
||||
);
|
||||
|
||||
if (removedElement) {
|
||||
@@ -51,7 +65,10 @@ export class StorageChangeHandler {
|
||||
}
|
||||
}
|
||||
|
||||
private handleShortcutsChange(newValue: { enabled: boolean, name: string }[], oldValue: { enabled: boolean, name: string }[]) {
|
||||
private handleShortcutsChange(
|
||||
newValue: { enabled: boolean; name: string }[],
|
||||
oldValue: { enabled: boolean; name: string }[],
|
||||
) {
|
||||
const addedShortcuts = newValue.filter((newItem: any) => {
|
||||
const isAdded = oldValue.some((oldItem: any) => {
|
||||
const match = oldItem.name === newItem.name;
|
||||
@@ -80,9 +97,9 @@ export class StorageChangeHandler {
|
||||
|
||||
private handleTransparencyEffectsChange(newValue: boolean) {
|
||||
if (newValue) {
|
||||
document.documentElement.classList.add('transparencyEffects');
|
||||
document.documentElement.classList.add("transparencyEffects");
|
||||
} else {
|
||||
document.documentElement.classList.remove('transparencyEffects');
|
||||
document.documentElement.classList.remove("transparencyEffects");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,4 +7,4 @@
|
||||
<body>
|
||||
<script type="module" src="./migration-iframe.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
interface Data {
|
||||
id: string;
|
||||
blob: Blob;
|
||||
type: 'image' | 'video';
|
||||
type: "image" | "video";
|
||||
}
|
||||
|
||||
const openDB = (): Promise<IDBDatabase> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const request = indexedDB.open('MyDatabase', 1);
|
||||
const request = indexedDB.open("MyDatabase", 1);
|
||||
request.onerror = () => reject(request.error);
|
||||
request.onsuccess = () => resolve(request.result);
|
||||
});
|
||||
@@ -18,7 +18,7 @@ const blobToBase64 = (blob: Blob): Promise<string> => {
|
||||
const reader = new FileReader();
|
||||
reader.onloadend = () => {
|
||||
const base64 = reader.result as string;
|
||||
resolve(base64.split(',')[1]); // Remove data URL prefix
|
||||
resolve(base64.split(",")[1]); // Remove data URL prefix
|
||||
};
|
||||
reader.onerror = () => reject(reader.error);
|
||||
reader.readAsDataURL(blob);
|
||||
@@ -27,8 +27,8 @@ const blobToBase64 = (blob: Blob): Promise<string> => {
|
||||
|
||||
const getAllBackgrounds = async (): Promise<Data[]> => {
|
||||
const db = await openDB();
|
||||
const tx = db.transaction('backgrounds', 'readonly');
|
||||
const store = tx.objectStore('backgrounds');
|
||||
const tx = db.transaction("backgrounds", "readonly");
|
||||
const store = tx.objectStore("backgrounds");
|
||||
const request = store.getAll();
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
@@ -38,88 +38,100 @@ const getAllBackgrounds = async (): Promise<Data[]> => {
|
||||
};
|
||||
|
||||
const getSelectedBackground = (): string | null => {
|
||||
return localStorage.getItem('selectedBackground');
|
||||
return localStorage.getItem("selectedBackground");
|
||||
};
|
||||
|
||||
const startMigration = async () => {
|
||||
try {
|
||||
console.info('Starting background extraction...');
|
||||
console.info("Starting background extraction...");
|
||||
let backgrounds: Data[];
|
||||
try {
|
||||
backgrounds = await getAllBackgrounds();
|
||||
if (!backgrounds || backgrounds.length === 0) {
|
||||
console.info('No backgrounds to migrate');
|
||||
window.parent.postMessage({ type: 'MIGRATION_COMPLETE' }, '*');
|
||||
console.info("No backgrounds to migrate");
|
||||
window.parent.postMessage({ type: "MIGRATION_COMPLETE" }, "*");
|
||||
return;
|
||||
}
|
||||
} catch (error: any) {
|
||||
if (error.name === 'NotFoundError' && error.message.includes('object stores was not found')) {
|
||||
console.info('No backgrounds to migrate: object store not found');
|
||||
window.parent.postMessage({ type: 'MIGRATION_COMPLETE' }, '*');
|
||||
if (
|
||||
error.name === "NotFoundError" &&
|
||||
error.message.includes("object stores was not found")
|
||||
) {
|
||||
console.info("No backgrounds to migrate: object store not found");
|
||||
window.parent.postMessage({ type: "MIGRATION_COMPLETE" }, "*");
|
||||
return;
|
||||
}
|
||||
console.error('Error fetching backgrounds:', error);
|
||||
throw new Error('Failed to fetch backgrounds');
|
||||
console.error("Error fetching backgrounds:", error);
|
||||
throw new Error("Failed to fetch backgrounds");
|
||||
}
|
||||
const selectedBackground = getSelectedBackground();
|
||||
console.info(`Found ${backgrounds.length} backgrounds`);
|
||||
|
||||
window.parent.postMessage({ type: 'GET_LAST_PROCESSED_ID' }, '*');
|
||||
window.parent.postMessage({ type: "GET_LAST_PROCESSED_ID" }, "*");
|
||||
|
||||
const lastProcessedId = await new Promise<string | null>(resolve => {
|
||||
const lastProcessedId = await new Promise<string | null>((resolve) => {
|
||||
const handler = (event: MessageEvent) => {
|
||||
if (event.data.type === 'LAST_PROCESSED_ID') {
|
||||
window.removeEventListener('message', handler);
|
||||
if (event.data.type === "LAST_PROCESSED_ID") {
|
||||
window.removeEventListener("message", handler);
|
||||
resolve(event.data.id);
|
||||
}
|
||||
};
|
||||
window.addEventListener('message', handler);
|
||||
window.addEventListener("message", handler);
|
||||
});
|
||||
|
||||
const remainingBackgrounds = lastProcessedId
|
||||
? backgrounds.slice(backgrounds.findIndex(b => b.id === lastProcessedId) + 1)
|
||||
const remainingBackgrounds = lastProcessedId
|
||||
? backgrounds.slice(
|
||||
backgrounds.findIndex((b) => b.id === lastProcessedId) + 1,
|
||||
)
|
||||
: backgrounds;
|
||||
|
||||
console.info(`Processing ${remainingBackgrounds.length} remaining backgrounds`);
|
||||
console.info(
|
||||
`Processing ${remainingBackgrounds.length} remaining backgrounds`,
|
||||
);
|
||||
|
||||
for (let i = 0; i < remainingBackgrounds.length; i++) {
|
||||
const background = remainingBackgrounds[i];
|
||||
const base64Data = await blobToBase64(background.blob);
|
||||
|
||||
window.parent.postMessage({
|
||||
type: 'BACKGROUND_DATA',
|
||||
payload: {
|
||||
id: background.id,
|
||||
data: base64Data,
|
||||
mediaType: background.type,
|
||||
total: backgrounds.length,
|
||||
processed: i + 1,
|
||||
isSelected: background.id === selectedBackground
|
||||
}
|
||||
}, '*');
|
||||
|
||||
await new Promise(resolve => setTimeout(resolve, 100));
|
||||
window.parent.postMessage(
|
||||
{
|
||||
type: "BACKGROUND_DATA",
|
||||
payload: {
|
||||
id: background.id,
|
||||
data: base64Data,
|
||||
mediaType: background.type,
|
||||
total: backgrounds.length,
|
||||
processed: i + 1,
|
||||
isSelected: background.id === selectedBackground,
|
||||
},
|
||||
},
|
||||
"*",
|
||||
);
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
}
|
||||
|
||||
window.parent.postMessage({ type: 'MIGRATION_COMPLETE' }, '*');
|
||||
|
||||
window.parent.postMessage({ type: "MIGRATION_COMPLETE" }, "*");
|
||||
} catch (error: any) {
|
||||
console.error('Extraction failed:', error);
|
||||
window.parent.postMessage({
|
||||
type: 'MIGRATION_ERROR',
|
||||
error: error.message || 'Unknown error'
|
||||
}, '*');
|
||||
console.error("Extraction failed:", error);
|
||||
window.parent.postMessage(
|
||||
{
|
||||
type: "MIGRATION_ERROR",
|
||||
error: error.message || "Unknown error",
|
||||
},
|
||||
"*",
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener('message', (event) => {
|
||||
window.addEventListener("message", (event) => {
|
||||
switch (event.data.type) {
|
||||
case 'PING':
|
||||
window.parent.postMessage({ type: 'PONG' }, '*');
|
||||
case "PING":
|
||||
window.parent.postMessage({ type: "PONG" }, "*");
|
||||
break;
|
||||
|
||||
case 'START_MIGRATION':
|
||||
|
||||
case "START_MIGRATION":
|
||||
startMigration();
|
||||
break;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -7,6 +7,6 @@ export class Mutex {
|
||||
|
||||
this.mutex = this.mutex.then(() => new Promise(begin));
|
||||
|
||||
return new Promise(res => begin = res);
|
||||
return new Promise((res) => (begin = res));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,4 +3,4 @@ export default function sendThemeUpdate() {
|
||||
if (iframe) {
|
||||
iframe.contentWindow?.postMessage({ type: 'themeChanged' }, '*');
|
||||
} */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,33 +1,37 @@
|
||||
import { changeSettingsClicked, closeExtensionPopup, SettingsClicked } from "./Closers/closeExtensionPopup"
|
||||
import { animate } from "motion"
|
||||
import { settingsState } from "./listeners/SettingsState"
|
||||
import {
|
||||
changeSettingsClicked,
|
||||
closeExtensionPopup,
|
||||
SettingsClicked,
|
||||
} from "./Closers/closeExtensionPopup";
|
||||
import { animate } from "motion";
|
||||
import { settingsState } from "./listeners/SettingsState";
|
||||
|
||||
export function setupSettingsButton() {
|
||||
var AddedSettings = document.getElementById("AddedSettings")
|
||||
var extensionPopup = document.getElementById("ExtensionPopup")
|
||||
|
||||
AddedSettings!.addEventListener("click", async () => {
|
||||
if (SettingsClicked) {
|
||||
closeExtensionPopup(extensionPopup as HTMLElement)
|
||||
var AddedSettings = document.getElementById("AddedSettings");
|
||||
var extensionPopup = document.getElementById("ExtensionPopup");
|
||||
|
||||
AddedSettings!.addEventListener("click", async () => {
|
||||
if (SettingsClicked) {
|
||||
closeExtensionPopup(extensionPopup as HTMLElement);
|
||||
} else {
|
||||
if (settingsState.animations) {
|
||||
animate(0, 1, {
|
||||
onUpdate: (progress) => {
|
||||
extensionPopup!.style.opacity = progress.toString();
|
||||
extensionPopup!.style.transform = `scale(${progress})`;
|
||||
},
|
||||
type: "spring",
|
||||
stiffness: 280,
|
||||
damping: 20,
|
||||
});
|
||||
} else {
|
||||
if (settingsState.animations) {
|
||||
animate(0, 1, {
|
||||
onUpdate: (progress) => {
|
||||
extensionPopup!.style.opacity = progress.toString()
|
||||
extensionPopup!.style.transform = `scale(${progress})`
|
||||
},
|
||||
type: "spring",
|
||||
stiffness: 280,
|
||||
damping: 20,
|
||||
})
|
||||
} else {
|
||||
extensionPopup!.style.opacity = "1"
|
||||
extensionPopup!.style.transform = "scale(1)"
|
||||
extensionPopup!.style.transition =
|
||||
"opacity 0s linear, transform 0s linear"
|
||||
}
|
||||
extensionPopup!.classList.remove("hide")
|
||||
changeSettingsClicked(true)
|
||||
extensionPopup!.style.opacity = "1";
|
||||
extensionPopup!.style.transform = "scale(1)";
|
||||
extensionPopup!.style.transition =
|
||||
"opacity 0s linear, transform 0s linear";
|
||||
}
|
||||
})
|
||||
}
|
||||
extensionPopup!.classList.remove("hide");
|
||||
changeSettingsClicked(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
import DOMPurify from 'dompurify';
|
||||
import DOMPurify from "dompurify";
|
||||
|
||||
export default function stringToHTML(str: string, styles = false) {
|
||||
const parser = new DOMParser();
|
||||
|
||||
|
||||
str = DOMPurify.sanitize(str, {
|
||||
ADD_ATTR: ['onclick'],
|
||||
ALLOWED_URI_REGEXP: /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|chrome-extension):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i
|
||||
ADD_ATTR: ["onclick"],
|
||||
ALLOWED_URI_REGEXP:
|
||||
/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|chrome-extension):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i,
|
||||
});
|
||||
|
||||
const doc = parser.parseFromString(str, 'text/html');
|
||||
const doc = parser.parseFromString(str, "text/html");
|
||||
|
||||
if (styles) {
|
||||
doc.body.style.cssText =
|
||||
'height: auto; overflow: scroll; margin: 0px; background: var(--background-primary);';
|
||||
"height: auto; overflow: scroll; margin: 0px; background: var(--background-primary);";
|
||||
}
|
||||
|
||||
return doc.body;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,75 +1,75 @@
|
||||
import { eventManager } from "@/seqta/utils/listeners/EventManager"
|
||||
import { delay } from "@/seqta/utils/delay"
|
||||
import { eventManager } from "@/seqta/utils/listeners/EventManager";
|
||||
import { delay } from "@/seqta/utils/delay";
|
||||
|
||||
export async function waitForElm(
|
||||
selector: string,
|
||||
usePolling: boolean = false,
|
||||
interval: number = 100,
|
||||
maxIterations?: number
|
||||
): Promise<Element> {
|
||||
if (usePolling) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let iterations = 0;
|
||||
if (maxIterations) {
|
||||
iterations = 0;
|
||||
}
|
||||
const checkForElement = () => {
|
||||
const element = document.querySelector(selector)
|
||||
if (element) {
|
||||
resolve(element)
|
||||
} else {
|
||||
if (maxIterations) {
|
||||
iterations++;
|
||||
if (iterations >= maxIterations) {
|
||||
reject(new Error("Element not found"));
|
||||
}
|
||||
}
|
||||
setTimeout(checkForElement, interval)
|
||||
}
|
||||
}
|
||||
|
||||
if (document.readyState === "loading") {
|
||||
document.addEventListener("DOMContentLoaded", checkForElement)
|
||||
} else {
|
||||
checkForElement()
|
||||
}
|
||||
})
|
||||
} else {
|
||||
return new Promise((resolve) => {
|
||||
const registerObserver = () => {
|
||||
const { unregister } = eventManager.register(
|
||||
`${selector}`,
|
||||
{
|
||||
customCheck: (element) => element.matches(selector),
|
||||
},
|
||||
async (element) => {
|
||||
resolve(element)
|
||||
await delay(1)
|
||||
unregister() // Remove the listener once the element is found
|
||||
},
|
||||
)
|
||||
return unregister
|
||||
}
|
||||
|
||||
let unregister = null
|
||||
|
||||
if (document.readyState === "loading") {
|
||||
// DOM is still loading, wait for it to be ready
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
unregister = registerObserver()
|
||||
})
|
||||
} else {
|
||||
unregister = registerObserver()
|
||||
}
|
||||
|
||||
const querySelector = () => document.querySelector(selector)
|
||||
const element = querySelector()
|
||||
|
||||
selector: string,
|
||||
usePolling: boolean = false,
|
||||
interval: number = 100,
|
||||
maxIterations?: number,
|
||||
): Promise<Element> {
|
||||
if (usePolling) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let iterations = 0;
|
||||
if (maxIterations) {
|
||||
iterations = 0;
|
||||
}
|
||||
const checkForElement = () => {
|
||||
const element = document.querySelector(selector);
|
||||
if (element) {
|
||||
if (unregister) unregister()
|
||||
resolve(element)
|
||||
return
|
||||
resolve(element);
|
||||
} else {
|
||||
if (maxIterations) {
|
||||
iterations++;
|
||||
if (iterations >= maxIterations) {
|
||||
reject(new Error("Element not found"));
|
||||
}
|
||||
}
|
||||
setTimeout(checkForElement, interval);
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (document.readyState === "loading") {
|
||||
document.addEventListener("DOMContentLoaded", checkForElement);
|
||||
} else {
|
||||
checkForElement();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
return new Promise((resolve) => {
|
||||
const registerObserver = () => {
|
||||
const { unregister } = eventManager.register(
|
||||
`${selector}`,
|
||||
{
|
||||
customCheck: (element) => element.matches(selector),
|
||||
},
|
||||
async (element) => {
|
||||
resolve(element);
|
||||
await delay(1);
|
||||
unregister(); // Remove the listener once the element is found
|
||||
},
|
||||
);
|
||||
return unregister;
|
||||
};
|
||||
|
||||
let unregister = null;
|
||||
|
||||
if (document.readyState === "loading") {
|
||||
// DOM is still loading, wait for it to be ready
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
unregister = registerObserver();
|
||||
});
|
||||
} else {
|
||||
unregister = registerObserver();
|
||||
}
|
||||
|
||||
const querySelector = () => document.querySelector(selector);
|
||||
const element = querySelector();
|
||||
|
||||
if (element) {
|
||||
if (unregister) unregister();
|
||||
resolve(element);
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user