aboutsummaryrefslogtreecommitdiff
path: root/vfs/vfs.js
diff options
context:
space:
mode:
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";
+ }
+}