you WOULD type a script
This commit is contained in:
parent
8cb6752168
commit
7a08c05cea
11 changed files with 385 additions and 359 deletions
16
Makefile
16
Makefile
|
@ -16,22 +16,24 @@ MAKEPAGES := $(TMPDIR)/make-pages
|
||||||
|
|
||||||
YAMLS != find -L $(DATADIR) -name $(INFONAME)
|
YAMLS != find -L $(DATADIR) -name $(INFONAME)
|
||||||
|
|
||||||
SCRIPTS != find script -name '*.js'
|
TSCRIPTS != find script -name '*.ts'
|
||||||
STYLES != find style -name '*.css'
|
STYLES != find style -name '*.css'
|
||||||
STYLESVGS != find style -name '*.svg'
|
STYLESVGS != find style -name '*.svg'
|
||||||
STYLEPNGS != find style -name '*.png'
|
STYLEPNGS != find style -name '*.png'
|
||||||
|
|
||||||
|
|
||||||
FONTS != find fonts \
|
FONTS != find fonts \
|
||||||
-iname '*.eot' -or -iname '*.svg' -or \
|
-iname '*.eot' -or -iname '*.svg' -or \
|
||||||
-iname '*.ttf' -or -iname '*.woff' -or \
|
-iname '*.ttf' -or -iname '*.woff' -or \
|
||||||
-iname '*.woff2' -or -iname '*.css'
|
-iname '*.woff2' -or -iname '*.css'
|
||||||
|
|
||||||
STATIC = $(SCRIPTS) $(STYLES) $(STYLEPNGS) $(STYLESVGS) $(FONTS)
|
STATIC = $(STYLES) $(STYLEPNGS) $(STYLESVGS) $(FONTS)
|
||||||
BSTATIC = $(patsubst %,$(BUILDDIR)/%,$(STATIC))
|
BSTATIC = $(patsubst %,$(BUILDDIR)/%,$(STATIC))
|
||||||
|
BSCRIPTS = $(patsubst %.ts,$(BUILDDIR)/%.js,$(TSCRIPTS))
|
||||||
|
|
||||||
.PHONY: all build
|
.PHONY: all build
|
||||||
all: build
|
all: build
|
||||||
build: $(BUILDDIR)/index.html $(BSTATIC)
|
build: $(BUILDDIR)/index.html $(BSTATIC) $(BSCRIPTS)
|
||||||
|
|
||||||
$(BUILDDIR)/index.html: $(DATADIR)/index.yaml $(MAKEPAGES)
|
$(BUILDDIR)/index.html: $(DATADIR)/index.yaml $(MAKEPAGES)
|
||||||
echo "[index] "$@
|
echo "[index] "$@
|
||||||
|
@ -46,6 +48,12 @@ $(BUILDDIR)/%: $(TMPDIR)/%
|
||||||
$(call copy,--link)
|
$(call copy,--link)
|
||||||
|
|
||||||
|
|
||||||
|
$(TMPDIR)/%.js: %.ts
|
||||||
|
echo "[tsc] "$@
|
||||||
|
tsc --strict --noEmitOnError \
|
||||||
|
--lib dom,es2021 --target es2015 \
|
||||||
|
--outDir $(dir $@) $^
|
||||||
|
|
||||||
$(TMPDIR)/%_small.png: $(DATADIR)/%.png
|
$(TMPDIR)/%_small.png: $(DATADIR)/%.png
|
||||||
$(call resize,$(SMALL),$(SMALL),^,-gravity center -crop 1:1+0)
|
$(call resize,$(SMALL),$(SMALL),^,-gravity center -crop 1:1+0)
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,7 @@ make' root (GalleryInfo {title, desc, prefix, filters, hidden}) infos = [b|@0
|
||||||
|
|
||||||
<meta name=robots content='noai,noimageai'>
|
<meta name=robots content='noai,noimageai'>
|
||||||
|
|
||||||
<script src=/script/gallery.js></script>
|
<script src=/script/gallery.js type=module></script>
|
||||||
$0.nsfwScript
|
$0.nsfwScript
|
||||||
|
|
||||||
<title>$title</title>
|
<title>$title</title>
|
||||||
|
|
|
@ -12,7 +12,7 @@ instance CanBuild What where
|
||||||
|
|
||||||
script :: Maybe What -> Builder
|
script :: Maybe What -> Builder
|
||||||
script Nothing = ""
|
script Nothing = ""
|
||||||
script (Just _) = [b|<script src=/script/nsfw-warning.js></script>|]
|
script (Just _) = [b|<script src=/script/nsfw-warning.js type=module></script>|]
|
||||||
|
|
||||||
dialog :: Maybe What -> Builder
|
dialog :: Maybe What -> Builder
|
||||||
dialog Nothing = ""
|
dialog Nothing = ""
|
||||||
|
|
|
@ -141,7 +141,7 @@ make' root siteName prefix nsfw _dataDir dir
|
||||||
|
|
||||||
<meta name=robots content='noai,noimageai'>
|
<meta name=robots content='noai,noimageai'>
|
||||||
|
|
||||||
<script src=/script/single.js></script>
|
<script src=/script/single.js type=module></script>
|
||||||
$nsfwScript
|
$nsfwScript
|
||||||
$bgStyle
|
$bgStyle
|
||||||
|
|
||||||
|
|
|
@ -1,204 +0,0 @@
|
||||||
(function() {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
let reqBoxes;
|
|
||||||
let excBoxes;
|
|
||||||
let allBoxes;
|
|
||||||
let tags;
|
|
||||||
let itemsByYear;
|
|
||||||
|
|
||||||
let showSingles = false;
|
|
||||||
|
|
||||||
|
|
||||||
function fillSets() {
|
|
||||||
let checkedValues = boxes =>
|
|
||||||
new Set(boxes.filter(b => b.checked).map(b => b.value));
|
|
||||||
|
|
||||||
return [checkedValues(reqBoxes), checkedValues(excBoxes)];
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateItems() {
|
|
||||||
let [reqTags, excTags] = fillSets();
|
|
||||||
let anyReq = reqTags.size > 0;
|
|
||||||
|
|
||||||
for (let [year, items] of itemsByYear) {
|
|
||||||
let hide = true;
|
|
||||||
|
|
||||||
for (let item of items) {
|
|
||||||
let req = tags.get(item).some(x => reqTags.has(x));
|
|
||||||
let exc = tags.get(item).some(x => excTags.has(x));
|
|
||||||
let hidden = exc || (anyReq && !req);
|
|
||||||
|
|
||||||
item.hidden = hidden;
|
|
||||||
hide &&= hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
document.getElementById(`marker-${year}`).hidden = hide;
|
|
||||||
}
|
|
||||||
|
|
||||||
function disp(pfx, tags) {
|
|
||||||
return Array(...tags).map(x => pfx + x).join('\u2003'); // em space
|
|
||||||
}
|
|
||||||
let plus = disp('+\u2009', reqTags); // thin space
|
|
||||||
let minus = disp('-\u2009', excTags);
|
|
||||||
document.getElementById('filters-details').dataset.filters =
|
|
||||||
`${plus}\u2003${minus}`.trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
function update() {
|
|
||||||
updateItems();
|
|
||||||
history.pushState(null, "", makeFragment());
|
|
||||||
}
|
|
||||||
|
|
||||||
function converseId(id) {
|
|
||||||
if (id.match(/^require/)) {
|
|
||||||
return id.replace('require', 'exclude');
|
|
||||||
} else {
|
|
||||||
return id.replace('exclude', 'require');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggle(checkbox) {
|
|
||||||
if (checkbox.checked)
|
|
||||||
document.getElementById(converseId(checkbox.id)).checked = false;
|
|
||||||
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function clearForm() {
|
|
||||||
allBoxes.forEach(b => b.checked = b.defaultChecked);
|
|
||||||
}
|
|
||||||
|
|
||||||
function clear(e) {
|
|
||||||
clearForm();
|
|
||||||
update();
|
|
||||||
if (e) e.preventDefault();
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggleSingles(e) {
|
|
||||||
showSingles = !showSingles;
|
|
||||||
|
|
||||||
for (let li of document.querySelectorAll('.filterlist li')) {
|
|
||||||
let count = +li.querySelector('label').dataset.count;
|
|
||||||
if (count <= 1) {
|
|
||||||
li.hidden = !showSingles;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e) e.preventDefault();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function makeFragment() {
|
|
||||||
let ids = allBoxes.filter(b => b.checked).map(b => b.id);
|
|
||||||
if (ids.length == 0) {
|
|
||||||
return '#all';
|
|
||||||
} else if (allBoxes.every(b => b.checked == b.defaultChecked)) {
|
|
||||||
return '#';
|
|
||||||
} else {
|
|
||||||
return '#' + ids.join(';');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function useFragment() {
|
|
||||||
let frag = decodeURIComponent(location.hash).replace(/^#/, '');
|
|
||||||
let details = document.getElementById('filters-details');
|
|
||||||
|
|
||||||
if (!frag) {
|
|
||||||
clearForm();
|
|
||||||
} else if (frag == 'all') {
|
|
||||||
allBoxes.forEach(b => b.checked = false);
|
|
||||||
details.open = false;
|
|
||||||
} else {
|
|
||||||
let set = new Set(frag.split(';'));
|
|
||||||
let re = /^(require|exclude)_|hide_filters/;
|
|
||||||
if (Array.from(set).every(x => re.test(x))) {
|
|
||||||
allBoxes.forEach(b => b.checked = set.has(b.id));
|
|
||||||
details.open = !frag.match(/hide_filters|example\b/);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
updateItems();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function sortFilters(cmp) {
|
|
||||||
function sort1(id) {
|
|
||||||
let elt = document.getElementById(id);
|
|
||||||
let children = [...elt.childNodes];
|
|
||||||
children.sort(cmp);
|
|
||||||
for (let c of children) {
|
|
||||||
elt.removeChild(c);
|
|
||||||
elt.appendChild(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sort1('require');
|
|
||||||
sort1('exclude');
|
|
||||||
}
|
|
||||||
|
|
||||||
function sortFiltersAlpha(e) {
|
|
||||||
function getName(x) {
|
|
||||||
if (x.nodeType == Node.ELEMENT_NODE) {
|
|
||||||
return x.getElementsByTagName('input')[0].value;
|
|
||||||
} else {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sortFilters((a, b) => getName(a).localeCompare(getName(b)));
|
|
||||||
e.preventDefault();
|
|
||||||
}
|
|
||||||
|
|
||||||
function sortFiltersUses(e) {
|
|
||||||
function getUses(x) {
|
|
||||||
if (x.nodeType == Node.ELEMENT_NODE) {
|
|
||||||
return parseInt(x.getElementsByTagName('label')[0].dataset.count);
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sortFilters((a, b) => getUses(b) - getUses(a));
|
|
||||||
e.preventDefault();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function setup() {
|
|
||||||
function inputs(id) {
|
|
||||||
let iter = document.getElementById(id).getElementsByTagName('input');
|
|
||||||
return Array.from(iter);
|
|
||||||
}
|
|
||||||
|
|
||||||
let items = Array.from(document.getElementsByClassName('post'));
|
|
||||||
|
|
||||||
itemsByYear = new Map;
|
|
||||||
for (let item of items) {
|
|
||||||
let year = item.dataset.year;
|
|
||||||
if (!itemsByYear.has(year)) itemsByYear.set(year, new Set);
|
|
||||||
itemsByYear.get(year).add(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
reqBoxes = inputs('require');
|
|
||||||
excBoxes = inputs('exclude');
|
|
||||||
allBoxes = [...reqBoxes, ...excBoxes];
|
|
||||||
|
|
||||||
tags = new Map(items.map(item => [item, item.dataset.tags.split(';')]));
|
|
||||||
|
|
||||||
|
|
||||||
allBoxes.forEach(b => b.addEventListener('change', () => toggle(b)));
|
|
||||||
|
|
||||||
function addClick(id, f) {
|
|
||||||
document.getElementById(id).addEventListener('click', f);
|
|
||||||
}
|
|
||||||
addClick('clear', clear);
|
|
||||||
addClick('sortalpha', sortFiltersAlpha);
|
|
||||||
addClick('sortuses', sortFiltersUses);
|
|
||||||
addClick('singles', toggleSingles);
|
|
||||||
|
|
||||||
window.addEventListener('popstate', useFragment);
|
|
||||||
|
|
||||||
useFragment();
|
|
||||||
}
|
|
||||||
|
|
||||||
window.addEventListener('DOMContentLoaded', setup);
|
|
||||||
})();
|
|
220
script/gallery.ts
Normal file
220
script/gallery.ts
Normal file
|
@ -0,0 +1,220 @@
|
||||||
|
type Boxes = Set<HTMLInputElement>;
|
||||||
|
|
||||||
|
let reqBoxes: Boxes;
|
||||||
|
let excBoxes: Boxes;
|
||||||
|
let allBoxes: Boxes;
|
||||||
|
let tags: Map<HTMLElement, string[]>;
|
||||||
|
let itemsByYear: Map<string, Set<HTMLElement>>;
|
||||||
|
|
||||||
|
let showSingles = false;
|
||||||
|
|
||||||
|
|
||||||
|
function fillSets() {
|
||||||
|
function checkedValues(boxes: Boxes) {
|
||||||
|
return new Set(Array.from(boxes).filter(b => b.checked).map(b => b.value));
|
||||||
|
}
|
||||||
|
|
||||||
|
return [checkedValues(reqBoxes), checkedValues(excBoxes)];
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateItems() {
|
||||||
|
let [reqTags, excTags] = fillSets();
|
||||||
|
let anyReq = reqTags.size > 0;
|
||||||
|
|
||||||
|
for (let [year, items] of itemsByYear) {
|
||||||
|
let hide = true;
|
||||||
|
|
||||||
|
for (let item of items) {
|
||||||
|
let req = tags.get(item)?.some(x => reqTags.has(x)) ?? false;
|
||||||
|
let exc = tags.get(item)?.some(x => excTags.has(x)) ?? false;
|
||||||
|
let hidden = exc || (anyReq && !req);
|
||||||
|
|
||||||
|
item.hidden = hidden;
|
||||||
|
hide &&= hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
let marker = document.getElementById(`marker-${year}`);
|
||||||
|
if (marker !== null) marker.hidden = hide;
|
||||||
|
}
|
||||||
|
|
||||||
|
function disp(pfx: string, tags: string[]) {
|
||||||
|
return Array(...tags).map(x => pfx + x).join('\u2003'); // em space
|
||||||
|
}
|
||||||
|
let plus = disp('+\u2009', Array.from(reqTags)); // thin space
|
||||||
|
let minus = disp('-\u2009', Array.from(excTags));
|
||||||
|
document.getElementById('filters-details')!.dataset.filters =
|
||||||
|
`${plus}\u2003${minus}`.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
function update() {
|
||||||
|
updateItems();
|
||||||
|
history.pushState(null, "", makeFragment());
|
||||||
|
}
|
||||||
|
|
||||||
|
function converseId(id: string) {
|
||||||
|
if (id.match(/^require/)) {
|
||||||
|
return id.replace('require', 'exclude');
|
||||||
|
} else {
|
||||||
|
return id.replace('exclude', 'require');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggle(checkbox: HTMLInputElement) {
|
||||||
|
if (checkbox.checked) {
|
||||||
|
let converse = document.getElementById(converseId(checkbox.id)) as HTMLInputElement;
|
||||||
|
converse.checked = false;
|
||||||
|
}
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function clearForm() {
|
||||||
|
allBoxes.forEach(b => b.checked = b.defaultChecked);
|
||||||
|
}
|
||||||
|
|
||||||
|
function clear(e: Event) {
|
||||||
|
clearForm();
|
||||||
|
update();
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleSingles(e: Event) {
|
||||||
|
showSingles = !showSingles;
|
||||||
|
|
||||||
|
let elems = Array.from(document.querySelectorAll('.filterlist li'));
|
||||||
|
for (let li of elems) {
|
||||||
|
let countStr = li.querySelector('label')?.dataset.count;
|
||||||
|
let count = countStr ? +countStr : 0;
|
||||||
|
if (count <= 1 && li instanceof HTMLElement) {
|
||||||
|
li.hidden = !showSingles;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e) e.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function makeFragment() {
|
||||||
|
let allBoxesArr = Array.from(allBoxes);
|
||||||
|
let ids = allBoxesArr.filter(b => b.checked).map(b => b.id);
|
||||||
|
if (ids.length == 0) {
|
||||||
|
return '#all';
|
||||||
|
} else if (allBoxesArr.every(b => b.checked == b.defaultChecked)) {
|
||||||
|
return '#';
|
||||||
|
} else {
|
||||||
|
return '#' + ids.join(';');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function useFragment() {
|
||||||
|
let frag = decodeURIComponent(location.hash).replace(/^#/, '');
|
||||||
|
let details = document.getElementById('filters-details') as HTMLDetailsElement;
|
||||||
|
|
||||||
|
if (!frag) {
|
||||||
|
clearForm();
|
||||||
|
} else if (frag == 'all') {
|
||||||
|
allBoxes.forEach(b => b.checked = false);
|
||||||
|
details.open = false;
|
||||||
|
} else {
|
||||||
|
let set = new Set(frag.split(';'));
|
||||||
|
let re = /^(require|exclude)_|hide_filters/;
|
||||||
|
if (Array.from(set).every(x => re.test(x))) {
|
||||||
|
allBoxes.forEach(b => b.checked = set.has(b.id));
|
||||||
|
details.open = !frag.match(/hide_filters|example\b/);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function sortFilters(cmp: (a: Node, b: Node) => number) {
|
||||||
|
function sort1(id: string) {
|
||||||
|
let elt = document.getElementById(id);
|
||||||
|
if (elt === null) return;
|
||||||
|
|
||||||
|
let children = Array.from(elt.childNodes);
|
||||||
|
children.sort(cmp);
|
||||||
|
for (let c of children) {
|
||||||
|
elt.removeChild(c);
|
||||||
|
elt.appendChild(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sort1('require');
|
||||||
|
sort1('exclude');
|
||||||
|
}
|
||||||
|
|
||||||
|
function sortFiltersAlpha(e: Event) {
|
||||||
|
function getName(node: Node) {
|
||||||
|
if (node.nodeType == Node.ELEMENT_NODE) {
|
||||||
|
let elt = node as Element;
|
||||||
|
return elt.getElementsByTagName('input')[0].value;
|
||||||
|
} else {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sortFilters((a, b) => getName(a).localeCompare(getName(b)));
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
function sortFiltersUses(e: Event) {
|
||||||
|
function getUses(node: Node) {
|
||||||
|
if (node.nodeType == Node.ELEMENT_NODE) {
|
||||||
|
let elt = node as Element;
|
||||||
|
let countStr = elt.getElementsByTagName('label')[0].dataset.count;
|
||||||
|
return countStr ? +countStr : 0;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sortFilters((a, b) => getUses(b) - getUses(a));
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function setup() {
|
||||||
|
function inputs(id: string) {
|
||||||
|
let iter = document.getElementById(id)!.getElementsByTagName('input');
|
||||||
|
return new Set(Array.from(iter));
|
||||||
|
}
|
||||||
|
|
||||||
|
let items = Array.from(document.getElementsByClassName('post')) as HTMLElement[];
|
||||||
|
|
||||||
|
itemsByYear = new Map;
|
||||||
|
for (let item of items) {
|
||||||
|
let year = item.dataset.year;
|
||||||
|
if (year !== undefined) {
|
||||||
|
if (!itemsByYear.has(year)) {
|
||||||
|
itemsByYear.set(year, new Set([item]));
|
||||||
|
} else {
|
||||||
|
itemsByYear.get(year)?.add(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reqBoxes = inputs('require');
|
||||||
|
excBoxes = inputs('exclude');
|
||||||
|
allBoxes = new Set([...reqBoxes, ...excBoxes]);
|
||||||
|
|
||||||
|
tags = new Map(items.map(item => [item, item.dataset.tags?.split(';') ?? []]));
|
||||||
|
|
||||||
|
|
||||||
|
allBoxes.forEach(b => b.addEventListener('change', () => toggle(b)));
|
||||||
|
|
||||||
|
function addClick(id: string, f: (e: Event) => void) {
|
||||||
|
document.getElementById(id)!.addEventListener('click', f);
|
||||||
|
}
|
||||||
|
addClick('clear', clear);
|
||||||
|
addClick('sortalpha', sortFiltersAlpha);
|
||||||
|
addClick('sortuses', sortFiltersUses);
|
||||||
|
addClick('singles', toggleSingles);
|
||||||
|
|
||||||
|
window.addEventListener('popstate', useFragment);
|
||||||
|
|
||||||
|
useFragment();
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('DOMContentLoaded', setup);
|
||||||
|
|
||||||
|
export {};
|
|
@ -1,38 +0,0 @@
|
||||||
(function () {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
let nsfwOk = 'nsfw-ok';
|
|
||||||
|
|
||||||
function alreadyYes() {
|
|
||||||
return localStorage.getItem(nsfwOk);
|
|
||||||
}
|
|
||||||
|
|
||||||
function dismiss() {
|
|
||||||
let dialog = document.getElementById('nsfw-dialog');
|
|
||||||
dialog.parentElement.removeChild(dialog);
|
|
||||||
}
|
|
||||||
|
|
||||||
function yes() {
|
|
||||||
localStorage.setItem(nsfwOk, 1);
|
|
||||||
dismiss();
|
|
||||||
}
|
|
||||||
|
|
||||||
// now just a normal link
|
|
||||||
/*
|
|
||||||
function no() {
|
|
||||||
document.location = '//crouton.net';
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
function setup() {
|
|
||||||
if (alreadyYes()) {
|
|
||||||
dismiss();
|
|
||||||
} else {
|
|
||||||
document.getElementById('nsfw-yes').onclick = yes;
|
|
||||||
// document.getElementById('nsfw-no').onclick = no;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', setup);
|
|
||||||
|
|
||||||
})();
|
|
28
script/nsfw-warning.ts
Normal file
28
script/nsfw-warning.ts
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
const nsfwOk = 'nsfw-ok';
|
||||||
|
|
||||||
|
function alreadyYes() {
|
||||||
|
return localStorage.getItem(nsfwOk) !== undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
function dismiss() {
|
||||||
|
let dialog = document.getElementById('nsfw-dialog')!;
|
||||||
|
dialog.parentElement?.removeChild(dialog);
|
||||||
|
}
|
||||||
|
|
||||||
|
function yes() {
|
||||||
|
localStorage.setItem(nsfwOk, '1');
|
||||||
|
dismiss();
|
||||||
|
}
|
||||||
|
|
||||||
|
function setup() {
|
||||||
|
if (alreadyYes()) {
|
||||||
|
dismiss();
|
||||||
|
} else {
|
||||||
|
document.getElementById('nsfw-yes')!.onclick = yes;
|
||||||
|
// nsfw-no is a normal link
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', setup);
|
||||||
|
|
||||||
|
export {};
|
110
script/single.js
110
script/single.js
|
@ -1,110 +0,0 @@
|
||||||
(function() {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
let mainfig;
|
|
||||||
let mainimg;
|
|
||||||
let mainlink;
|
|
||||||
let altButtons;
|
|
||||||
let skipAll;
|
|
||||||
|
|
||||||
let opened = new Set;
|
|
||||||
|
|
||||||
function openCW(id, caption, focusLink = false) {
|
|
||||||
if (id) opened.add(id);
|
|
||||||
mainfig.removeChild(caption);
|
|
||||||
mainlink.tabIndex = 0;
|
|
||||||
if (focusLink) mainlink.focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
function addCWListeners(id, caption) {
|
|
||||||
if (caption) {
|
|
||||||
caption.addEventListener('click', e => openCW(id, caption));
|
|
||||||
caption.addEventListener('keyup',
|
|
||||||
e => { if (e.key == 'Enter') openCW(id, caption, true) });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function setImage(id, src, href, cw) {
|
|
||||||
let caption = document.getElementById('cw');
|
|
||||||
let newCaption;
|
|
||||||
|
|
||||||
let checked = skipAll ? skipAll.checked : false;
|
|
||||||
|
|
||||||
if (!checked && !opened.has(id) && cw) {
|
|
||||||
newCaption = document.getElementById('cw-template')
|
|
||||||
.content.firstElementChild.cloneNode(true);
|
|
||||||
newCaption.querySelector('#cw-text').innerHTML = cw;
|
|
||||||
addCWListeners(id, newCaption);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (caption) {
|
|
||||||
openCW(null, caption);
|
|
||||||
}
|
|
||||||
if (newCaption) {
|
|
||||||
mainfig.insertBefore(newCaption, mainlink);
|
|
||||||
mainlink.tabIndex = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
mainimg.src = src;
|
|
||||||
mainlink.href = href;
|
|
||||||
}
|
|
||||||
|
|
||||||
function activateButton(button, doPush = true) {
|
|
||||||
setImage(button.id, button.value,
|
|
||||||
button.dataset.link, button.dataset.warning);
|
|
||||||
|
|
||||||
if (doPush) history.pushState(null, '', '#' + button.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
function useFragment(firstLoad = false) {
|
|
||||||
let button = altButtons[0];
|
|
||||||
|
|
||||||
let frag = decodeURIComponent(location.hash).replace(/^#/, '');
|
|
||||||
if (frag) {
|
|
||||||
let selected = document.getElementById(frag);
|
|
||||||
if (selected) button = selected;
|
|
||||||
}
|
|
||||||
|
|
||||||
let id;
|
|
||||||
|
|
||||||
if (button) {
|
|
||||||
id = button.id;
|
|
||||||
button.checked = true;
|
|
||||||
activateButton(button, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (firstLoad) addCWListeners(id, document.getElementById('cw'));
|
|
||||||
}
|
|
||||||
|
|
||||||
function setup() {
|
|
||||||
mainfig = document.getElementById('mainfig');
|
|
||||||
mainimg = document.getElementById('mainimg');
|
|
||||||
mainlink = document.getElementById('mainlink');
|
|
||||||
skipAll = document.getElementById('skipAll');
|
|
||||||
|
|
||||||
let alts = document.getElementById('alts');
|
|
||||||
if (alts) {
|
|
||||||
let inputs = Array.from(alts.getElementsByTagName('input'));
|
|
||||||
altButtons = inputs.filter(e => e.name == 'variant');
|
|
||||||
} else {
|
|
||||||
altButtons = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let button of altButtons) {
|
|
||||||
button.onchange = e => { if (button.checked) activateButton(button); };
|
|
||||||
}
|
|
||||||
|
|
||||||
if (skipAll) {
|
|
||||||
skipAll.onchange = e => { if (skipAll.checked) {
|
|
||||||
let caption = document.getElementById('cw');
|
|
||||||
if (caption) { openCW(null, caption, false); }
|
|
||||||
} };
|
|
||||||
}
|
|
||||||
|
|
||||||
window.addEventListener('popstate', e => useFragment());
|
|
||||||
useFragment(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
window.addEventListener('DOMContentLoaded', setup);
|
|
||||||
|
|
||||||
})();
|
|
114
script/single.ts
Normal file
114
script/single.ts
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
let mainfig: HTMLElement;
|
||||||
|
let mainimg: HTMLImageElement;
|
||||||
|
let mainlink: HTMLAnchorElement;
|
||||||
|
let altButtons: HTMLInputElement[];
|
||||||
|
let skipAll: HTMLInputElement;
|
||||||
|
|
||||||
|
let opened = new Set;
|
||||||
|
|
||||||
|
function openCW(id: string | null, caption: HTMLElement | null,
|
||||||
|
focusLink = false) {
|
||||||
|
if (id !== null) opened.add(id);
|
||||||
|
if (caption !== null) mainfig.removeChild(caption);
|
||||||
|
mainlink.tabIndex = 0;
|
||||||
|
if (focusLink) mainlink.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
function addCWListeners(id: string | null,
|
||||||
|
caption: HTMLElement | null) {
|
||||||
|
if (caption) {
|
||||||
|
caption.addEventListener('click', _e => openCW(id, caption));
|
||||||
|
caption.addEventListener('keyup',
|
||||||
|
e => { if (e.key == 'Enter') openCW(id, caption, true) });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setImage(id: string | null,
|
||||||
|
src: string,
|
||||||
|
href: string,
|
||||||
|
cw: string) {
|
||||||
|
let caption = document.getElementById('cw');
|
||||||
|
let newCaption: HTMLElement | null = null;
|
||||||
|
|
||||||
|
let checked = skipAll ? skipAll.checked : false;
|
||||||
|
|
||||||
|
if (!checked && !opened.has(id) && cw) {
|
||||||
|
let template = document.getElementById('cw-template') as HTMLTemplateElement;
|
||||||
|
newCaption = template.content.firstElementChild!.cloneNode(true) as HTMLElement;
|
||||||
|
newCaption.querySelector('#cw-text')!.innerHTML = cw;
|
||||||
|
addCWListeners(id, newCaption);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (caption) {
|
||||||
|
openCW(null, caption);
|
||||||
|
}
|
||||||
|
if (newCaption !== null) {
|
||||||
|
mainfig.insertBefore(newCaption, mainlink);
|
||||||
|
mainlink.tabIndex = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
mainimg.src = src;
|
||||||
|
mainlink.href = href;
|
||||||
|
}
|
||||||
|
|
||||||
|
function activateButton(button: HTMLInputElement,
|
||||||
|
doPush = true) {
|
||||||
|
setImage(button.id, button.value,
|
||||||
|
button.dataset.link!,
|
||||||
|
button.dataset.warning!);
|
||||||
|
|
||||||
|
if (doPush) history.pushState(null, '', '#' + button.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
function useFragment(firstLoad = false) {
|
||||||
|
let button = altButtons[0];
|
||||||
|
|
||||||
|
let frag = decodeURIComponent(location.hash).replace(/^#/, '');
|
||||||
|
if (frag) {
|
||||||
|
let selected = document.getElementById(frag) as HTMLInputElement;
|
||||||
|
if (selected) button = selected;
|
||||||
|
}
|
||||||
|
|
||||||
|
let id: string | null = null;
|
||||||
|
|
||||||
|
if (button) {
|
||||||
|
id = button.id;
|
||||||
|
button.checked = true;
|
||||||
|
activateButton(button, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (firstLoad) addCWListeners(id, document.getElementById('cw'));
|
||||||
|
}
|
||||||
|
|
||||||
|
function setup() {
|
||||||
|
mainfig = document.getElementById('mainfig')!;
|
||||||
|
mainimg = document.getElementById('mainimg') as HTMLImageElement;
|
||||||
|
mainlink = document.getElementById('mainlink') as HTMLAnchorElement;
|
||||||
|
skipAll = document.getElementById('skipAll') as HTMLInputElement;
|
||||||
|
|
||||||
|
let alts = document.getElementById('alts');
|
||||||
|
if (alts) {
|
||||||
|
let inputs = Array.from(alts.getElementsByTagName('input'));
|
||||||
|
altButtons = inputs.filter(e => e.name == 'variant');
|
||||||
|
} else {
|
||||||
|
altButtons = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let button of altButtons) {
|
||||||
|
button.onchange = _e => { if (button.checked) activateButton(button); };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (skipAll) {
|
||||||
|
skipAll.onchange = _e => { if (skipAll.checked) {
|
||||||
|
let caption = document.getElementById('cw');
|
||||||
|
if (caption) { openCW(null, caption, false); }
|
||||||
|
} };
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('popstate', _e => useFragment());
|
||||||
|
useFragment(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('DOMContentLoaded', setup);
|
||||||
|
|
||||||
|
export {};
|
8
tsconfig.json
Normal file
8
tsconfig.json
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"strict": true,
|
||||||
|
"noEmitOnError": true,
|
||||||
|
"lib": ["ES2021", "dom"],
|
||||||
|
"target": "ES2015"
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue