diff --git a/public/png/index.html b/public/png/index.html index a83c846..54e829b 100644 --- a/public/png/index.html +++ b/public/png/index.html @@ -12,10 +12,7 @@ - + diff --git a/public/png/parsePng.js b/public/png/parsePng.js index d7dda03..d69f824 100644 --- a/public/png/parsePng.js +++ b/public/png/parsePng.js @@ -3,8 +3,7 @@ import { PngNodeType } from "./constants.js"; import { areBytesEqual, chunkBytes } from "../common/bytes.js"; import crc32 from "./crc32.js"; - -/** @typedef {import("../../types/png.d.ts").Node} PngNode */ +/** @typedef {import("../../types/png.d.ts").PngNode} PngNode */ const PNG_SIGNATURE = new Uint8Array([137, 80, 78, 71, 13, 10, 26, 10]); diff --git a/public/png/png.js b/public/png/png.js index 0f2f956..b4494c2 100644 --- a/public/png/png.js +++ b/public/png/png.js @@ -1,13 +1,82 @@ // @ts-check +import crel from "../common/crel.js"; import parsePng from "./parsePng.js"; - import parseHash from "./parseHash.js"; +/** @typedef {import("./nodePath.js").NodePath} NodePath */ +/** @typedef {import("../../types/png.d.ts").PngNode} PngNode */ const errorEl = document.getElementById("error"); const explorerEl = document.getElementById("explorer"); 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 }); + + // TODO: Show a user-friendly title. + const isRoot = path.length === 0; + const title = node.type; + const description = "TODO: Description"; + const nodeTreeEl = crel( + "details", + { "data-path": path, open: isRoot }, + 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), + ); + nodeBytesEl.append(childBytesEl); + treeChildrenEl.append(childTreeEl); + }); + nodeTreeEl.append(treeChildrenEl); + } else { + // TODO: Update this formatting + nodeBytesEl.innerHTML = [...node.bytes].map((b) => + b.toString(16).padStart(2, "0") + ).join(""); + } + + 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 = () => { // TODO: We may want a better UI here. // TODO: Handle hash changes. @@ -26,8 +95,11 @@ const main = () => { return; } - // TODO: Actually do something! - console.log(rootNode); + const explorer = new Explorer(rootNode); + + explorerEl.innerHTML = ""; + explorerEl.append(explorer.el); + explorerEl.removeAttribute("hidden"); }; main(); diff --git a/types/png.d.ts b/types/png.d.ts index e36223c..2a51325 100644 --- a/types/png.d.ts +++ b/types/png.d.ts @@ -1,4 +1,6 @@ -export type Node = { +import { PngNodeType } from "../public/png/constants.js"; + +type Node = { /** * The type of this node. Typically an enum specific to the format. */ @@ -17,3 +19,5 @@ export type Node = { */ children?: ReadonlyArray>; }; + +export type PngNode = Node;