Skip to content

Commit

Permalink
change: new chapters layout #91;
Browse files Browse the repository at this point in the history
  • Loading branch information
MapoMagpie committed Sep 15, 2024
1 parent 7e79821 commit ce3667d
Show file tree
Hide file tree
Showing 10 changed files with 609 additions and 370 deletions.
621 changes: 368 additions & 253 deletions eh-view-enhance.user.js

Large diffs are not rendered by default.

7 changes: 4 additions & 3 deletions src/event-bus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { CherryPick } from "./download/downloader";
import { IMGFetcherQueue } from "./fetcher-queue";
import { IMGFetcher } from "./img-fetcher";
import { VisualNode } from "./img-node";
import { Chapter } from "./page-fetcher";
import { evLog } from "./utils/ev-log";

export class EventManager {
Expand Down Expand Up @@ -41,20 +42,20 @@ export interface Events {
"bifm-on-show": () => void;
"bifm-on-hidden": () => void;
"pf-on-appended": (total: number, nodes: VisualNode[], chapterIndex: number, done?: boolean) => void;
"pf-change-chapter": (index: number) => void;
"pf-update-chapters": (chapters: Chapter[]) => void;
"pf-change-chapter": (index: number, chapter: Chapter) => void;
"pf-try-extend": () => void;
"imf-on-finished": (index: number, success: boolean, imf: IMGFetcher) => void;
"imf-on-click": (imf: IMGFetcher) => void;
"imf-download-state-change": (imf: IMGFetcher) => void;
"ifq-do": (index: number, imf: IMGFetcher, oriented: Oriented) => void;
"ifq-on-do": (index: number, queue: IMGFetcherQueue, downloading: boolean) => void;
"ifq-on-finished-report": (index: number, queue: IMGFetcherQueue) => void;
"pf-try-extend": () => void;
"downloader-canvas-resize": () => void;
"notify-message": (level: "error" | "info", message: string, duration?: number) => void;
"cherry-pick-changed": (chapaterIndex: number, cherryPick: CherryPick) => void;
"add-cherry-pick-range": (chapterIndex: number, index: number, positive: boolean, shiftKey: boolean) => void;
"imf-check-picked": (chapterIndex: number, index: number) => boolean;
"back-chapters-selection": () => void;
"pf-init": (cb: () => void) => void;
"toggle-main-view": (open?: boolean) => void;
"toggle-auto-play": () => void;
Expand Down
47 changes: 1 addition & 46 deletions src/img-node.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { DownloadState } from "./img-fetcher";
import { Chapter } from "./page-fetcher";
import { Debouncer } from "./utils/debouncer";
import { resizing } from "./utils/image-resizing";

const DEFAULT_THUMBNAIL = "data:image/gif;base64,R0lGODlhAQABAIAAAMLCwgAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==";
export const DEFAULT_THUMBNAIL = "data:image/gif;base64,R0lGODlhAQABAIAAAMLCwgAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==";

const DEFAULT_NODE_TEMPLATE = document.createElement("div");
DEFAULT_NODE_TEMPLATE.classList.add("img-node");
Expand Down Expand Up @@ -222,47 +221,3 @@ export default class ImageNode {
}
}

export class ChapterNode implements VisualNode {
chapter: Chapter;
index: number;
constructor(chapter: Chapter, index: number) {
this.chapter = chapter;
this.index = index;
}
ratio(): number | undefined {
return undefined;
}

create(): HTMLElement {
const element = DEFAULT_NODE_TEMPLATE.cloneNode(true) as HTMLElement;
const anchor = element.firstElementChild as HTMLAnchorElement;
if (this.chapter.thumbimg) {
const img = anchor.firstElementChild as HTMLImageElement;
img.src = this.chapter.thumbimg;
img.title = this.chapter.title.toString();
img.style.display = "block";
img.nextElementSibling?.remove();
}
// create title element
const description = document.createElement("div");
description.classList.add("ehvp-chapter-description");
if (Array.isArray(this.chapter.title)) {
description.innerHTML = this.chapter.title.map((t) => `<span>${t}</span>`).join("<br>");
} else {
description.innerHTML = `<span>${this.chapter.title}</span>`;
}
anchor.appendChild(description);

anchor.onclick = (event) => {
event.preventDefault();
this.chapter.onclick?.(this.index);
};
return element;
}

render(): void { }

isRender(): boolean {
return true;
}
}
17 changes: 4 additions & 13 deletions src/page-fetcher.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import EBUS from "./event-bus";
import { IMGFetcherQueue } from "./fetcher-queue";
import { IMGFetcher } from "./img-fetcher";
import ImageNode, { ChapterNode, VisualNode } from "./img-node";
import ImageNode, { VisualNode } from "./img-node";
import { Matcher } from "./platform/platform";
import { Debouncer } from "./utils/debouncer";
import { evLog } from "./utils/ev-log";
Expand Down Expand Up @@ -37,7 +37,6 @@ export class PageFetcher {
EBUS.subscribe("ifq-on-finished-report", (index) => debouncer.addEvent("APPEND-NEXT-PAGES", () => this.appendPages(index), 5));
// triggered when scrolling
EBUS.subscribe("pf-try-extend", () => debouncer.addEvent("APPEND-NEXT-PAGES", () => !this.queue.downloading?.() && this.appendNextPage(), 5));
EBUS.subscribe("back-chapters-selection", () => this.backChaptersSelection());
EBUS.subscribe("pf-init", (cb) => this.init().then(cb));
}

Expand All @@ -54,7 +53,7 @@ export class PageFetcher {
this.chapters.forEach(c => {
c.sourceIter = this.matcher.fetchPagesSource(c);
c.onclick = (index) => {
EBUS.emit("pf-change-chapter", index);
EBUS.emit("pf-change-chapter", index, c);
if (this.chapters[index].queue) {
this.appendToView(this.chapters[index].queue.length, this.chapters[index].queue, index, this.chapters[index].done);
}
Expand All @@ -64,20 +63,12 @@ export class PageFetcher {
}
};
});

EBUS.emit("pf-update-chapters", this.chapters);
if (this.chapters.length === 1) {
this.beforeInit?.();
EBUS.emit("pf-change-chapter", 0);
EBUS.emit("pf-change-chapter", 0, this.chapters[0]);
await this.changeChapter(0).then(this.afterInit).catch(this.onFailed);
}
if (this.chapters.length > 1) {
this.backChaptersSelection();
}
}

backChaptersSelection() {
EBUS.emit("pf-change-chapter", -1);
this.appendToView(this.chapters.length, this.chapters.map((c, i) => new ChapterNode(c, i)), -1, true);
}

/// start the chapter by index
Expand Down
127 changes: 127 additions & 0 deletions src/ui/chapters-panel.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import EBUS from "../event-bus";
import { DEFAULT_THUMBNAIL } from "../img-node";
import { Chapter } from "../page-fetcher";
import q from "../utils/query-element";

export class ChaptersPanel {

panel: HTMLElement;
root: HTMLElement;
thumbnail: HTMLElement;
thumbnailImg: HTMLImageElement;
thumbnailCanvas: HTMLCanvasElement;
listContainer: HTMLElement;
first: boolean = false;

constructor(root: HTMLElement) {
this.root = root;
this.panel = q("#chapters-panel", root);
this.thumbnail = q("#chapter-thumbnail", root);
this.thumbnailImg = q("#chapter-thumbnail-image", root);
this.thumbnailCanvas = q("#chapter-thumbnail-canvas", root);
this.listContainer = q("#chapter-list", root);

EBUS.subscribe("pf-update-chapters", (chapters) => {
this.updateChapterList(chapters);
if (chapters.length > 1) {
this.relocateToCenter();
}
});
EBUS.subscribe("pf-change-chapter", (index, chapter) => this.updateHighlight(index, chapter));
}

updateChapterList(chapters: Chapter[]) {
const ul = this.listContainer.firstElementChild as HTMLElement;
chapters.forEach((ch, i) => {
const li = document.createElement("div");
let title = "";
if (ch.title instanceof Array) {
title = ch.title.join("\t");
} else {
title = ch.title;
}
li.innerHTML = `<span>${title}</span>`
li.setAttribute("id", "chapter-list-item-" + ch.id.toString());
li.classList.add("chapter-list-item");
li.addEventListener("click", () => {
ch.onclick?.(i);
if (this.first) {
this.first = false;
this.panel.classList.add("p-collapse");
this.panel.classList.remove("p-collapse-deny");
this.panel.classList.remove("p-chapters-center");
}
});
li.addEventListener("mouseenter", () => this.updateChapterThumbnail(ch))
ul.appendChild(li);
});
this.updateChapterThumbnail(chapters[0]);
}

relocateToCenter() {
this.first = true;
this.panel.classList.remove("p-collapse");
this.panel.classList.add("p-collapse-deny");
this.panel.classList.add("p-chapters-center");
const [w, h] = [this.root.offsetWidth, this.root.offsetHeight];
const [pw, ph] = [this.panel.offsetWidth, this.panel.offsetHeight];
const [left, top] = [(w / 2) - (pw / 2), (h / 2) - (ph / 2)];
this.panel.style.left = left + "px";
this.panel.style.top = top + "px";
}

updateHighlight(index: number, chapter: Chapter) {
Array.from(this.listContainer.querySelectorAll("div > .chapter-list-item")).forEach((li, i) => {
if (i === index) {
li.classList.add("chapter-list-item-hl")
} else {
li.classList.remove("chapter-list-item-hl")
}
});
this.updateChapterThumbnail(chapter);
}

updateChapterThumbnail(chapter: Chapter) {
this.thumbnailImg.onload = () => {
const width = this.thumbnailImg.naturalWidth;
const height = this.thumbnailImg.naturalHeight;
let [sx, sw, sy, sh] = [0, width, 0, height];
if (width > height) {
sx = Math.floor((width - height) / 2);
sw = height;
} else if (width < height) {
sy = Math.floor((height - width) / 2);
sh = width;
}
this.thumbnailCanvas.width = sw;
this.thumbnailCanvas.height = sh;
const ctx = this.thumbnailCanvas.getContext("2d")!;
ctx.drawImage(this.thumbnailImg, sx, sy, sw, sh, 0, 0, width, height);
};
this.thumbnailImg.src = chapter.thumbimg ?? DEFAULT_THUMBNAIL;
// create title element
this.thumbnail.querySelector(".ehvp-chapter-description")?.remove();
const description = document.createElement("div");
description.classList.add("ehvp-chapter-description");
if (Array.isArray(chapter.title)) {
description.innerHTML = chapter.title.map((t) => `<span>${t}</span>`).join("<br>");
} else {
description.innerHTML = `<span>${chapter.title}</span>`;
}
this.thumbnail.appendChild(description);
}

static html() {
return `
<div id="chapters-panel" class="p-panel p-chapters p-collapse">
<div id="chapter-thumbnail" class="chapter-thumbnail">
<img id="chapter-thumbnail-image" src="${DEFAULT_THUMBNAIL}" alt="thumbnail" style="display:none;" />
<canvas id="chapter-thumbnail-canvas" width="100" height="100"></canvas>
</div>
<div id="chapter-list" class="chapter-list">
<div></div>
</div>
</div>`;
}
}

21 changes: 11 additions & 10 deletions src/ui/event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { createStyleCustomPanel } from "./style-custom-panel";
export type Events = ReturnType<typeof initEvents>;

export type KeyboardInBigImageModeId = "step-image-prev" | "step-image-next" | "exit-big-image-mode" | "step-to-first-image" | "step-to-last-image" | "scale-image-increase" | "scale-image-decrease" | "scroll-image-up" | "scroll-image-down" | "toggle-auto-play";
export type KeyboardInFullViewGridId = "open-big-image-mode" | "pause-auto-load-temporarily" | "exit-full-view-grid" | "columns-increase" | "columns-decrease" | "back-chapters-selection" | "toggle-auto-play" | "retry-fetch-next-page";
export type KeyboardInFullViewGridId = "open-big-image-mode" | "pause-auto-load-temporarily" | "exit-full-view-grid" | "columns-increase" | "columns-decrease" | "toggle-auto-play" | "retry-fetch-next-page"; // "back-chapters-selection"
export type KeyboardInMainId = "open-full-view-grid" | "start-download";
export type KeyboardEvents = {
inBigImageMode: Record<KeyboardInBigImageModeId, KeyboardDesc>,
Expand Down Expand Up @@ -171,20 +171,21 @@ export function initEvents(HTML: Elements, BIFM: BigImageFrameManager, IFQ: IMGF
});
}

function togglePanelEvent(id: string, collapse?: boolean, target?: HTMLElement) {
let element = q(`#${id}-panel`, HTML.pageHelper);
function togglePanelEvent(idPrefix: string, collapse?: boolean, target?: HTMLElement) {
const id = `${idPrefix}-panel`;
let element = q("#" + id, HTML.pageHelper);
if (!element) return;

// collapse not specified, toggle
if (collapse === undefined) {
togglePanelEvent(id, !element.classList.contains("p-collapse"), target);
togglePanelEvent(idPrefix, !element.classList.contains("p-collapse"), target);
return;
}
if (collapse) {
collapsePanelEvent(element, id);
} else {
// close other panel
["config", "downloader"].filter(k => k !== id).forEach(id => togglePanelEvent(id, true));
Array.from(HTML.root.querySelectorAll<HTMLElement>(".p-panel"))
.filter(ele => ele !== element).forEach(ele => collapsePanelEvent(ele, ele.id));
// extend
element.classList.remove("p-collapse");
if (target) {
Expand Down Expand Up @@ -347,10 +348,10 @@ export function initEvents(HTML: Elements, BIFM: BigImageFrameManager, IFQ: IMGF
["-"],
() => modNumberConfigEvent("colCount", "minus")
),
"back-chapters-selection": new KeyboardDesc(
["b"],
() => EBUS.emit("back-chapters-selection")
),
// "back-chapters-selection": new KeyboardDesc(
// ["b"],
// () => EBUS.emit("back-chapters-selection")
// ),
"toggle-auto-play": new KeyboardDesc(
["p"],
() => EBUS.emit("toggle-auto-play")
Expand Down
Loading

0 comments on commit ce3667d

Please sign in to comment.