diff options
Diffstat (limited to 'vfs/vfs.js')
| -rw-r--r-- | vfs/vfs.js | 202 |
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"; + } +} |
