303 lines
8.0 KiB
TypeScript
303 lines
8.0 KiB
TypeScript
/*
|
|
Copyright 2022 0xf8
|
|
|
|
This file is part of Galerie
|
|
|
|
Galerie is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
|
Galerie is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
You should have received a copy of the GNU General Public License along with Galerie. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
import App from "./app";
|
|
import React from "react";
|
|
|
|
import jQuery from "jquery";
|
|
const $ = jQuery;
|
|
|
|
import Settings, { apiUrl } from "./settings";
|
|
|
|
const settings = new Settings();
|
|
|
|
let global_ActiveContextMenu: ContextMenu = null;
|
|
let global_ActivePopout: Popout = null;
|
|
|
|
|
|
// ===================
|
|
// === ContextMenu ===
|
|
// ===================
|
|
|
|
class ContextMenu {
|
|
public menu: JQuery<HTMLElement>;
|
|
private overlay: JQuery<HTMLElement>;
|
|
|
|
constructor(label: string, buttons: JQuery<HTMLElement>[], position: [any, any]) {
|
|
this.overlay = $("<div class='overlay'>");
|
|
this.menu = $("<div class='contextmenu'>");
|
|
|
|
let labelElement = $("<span>");
|
|
labelElement.text(label);
|
|
this.menu.append(labelElement);
|
|
|
|
for (let _b in buttons) this.menu.append(buttons[_b]);
|
|
|
|
this.menu.css("top", position[1]);
|
|
this.menu.css("left", position[0]);
|
|
|
|
this.overlay.append(this.menu);
|
|
}
|
|
|
|
public static async createButton(text: string) {
|
|
return $("<button class='option'>").text(text);
|
|
}
|
|
|
|
public async create(): Promise<boolean> {
|
|
if (global_ActiveContextMenu != null)
|
|
return false;
|
|
global_ActiveContextMenu = this;
|
|
|
|
$("root").append(this.overlay);
|
|
|
|
$(document).one("click", async (ev) => {
|
|
ev.preventDefault();
|
|
|
|
await this.destroy();
|
|
})
|
|
|
|
return true;
|
|
}
|
|
|
|
public async destroy(): Promise<boolean> {
|
|
if (global_ActiveContextMenu != this)
|
|
return false;
|
|
global_ActiveContextMenu = null;
|
|
|
|
this.overlay.remove();
|
|
this.menu.remove();
|
|
}
|
|
}
|
|
|
|
|
|
class Popout {
|
|
private element: JQuery<HTMLElement>;
|
|
private overlay: JQuery<HTMLElement>;
|
|
|
|
constructor(element: JQuery<HTMLElement>, src: string) {
|
|
this.element = element.clone();
|
|
|
|
this.element.removeClass("resourceh resource");
|
|
this.element.addClass("popout");
|
|
|
|
this.overlay = $("<div class='overlay'>")
|
|
this.overlay.append(this.element);
|
|
|
|
this.element.on("contextmenu", Popout.createPopoutMenu(this.element, src));
|
|
}
|
|
|
|
create() {
|
|
if (global_ActivePopout != null)
|
|
return;
|
|
global_ActivePopout = this;
|
|
|
|
$("root").append(this.overlay);
|
|
this.overlay.one("click", (event) => {
|
|
event.preventDefault();
|
|
|
|
this.destroy();
|
|
})
|
|
|
|
}
|
|
|
|
destroy() {
|
|
if (global_ActivePopout != this)
|
|
return;
|
|
global_ActivePopout = null;
|
|
|
|
this.overlay.remove();
|
|
this.element.remove();
|
|
}
|
|
|
|
static createPopoutMenu(element: JQuery<HTMLElement>, src: string) {
|
|
return async (event) => {
|
|
event.preventDefault();
|
|
|
|
let favoriteButton = await ContextMenu.createButton("Add to favorites");
|
|
let blacklistButton = await ContextMenu.createButton("Add to blacklist");
|
|
|
|
let removeFButton = await ContextMenu.createButton("Remove from favorites");
|
|
let removeBButton = await ContextMenu.createButton("Remove from blacklist");
|
|
|
|
let undoLFButton = await ContextMenu.createButton("Undo last favorite");
|
|
let undoLBButton = await ContextMenu.createButton("Undo last blacklist");
|
|
|
|
let clearFButton = await ContextMenu.createButton("Clear favorites");
|
|
let clearBButton = await ContextMenu.createButton("Clear blacklist");
|
|
|
|
let reloadButton = await ContextMenu.createButton("Reload images");
|
|
let reloadOFButton = await ContextMenu.createButton("Reload and show only favorites");
|
|
|
|
let closeMenuButton = await ContextMenu.createButton("Close this menu");
|
|
|
|
let Menu = new ContextMenu("Manage resource", [
|
|
favoriteButton, blacklistButton, $("<hr/>"),
|
|
removeFButton, removeBButton, $("<hr/>"),
|
|
undoLFButton, undoLBButton, $("<hr/>"),
|
|
clearFButton, clearBButton, $("<hr/>"),
|
|
reloadButton, reloadOFButton, closeMenuButton
|
|
], [event.clientX, event.clientY]);
|
|
|
|
favoriteButton.on("click", async (ev) => {
|
|
ev.preventDefault();
|
|
await settings.favorites.push(src);
|
|
});
|
|
blacklistButton.on("click", async (ev) => {
|
|
ev.preventDefault();
|
|
element.remove();
|
|
await settings.blacklist.push(src);
|
|
});
|
|
|
|
removeFButton.on("click", async (ev) => {
|
|
ev.preventDefault();
|
|
await settings.favorites.delete(src);
|
|
})
|
|
removeBButton.on("click", async (ev) => {
|
|
ev.preventDefault();
|
|
await settings.blacklist.delete(src);
|
|
})
|
|
|
|
undoLFButton.on("click", async (ev) => {
|
|
ev.preventDefault();
|
|
await settings.favorites.pop();
|
|
});
|
|
undoLBButton.on("click", async (ev) => {
|
|
ev.preventDefault();
|
|
await settings.blacklist.pop();
|
|
});
|
|
|
|
clearFButton.on("click", async (ev) => {
|
|
ev.preventDefault();
|
|
await settings.favorites.clear();
|
|
});
|
|
clearBButton.on("click", async (ev) => {
|
|
ev.preventDefault();
|
|
await settings.blacklist.clear();
|
|
})
|
|
|
|
reloadButton.on("click", async (ev) => {
|
|
ev.preventDefault();
|
|
|
|
await Gallery.loadDisplay(await settings.cache.shuffle());
|
|
})
|
|
reloadOFButton.on("click", async (ev) => {
|
|
ev.preventDefault();
|
|
|
|
await Gallery.loadDisplay(await settings.favorites.shuffle());
|
|
})
|
|
|
|
closeMenuButton.on("click", async (ev) => {
|
|
ev.preventDefault();
|
|
|
|
await Menu.destroy();
|
|
})
|
|
|
|
Menu.create();
|
|
}
|
|
}
|
|
}
|
|
|
|
let _log = (f, ...m: any) => {
|
|
f(...m);
|
|
}
|
|
|
|
let log = (...m: any[]) => {
|
|
_log(console.log, ...m);
|
|
}
|
|
|
|
let warn = (...m: any[]) => {
|
|
_log(console.warn, ...m);
|
|
}
|
|
|
|
let error = (...m: any[]) => {
|
|
_log(console.error, ...m);
|
|
}
|
|
|
|
let debug = (...m: any[]) => {
|
|
_log(console.debug, ...m);
|
|
}
|
|
|
|
// ===============
|
|
// === Gallery ===
|
|
// ===============
|
|
|
|
class gallery {
|
|
constructor() {}
|
|
|
|
public async load(): Promise<void> {
|
|
log("Validating cache");
|
|
|
|
await settings.cache.load();
|
|
}
|
|
|
|
public async loadDisplay(data: string[]): Promise<void> {
|
|
await this.clearDisplay();
|
|
|
|
if (data.length != 0)
|
|
for (let i = 0; i < data.length; i++) {
|
|
let f = await data.at(i);
|
|
|
|
if (await settings.blacklist.contains(f))
|
|
continue;
|
|
|
|
this.createElement("img", f).then((e) => e.appendTo($("div#display")))
|
|
}
|
|
else {
|
|
let t = $("<span style='margin-top: 3em'>There's nothing here. <a style='color: white; text-decoration: none' href='#'>Reload?</a></span>");
|
|
t.children("a").on("click", async (e) => {
|
|
e.preventDefault();
|
|
this.loadDisplay(await settings.cache.shuffle());
|
|
});
|
|
// let t = <span>There's nothing here. <a href="#" onClick={ async () => this.loadDisplay(await settings.cache.shuffle()) }>Reload?</a></span>
|
|
$(t).appendTo($("div#display"))
|
|
}
|
|
}
|
|
|
|
private async clearDisplay(): Promise<void> {
|
|
$("#display").children().remove();
|
|
}
|
|
|
|
private async createElement(tag: string, src: string): Promise<JQuery<HTMLElement>> {
|
|
let element = $(`<${tag} class='resource resourceh'>`);
|
|
element.prop("loop", true);
|
|
element.prop("nocontrols", true);
|
|
element.attr("src", `${apiUrl}img/${src}`);
|
|
|
|
let popoutHandler = async (event) => {
|
|
event.preventDefault();
|
|
|
|
const popout = new Popout(element, src);
|
|
|
|
popout.create();
|
|
}
|
|
|
|
element.on("click", popoutHandler);
|
|
|
|
element.on("contextmenu", Popout.createPopoutMenu(element, src));
|
|
|
|
return element;
|
|
}
|
|
};
|
|
|
|
|
|
let Gallery = new gallery();
|
|
|
|
window.onload = async () => {
|
|
await Gallery.load();
|
|
await Gallery.loadDisplay(await settings.cache.shuffle());
|
|
}
|
|
|
|
const root = App(() => {
|
|
return <>
|
|
<div id="container">
|
|
<div id="display"></div>
|
|
</div>
|
|
</>;
|
|
}) |