aboutsummaryrefslogtreecommitdiff
path: root/vfs/vfs.js
diff options
context:
space:
mode:
authorShulhan <ms@kilabit.info>2024-09-15 14:32:48 +0700
committerShulhan <ms@kilabit.info>2024-09-15 14:32:48 +0700
commitd1e96e09438b4a5c7580b86c469e817a61be991f (patch)
tree4d81fb2fd62207bbb9162b81083c721ec8fd8e29 /vfs/vfs.js
parent1cc9c9dd68a3a59c685505228336430624608852 (diff)
downloadpakakeh.ts-d1e96e09438b4a5c7580b86c469e817a61be991f.tar.xz
all: commit all generate JavaScript files
This is to simplify development on third party where they can clone and include the file directly without installing or running anything to build the files.
Diffstat (limited to 'vfs/vfs.js')
-rw-r--r--vfs/vfs.js202
1 files changed, 202 insertions, 0 deletions
diff --git a/vfs/vfs.js b/vfs/vfs.js
new file mode 100644
index 0000000..440a8b5
--- /dev/null
+++ b/vfs/vfs.js
@@ -0,0 +1,202 @@
+// SPDX-FileCopyrightText: 2021 M. Shulhan <ms@kilabit.info>
+// SPDX-License-Identifier: GPL-3.0-or-later
+const CLASS_VFS_PATH = "wui_vfs_path";
+const CLASS_VFS_LIST = "wui_vfs_list";
+export class WuiVfs {
+ constructor(opts) {
+ this.opts = opts;
+ const el = document.getElementById(opts.id);
+ if (!el) {
+ console.error("WuiVfs: element id", opts.id, "not found");
+ return;
+ }
+ this.el = el;
+ this.com_path = new WuiVfsPath((path) => {
+ this.openDir(path);
+ });
+ this.el.appendChild(this.com_path.el);
+ this.com_list = new WuiVfsList((node) => {
+ this.openNode(node);
+ });
+ this.el.appendChild(this.com_list.el);
+ }
+ // filter the VFS list based on text value.
+ filter(text) {
+ this.com_list.filter(text);
+ }
+ // openNode is a handler that will be called when a node is clicked
+ // inside the WuiVfsList.
+ openNode(node) {
+ if (node.is_dir) {
+ this.openDir(node.path);
+ }
+ else {
+ this.opts.openNode(node);
+ }
+ }
+ // openDir is a handler that will be called when a path is clicked
+ // inside the WuiVfsPath.
+ async openDir(path) {
+ const res = await this.opts.open(path, true);
+ if (res.code != 200) {
+ return;
+ }
+ this.set(res.data);
+ }
+ set(node) {
+ if (node.is_dir) {
+ this.com_path.open(node);
+ this.com_list.open(node);
+ }
+ }
+}
+class WuiVfsList {
+ constructor(onClick) {
+ this.onClick = onClick;
+ this.node = null;
+ this.el = document.createElement("div");
+ this.el.classList.add(CLASS_VFS_LIST);
+ this.el.style.borderWidth = "1px";
+ this.el.style.borderStyle = "solid";
+ this.el.style.borderColor = "silver";
+ }
+ // filter re-render the list by including only the node that have name
+ // match with "text".
+ filter(text) {
+ const regexp = new RegExp(text, "i");
+ for (const elChild of this.el.children) {
+ if (regexp.test(elChild.innerHTML)) {
+ elChild.removeAttribute("hidden");
+ }
+ else {
+ elChild.setAttribute("hidden", "true");
+ }
+ }
+ }
+ open(node) {
+ this.node = node;
+ this.el.innerHTML = "";
+ if (!this.node) {
+ return;
+ }
+ if (!this.node.childs) {
+ return;
+ }
+ for (const c of this.node.childs) {
+ const el = document.createElement("div");
+ el.style.padding = "1em";
+ el.style.cursor = "pointer";
+ el.setAttribute("tabindex", "0");
+ el.innerText = c.name;
+ if (c.is_dir) {
+ el.innerText += "/";
+ el.style.backgroundColor = "cornsilk";
+ }
+ el.onclick = () => {
+ this.onClick(c);
+ };
+ el.onkeydown = (ev) => {
+ if (ev.key !== "Enter") {
+ return true;
+ }
+ this.onClick(c);
+ this.el.focus();
+ return false;
+ };
+ el.onblur = () => {
+ this.onBlur(c, el);
+ };
+ el.onmouseout = () => {
+ this.onBlur(c, el);
+ };
+ el.onfocus = () => {
+ this.onFocus(el);
+ };
+ el.onmouseover = () => {
+ this.onFocus(el);
+ };
+ this.el.appendChild(el);
+ }
+ }
+ onBlur(c, el) {
+ if (c.is_dir) {
+ el.style.backgroundColor = "cornsilk";
+ }
+ else {
+ el.style.backgroundColor = "white";
+ }
+ }
+ onFocus(el) {
+ el.style.backgroundColor = "aliceblue";
+ }
+}
+class WuiVfsPath {
+ constructor(onClick) {
+ this.el = document.createElement("div");
+ this.el.classList.add(CLASS_VFS_PATH);
+ this.el.style.borderWidth = "1px";
+ this.el.style.borderStyle = "solid";
+ this.el.style.borderColor = "silver";
+ this.el.style.overflow = "auto";
+ this.el.style.padding = "10px 10px 20px 0px";
+ this.el.style.whiteSpace = "nowrap";
+ this.onClick = onClick;
+ }
+ open(node) {
+ this.el.innerHTML = "";
+ let paths = [];
+ if (node.path == "/") {
+ paths.push(node.path);
+ }
+ else {
+ paths = node.path.split("/");
+ }
+ paths.forEach((path, x) => {
+ let fullPath = "";
+ let p = "";
+ if (x == 0) {
+ p = "/";
+ fullPath = "/";
+ }
+ else {
+ p = path;
+ fullPath = paths.slice(0, x + 1).join("/");
+ }
+ const crumb = document.createElement("span");
+ crumb.style.padding = "1em";
+ crumb.style.cursor = "pointer";
+ crumb.setAttribute("tabindex", "0");
+ crumb.innerHTML = p;
+ crumb.onclick = () => {
+ this.onClick(fullPath);
+ };
+ crumb.onkeydown = (ev) => {
+ if (ev.key !== "Enter") {
+ return true;
+ }
+ this.onClick(fullPath);
+ this.el.focus();
+ return false;
+ };
+ crumb.onmouseout = () => {
+ this.onBlur(crumb);
+ };
+ crumb.onblur = () => {
+ this.onBlur(crumb);
+ };
+ crumb.onmouseover = () => {
+ this.onFocus(crumb);
+ };
+ crumb.onfocus = () => {
+ this.onFocus(crumb);
+ };
+ this.el.appendChild(crumb);
+ });
+ }
+ onBlur(crumb) {
+ crumb.style.backgroundColor = "white";
+ }
+ onFocus(crumb) {
+ crumb.style.backgroundColor = "aliceblue";
+ }
+}