1
0
Fork 0
mirror of https://github.com/Eggbertx/gochan.git synced 2025-09-13 09:26:23 -07:00

Implement frontend spoiler handling, refactor loading to reduce FOUC

This commit is contained in:
Eggbertx 2025-04-24 15:36:33 -07:00
parent 13f29a5836
commit 4cca346f47
6 changed files with 119 additions and 27 deletions

View file

@ -74,7 +74,6 @@ def path_info(loc):
def update_gochan_version():
global gochan_version
with open("pkg/config/config.go", "r") as config:
# GochanVersion = "4.1.0"
config_str = config.read()
matches = re.findall(r"\bGochanVersion\s*=\s*\"(\S+)\"", config_str)
if len(matches) > 0:

View file

@ -1,6 +1,6 @@
import $ from "jquery";
interface BannerProps {
interface BannerAttributes {
src: string;
alt: string;
width?: number;
@ -10,6 +10,12 @@ interface BannerProps {
export function setPageBanner() {
const slashArr = location.pathname.split("/");
const board = (slashArr.length >= 2)?slashArr[1]:"";
const $bannerImg = $<HTMLImageElement>("<img/>").attr({
src: "/static/banners/gochan_go-parody.png", // placeholder, may or may not actually exist
width: 300,
height: 100,
alt: "Page banner",
}).insertBefore("header h1#board-title");
$.get({
url: `${webroot}util/banner`,
@ -18,17 +24,19 @@ export function setPageBanner() {
},
dataType: "json"
}).then(data => {
if(!data || data.Filename === undefined || data.Filename === "") {
return; // no banners :(
if((data?.Filename ?? "") === "") {
// no banners :(
$bannerImg.remove();
return;
}
const props: BannerProps = {
const attributes: BannerAttributes = {
src: `${webroot}static/banners/${data.Filename}`,
alt: "Page banner"
};
if(data.Width > 0 && data.Height > 0) {
props.width = data.Width;
props.height = data.Height;
attributes.width = data.Width;
attributes.height = data.Height;
}
$("<img/>").prop(props).insertBefore("header h1#board-title");
$bannerImg.attr(attributes);
});
}

View file

@ -306,9 +306,10 @@ export function closeQR() {
}
window.closeQR = closeQR;
$(() => {
const board = currentBoard();
if(board === "") return; // not on a board
const board = currentBoard();
if(board !== "") {
if(getBooleanStorageVal("useqr", true))
initQR();
getThreadCooldown(board).then(cd => threadCooldown = cd);
getReplyCooldown(board).then(cd => replyCooldown = cd);
});
}

View file

@ -2,8 +2,8 @@ import $, { noop } from "jquery";
import { getBooleanStorageVal } from "../storage";
export let $topbar:JQuery<HTMLElement> = null;
export let topbarHeight = 32;
export const $topbar = $("div#topbar");
export let topbarHeight = $topbar.height() + 4;
interface BeforeAfter {
before?: any;
@ -51,7 +51,6 @@ export class TopBarButton {
* Initialize the bar at the top of the page with board links and buttons
*/
export function initTopBar() {
$topbar = $("div#topbar");
if(getBooleanStorageVal("pintopbar", true)) {
$topbar.css({
"z-index": "10",

View file

@ -4,7 +4,7 @@ import "./vars";
import "./cookies";
import "./notifications";
import { setPageBanner } from "./dom/banners";
import { setCustomCSS, setCustomJS, setTheme, updateExternalLinks } from "./settings";
import { setCustomCSS, setCustomJS, setTheme, updateExternalLinks, updateSpoilerTextReveal, updateSpoilerThreadReveal } from "./settings";
import { handleKeydown } from "./boardevents";
import { initStaff, createStaffMenu, addStaffThreadOptions } from "./management/manage";
import { getPageThread } from "./postinfo";
@ -26,10 +26,23 @@ export function toBottom() {
}
window.toBottom = toBottom;
$(() => {
setTheme();
const pageThread = getPageThread();
if(pageThread.board !== "") {
prepareThumbnails();
if(pageThread.op < 1) {
updateSpoilerThreadReveal();
updateSpoilerTextReveal();
}
updateBrowseButton();
}
const pageThread = getPageThread();
setTheme();
setCustomCSS();
setCustomJS();
setPageBanner();
$(() => {
initStaff()
.then((staff) => {
if(staff?.rank < 1)
@ -44,13 +57,8 @@ $(() => {
const passwordText = $("input#postpassword").val();
$("input#delete-password").val(passwordText);
setPageBanner();
if(pageThread.board !== "") {
prepareThumbnails();
if(getBooleanStorageVal("useqr", true))
initQR();
initPostPreviews();
updateBrowseButton();
}
$("div.post, div.reply").each((i, elem) => {
addPostDropdown($(elem));
@ -58,6 +66,4 @@ $(() => {
$(document).on("keydown", handleKeydown);
initFlags();
updateExternalLinks();
setCustomCSS();
setCustomJS();
});

View file

@ -12,6 +12,9 @@ import { updateBrowseButton } from "./dom/uploaddata";
let $settingsButton: TopBarButton = null;
const settings: Map<string, Setting<boolean|number|string,HTMLElement>> = new Map();
const spoilerThreadNotice = "This thread contains spoilers<br/>";
const spoilerImage = "/static/spoiler.png";
type ElementValue = string|number|string[];
@ -256,6 +259,80 @@ export function setCustomCSS() {
.appendTo(document.head);
}
export function updateSpoilerTextReveal() {
const revealSpoilerText = getBooleanStorageVal("revealspoilertext", false);
if(revealSpoilerText) {
$(".spoiler").removeClass("spoiler").addClass("spoiler-reveal");
} else {
$(".spoiler").addClass("spoiler").removeClass("spoiler-reveal");
}
}
function revealSpoilerImage(el:HTMLImageElement) {
if(el.hasAttribute("spoiler-src")) {
el.setAttribute("src", el.getAttribute("spoiler-src"));
el.removeAttribute("spoiler-src");
}
if(el.hasAttribute("spoiler-width")) {
el.setAttribute("width", el.getAttribute("spoiler-width"));
el.removeAttribute("spoiler-width");
}
if(el.hasAttribute("spoiler-height")) {
el.setAttribute("height", el.getAttribute("spoiler-height"));
el.removeAttribute("spoiler-height");
}
}
export function updateSpoilerThreadReveal() {
const revealSpoilerThreads = getBooleanStorageVal("revealspoilerthreads", false);
const $spoilerThreads = $<HTMLDivElement>(".spoiler-thread");
const $spoilerThreadThumbs = $spoilerThreads.find<HTMLImageElement>(".op-post .thumb")
.filter((_i, el) => !el.classList.contains("spoiler-thumb"));
// first reveal (or hide) the spoiler thumbs according to the setting value
$spoilerThreadThumbs.each((i, el) => {
if(revealSpoilerThreads) {
revealSpoilerImage(el);
} else {
if(!el.hasAttribute("spoiler-src")) {
el.setAttribute("spoiler-src", el.getAttribute("src"));
}
if(!el.hasAttribute("spoiler-width") && el.hasAttribute("width")) {
el.setAttribute("spoiler-width", el.getAttribute("width"));
el.setAttribute("width", "125px");
}
if(!el.hasAttribute("spoiler-height") && el.hasAttribute("height")) {
el.setAttribute("spoiler-height", el.getAttribute("height"));
el.setAttribute("height", "125px");
}
el.setAttribute("src", path.join(webroot ?? "/", spoilerImage));
}
});
if(revealSpoilerThreads) {
$(".spoiler-notice").remove();
$(".spoiler-thread .reply-container").show();
$(".spoiler-thread .op-post .post-text").show();
} else {
$(".spoiler-thread .reply-container").hide();
$(".spoiler-thread .op-post .post-text").hide();
$("<div/>").addClass("spoiler-notice").append(
spoilerThreadNotice,
$("<button/>").text("Reveal").on("click", ev => {
ev.stopPropagation();
const $thread = $(ev.target).parents(".spoiler-thread");
$thread.find(".op-post .post-text").show();
$thread.find(".reply-container").show();
$thread.find(".spoiler-notice").remove();
$thread.find<HTMLImageElement>(".thumb").each((i, el) => {
revealSpoilerImage(el);
});
return false;
})
).insertAfter($spoilerThreads.find(".op-post .post-text"));
}
}
$(() => {
const styleOptions = [];
for(const style of styles) {
@ -268,7 +345,7 @@ $(() => {
if(val === "" && themeElem.hasAttribute("default-href")) {
themeElem.setAttribute("href", themeElem.getAttribute("default-href"));
} else if(val !== "") {
themeElem.setAttribute("href", `${webroot}css/${val}`);
themeElem.setAttribute("href", `${webroot ?? "/"}css/${val}`);
}
}) as Setting);
settings.set("pintopbar", new BooleanSetting("pintopbar", "Pin top bar", true, initTopBar));
@ -279,6 +356,8 @@ $(() => {
if(getBooleanStorageVal("useqr", true)) initQR();
else closeQR();
}));
settings.set("revealspoilertext", new BooleanSetting("revealspoilertext", "Show spoiler text", false, updateSpoilerTextReveal));
settings.set("revealspoilerthreads", new BooleanSetting("revealspoilerthreads", "Reveal spoiler threads", false, updateSpoilerThreadReveal));
settings.set("extlinksnewtab", new BooleanSetting("extlinksnewtab", "Open external links in new tab", true, updateExternalLinks));
settings.set("persistentqr", new BooleanSetting("persistentqr", "Persistent Quick Reply", false));
settings.set("watcherseconds", new NumberSetting("watcherseconds", "Check watched threads every # seconds", 15, {