diff options
| author | Shulhan <ms@kilabit.info> | 2024-09-15 14:32:48 +0700 |
|---|---|---|
| committer | Shulhan <ms@kilabit.info> | 2024-09-15 14:32:48 +0700 |
| commit | d1e96e09438b4a5c7580b86c469e817a61be991f (patch) | |
| tree | 4d81fb2fd62207bbb9162b81083c721ec8fd8e29 /vfs/vfs.js | |
| parent | 1cc9c9dd68a3a59c685505228336430624608852 (diff) | |
| download | pakakeh.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.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"; + } +} |
