-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #11 from tiagofilipenunes/fix-settings-fail
Fix settings pop-up failing to load/save settings
- Loading branch information
Showing
5 changed files
with
162 additions
and
235 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
import { RequestResponse } from "../logic"; | ||
import { capitalizeFirstLetter, getSettings } from "../logic/utils"; | ||
|
||
export class IFrameManipulator { | ||
mainElement: HTMLDivElement; | ||
|
||
constructor() { | ||
this.mainElement = this.findMainElement(); | ||
} | ||
|
||
private findMainElement = (): HTMLDivElement => { | ||
const mainElements = Array.from(document.querySelectorAll("div")); | ||
const mainElement = mainElements.find( | ||
(mainElement) => mainElement.getAttribute("data-type") === "diff" | ||
); | ||
if (!mainElement) throw Error("Main Element not found"); | ||
return mainElement; | ||
}; | ||
|
||
private selectView = (id: string) => { | ||
const viewElements = Array.from(this.mainElement.children) as HTMLElement[]; | ||
if (!viewElements.length) throw Error("View Elements not found"); | ||
viewElements.forEach((child) => { | ||
const childStyle = child.getAttribute("style"); | ||
if (!childStyle) return; | ||
if ( | ||
child.getAttribute("class")?.toLowerCase().includes(id.toLowerCase()) | ||
) { | ||
child.style.setProperty("display", "block"); | ||
} else { | ||
child.style.setProperty("display", "none"); | ||
} | ||
}); | ||
}; | ||
|
||
private clickFieldset = (textNode: string) => { | ||
const fieldSetElement = this.mainElement.querySelector("fieldset"); | ||
if (!fieldSetElement) throw Error("Fieldset Element not found"); | ||
const fieldSetLabelChildren = Array.from( | ||
fieldSetElement.children | ||
) as HTMLElement[]; | ||
fieldSetLabelChildren.forEach((child) => { | ||
if (child.textContent?.toLowerCase().includes(textNode.toLowerCase())) { | ||
// Simulate clicking on the specified element. | ||
child.dispatchEvent(new Event("mousedown")); | ||
child.click(); | ||
} | ||
}); | ||
}; | ||
|
||
private selectFieldset = (textNode: string) => { | ||
const fieldSetElement = this.mainElement.querySelector("fieldset"); | ||
if (!fieldSetElement) throw Error("Fieldset Element not found"); | ||
const fieldSetLabelChildren = Array.from(fieldSetElement.children); | ||
fieldSetLabelChildren.forEach((child) => { | ||
if (child.textContent?.toLowerCase().includes(textNode.toLowerCase())) { | ||
child.setAttribute("class", "js-view-mode selected"); | ||
} else { | ||
child.setAttribute("class", "js-view-mode"); | ||
} | ||
}); | ||
}; | ||
|
||
private getImageSource = async (src: string) => { | ||
const loadImageResponse: RequestResponse = | ||
await browser.runtime.sendMessage({ | ||
action: "loadImage", | ||
src, | ||
}); | ||
if (!loadImageResponse.success) throw new Error("Could not load image"); | ||
return loadImageResponse.response; | ||
}; | ||
|
||
private getDataFileURL = () => { | ||
const dataFileA = this.mainElement.getAttribute("data-file1"); | ||
const dataFileB = this.mainElement.getAttribute("data-file2"); | ||
if (!dataFileA || !dataFileB) throw Error("Couldn't get data-file URL"); | ||
return [dataFileA, dataFileB]; | ||
}; | ||
|
||
private loadImage = async (src: string): Promise<HTMLImageElement> => { | ||
return new Promise(async (resolve, reject) => { | ||
const img = new Image(); | ||
img.crossOrigin = "anonymous"; | ||
img.setAttribute("crossOrigin", ""); | ||
img.onload = () => resolve(img); | ||
img.onerror = (error) => { | ||
console.error("Failed to load image for reason:", error); | ||
reject(error); | ||
}; | ||
// Firefox requires images to be loaded in a background script | ||
img.src = await this.getImageSource(src); | ||
}); | ||
}; | ||
|
||
loadImages = async () => { | ||
const [dataFileA, dataFileB] = this.getDataFileURL(); | ||
return Promise.all([this.loadImage(dataFileA), this.loadImage(dataFileB)]); | ||
}; | ||
|
||
addNewViewElement = (algoName: string): HTMLDivElement => { | ||
const id = algoName.replace(" ", "-").toLowerCase(); | ||
|
||
// Add new view element | ||
const diffElement = document.createElement("div"); | ||
diffElement.setAttribute("class", `${id}-skin view`); | ||
diffElement.setAttribute("style", "display: none;"); | ||
const lastElement = this.mainElement.lastElementChild; | ||
if (!lastElement) | ||
throw Error("Couldn't get last element from main element"); | ||
this.mainElement.insertBefore(diffElement, lastElement); | ||
|
||
// Find fieldset element | ||
const fieldSetElements = this.mainElement.querySelector("fieldset"); | ||
if (!fieldSetElements) | ||
throw Error("Couldn't get fieldset elements from main element"); | ||
|
||
// Append new label elements | ||
const newLabelElement = document.createElement("label"); | ||
newLabelElement.setAttribute("class", "js-view-mode"); | ||
const newTextElement = document.createTextNode( | ||
capitalizeFirstLetter(algoName) | ||
); | ||
const newLabelInputElement = document.createElement("input"); | ||
newLabelInputElement.setAttribute("name", "view-mode"); | ||
newLabelInputElement.setAttribute("type", "radio"); | ||
newLabelInputElement.setAttribute("value", `${id}-skin`); | ||
|
||
newLabelInputElement.onclick = () => { | ||
this.selectFieldset(algoName); | ||
this.selectView(id); | ||
}; | ||
|
||
newLabelElement.appendChild(newLabelInputElement); | ||
newLabelElement.appendChild(newTextElement); | ||
fieldSetElements.appendChild(newLabelElement); | ||
|
||
return diffElement; | ||
}; | ||
|
||
setDefaultView = async () => { | ||
const settings = await getSettings(); | ||
const algoName = settings.defaultAlgo; | ||
if (!algoName) return; | ||
this.selectFieldset(algoName); | ||
this.selectView(algoName); | ||
// Wait 1 sec to allow views to load | ||
setTimeout(() => { | ||
this.clickFieldset(algoName); | ||
window.scrollTo({ top: 0, behavior: "smooth" }); | ||
}, 1000); | ||
}; | ||
} | ||
|
||
const iFrameManipulator = new IFrameManipulator(); | ||
window.onload = iFrameManipulator.setDefaultView; |
Oops, something went wrong.