import ConfettiManager from "./confetttiManager";
import Overlay from "./Overlay";
import { calculateRelativeLuminance } from "./utils";
/** The overlay builder for the color filter Blue Marble window.
* @description This class handles the overlay UI for the color filter window of the Blue Marble userscript.
* @class WindowFilter
* @since 0.88.329
* @see {@link Overlay} for examples
*/
export default class WindowFilter extends Overlay {
/** Constructor for the color filter window
* @param {*} executor - The executing class
* @since 0.88.329
* @see {@link Overlay#constructor}
*/
constructor(executor) {
super(executor.name, executor.version); // Executes the code in the Overlay constructor
this.window = null; // Contains the *window* DOM tree
this.windowID = 'bm-window-filter'; // The ID attribute for this window
this.windowParent = document.body; // The parent of the window DOM tree
/** The templateManager instance currently being used. @type {TemplateManager} */
this.templateManager = executor.apiManager?.templateManager;
// Eye icons
this.eyeOpen = '';
this.eyeClosed = '';
// Localization formats
this.localizeNumber = new Intl.NumberFormat();
this.localizePercent = new Intl.NumberFormat(undefined, {
style: 'percent',
minimumFractionDigits: 2,
maximumFractionDigits: 2
});
// Localization string formatting for "Remaining Time" in color filter window.
// This is more of a hint than anything, as browsers seem to ignore it >:(
this.localizeDateTimeOptions = {
month: 'long', // July
day: 'numeric', // 23
hour: '2-digit', // 17
minute: '2-digit', // 47
second: '2-digit' // 00
}
// Obtains the color palette Blue Marble currently uses
const { palette: palette, LUT: _ } = this.templateManager.paletteBM;
this.palette = palette;
// Tile quantity information
this.tilesLoadedTotal = 0; // Number of tiles that have been loaded in this session
this.tilesTotal = 0; // Number of tiles total, across all templates
}
/** Spawns a Color Filter window.
* If another color filter window already exists, we DON'T spawn another!
* Parent/child relationships in the DOM structure below are indicated by indentation.
* @since 0.88.149
*/
buildWindow() {
// If a color filter window already exists, throw an error and return early
if (document.querySelector(`#${this.windowID}`)) {
this.handleDisplayError('Color Filter window already exists!');
return;
}
// Creates a new color filter window
this.window = this.addDiv({'id': this.windowID, 'class': 'bm-window'})
.addDragbar()
.addButton({'class': 'bm-button-circle', 'textContent': '▼', 'aria-label': 'Minimize window "Color Filter"', 'data-button-status': 'expanded'}, (instance, button) => {
button.onclick = () => instance.handleMinimization(button);
button.ontouchend = () => {button.click()}; // Needed only to negate weird interaction with dragbar
}).buildElement()
.addDiv().buildElement() // Contains the minimized h1 element
.addButton({'class': 'bm-button-circle', 'textContent': '🞪', 'aria-label': 'Close window "Color Filter"'}, (instance, button) => {
button.onclick = () => {document.querySelector(`#${this.windowID}`)?.remove();};
button.ontouchend = () => {button.click();}; // Needed only to negate weird interaction with dragbar
}).buildElement()
.buildElement()
.addDiv({'class': 'bm-window-content'})
.addDiv({'class': 'bm-container bm-center-vertically'})
.addHeader(1, {'textContent': 'Color Filter'}).buildElement()
.buildElement()
.addHr().buildElement()
.addDiv({'class': 'bm-container bm-flex-between bm-center-vertically', 'style': 'gap: 1.5ch;'})
.addButton({'textContent': 'Select All'}, (instance, button) => {
button.onclick = () => this.#selectColorList(false);
}).buildElement()
.addButton({'textContent': 'Unselect All'}, (instance, button) => {
button.onclick = () => this.#selectColorList(true);
}).buildElement()
.buildElement()
.addDiv({'class': 'bm-container bm-scrollable'})
.addDiv({'class': 'bm-container', 'style': 'margin-left: 2.5ch; margin-right: 2.5ch;'})
.addDiv({'class': 'bm-container'})
.addSpan({'id': 'bm-filter-tile-load', 'innerHTML': 'Tiles Loaded: 0 / ???'}).buildElement()
.addBr().buildElement()
.addSpan({'id': 'bm-filter-tot-correct', 'innerHTML': 'Correct Pixels: ???'}).buildElement()
.addBr().buildElement()
.addSpan({'id': 'bm-filter-tot-total', 'innerHTML': 'Total Pixels: ???'}).buildElement()
.addBr().buildElement()
.addSpan({'id': 'bm-filter-tot-remaining', 'innerHTML': 'Complete: ??? (???)'}).buildElement()
.addBr().buildElement()
.addSpan({'id': 'bm-filter-tot-completed', 'innerHTML': '??? ???'}).buildElement()
.buildElement()
.addDiv({'class': 'bm-container'})
.addP({'innerHTML': `Colors with the icon ${this.eyeOpen.replace('