PNG: move explorer to separate file (no expected impact)

This commit is contained in:
Evan Hahn 2023-08-02 13:48:36 -05:00
parent ed8a1c3b63
commit 6e047609ce
2 changed files with 85 additions and 70 deletions

83
public/png/explorer.js Normal file
View File

@ -0,0 +1,83 @@
// @ts-check
import crel from "../common/crel.js";
import formatBytes from "../common/formatBytes.js";
/** @typedef {import("./nodePath.js").NodePath} NodePath */
/** @typedef {import("../../types/png.d.ts").PngNode} PngNode */
/**
* @typedef {Function} NodeUiFn
* @param {PngNode} node
* @returns {NodeUi}
*/
class Explorer {
#bytesEl = crel("div", { class: "bytes" });
#treeEl = crel("div", { class: "tree" });
/**
* @param {PngNode} rootNode
* @param {NodeUiFn} getNodeUi
*/
constructor(rootNode, getNodeUi) {
/**
* @param {PngNode} node
* @param {NodePath} path
* @returns [HTMLElement, HTMLElement] Each node's bytes and tree elements.
*/
const traverse = (node, path) => {
const nodeBytesEl = crel("span", { "data-path": path });
const isRoot = path.length === 0;
const { title, description } = getNodeUi(node);
const nodeTreeEl = crel(
"details",
{ "data-path": path, ...(isRoot ? { open: "open" } : {}) },
crel(
"summary",
{},
crel("span", { "class": "title" }, title),
crel(
"span",
{ "class": "bytecount" },
"TODO: X bytes",
),
),
description,
);
if (node.children) {
const treeChildrenEl = crel("div", { class: "children" });
node.children.forEach((child, index) => {
const [childBytesEl, childTreeEl] = traverse(
child,
path.concat(index),
);
if (index > 0) nodeBytesEl.append(" ");
nodeBytesEl.append(childBytesEl);
treeChildrenEl.append(childTreeEl);
});
nodeTreeEl.append(treeChildrenEl);
} else {
nodeBytesEl.innerHTML = formatBytes(node.bytes, 256);
}
return [nodeBytesEl, nodeTreeEl];
};
// TODO: better variable names
const [a, b] = traverse(rootNode, []);
this.#bytesEl.append(a);
this.#treeEl.append(b);
this.el = document.createDocumentFragment();
this.el.append(this.#bytesEl, this.#treeEl);
}
}
/**
* @param {PngNode} rootNode
* @param {NodeUiFn} getNodeUi
* @returns {DocumentFragment}
*/
export default (rootNode, getNodeUi) => new Explorer(rootNode, getNodeUi).el;

View File

@ -1,80 +1,14 @@
// @ts-check // @ts-check
import crel from "../common/crel.js";
import formatBytes from "../common/formatBytes.js";
import parsePng from "./parsePng.js"; import parsePng from "./parsePng.js";
import parseHash from "./parseHash.js"; import parseHash from "./parseHash.js";
import getNodeUi from "./getNodeUi.js"; import getNodeUi from "./getNodeUi.js";
/** @typedef {import("./nodePath.js").NodePath} NodePath */ import explorer from "./explorer.js";
/** @typedef {import("../../types/png.d.ts").PngNode} PngNode */
const errorEl = document.getElementById("error"); const errorEl = document.getElementById("error");
const explorerEl = document.getElementById("explorer"); const explorerEl = document.getElementById("explorer");
if (!errorEl || !explorerEl) throw new Error("HTML is not set up correctly"); if (!errorEl || !explorerEl) throw new Error("HTML is not set up correctly");
class Explorer {
#bytesEl = crel("div", { class: "bytes" });
#treeEl = crel("div", { class: "tree" });
/**
* @param {PngNode} rootNode
*/
constructor(rootNode) {
/**
* @param {PngNode} node
* @param {NodePath} path
* @returns [HTMLElement, HTMLElement] Each node's bytes and tree elements.
*/
const traverse = (node, path) => {
const nodeBytesEl = crel("span", { "data-path": path });
const isRoot = path.length === 0;
const { title, description } = getNodeUi(node);
const nodeTreeEl = crel(
"details",
{ "data-path": path, ...(isRoot ? { open: "open" } : {}) },
crel(
"summary",
{},
crel("span", { "class": "title" }, title),
crel(
"span",
{ "class": "bytecount" },
"TODO: X bytes",
),
),
description,
);
if (node.children) {
const treeChildrenEl = crel("div", { class: "children" });
node.children.forEach((child, index) => {
const [childBytesEl, childTreeEl] = traverse(
child,
path.concat(index),
);
if (index > 0) nodeBytesEl.append(" ");
nodeBytesEl.append(childBytesEl);
treeChildrenEl.append(childTreeEl);
});
nodeTreeEl.append(treeChildrenEl);
} else {
nodeBytesEl.innerHTML = formatBytes(node.bytes, 256);
}
return [nodeBytesEl, nodeTreeEl];
};
// TODO: better variable names
const [a, b] = traverse(rootNode, []);
this.#bytesEl.append(a);
this.#treeEl.append(b);
this.el = document.createDocumentFragment();
this.el.append(this.#bytesEl, this.#treeEl);
}
}
const main = () => { const main = () => {
// TODO: We may want a better UI here. // TODO: We may want a better UI here.
// TODO: Handle hash changes. // TODO: Handle hash changes.
@ -93,10 +27,8 @@ const main = () => {
return; return;
} }
const explorer = new Explorer(rootNode);
explorerEl.innerHTML = ""; explorerEl.innerHTML = "";
explorerEl.append(explorer.el); explorerEl.append(explorer(rootNode, getNodeUi));
explorerEl.removeAttribute("hidden"); explorerEl.removeAttribute("hidden");
}; };