commit 7ee7cf4a1d48b01b98587055d5a7a39ec07bf511 Author: Ray Date: Sun Sep 10 02:06:33 2023 +0100 Initial commit diff --git a/bbtreeview.css b/bbtreeview.css new file mode 100644 index 0000000..7cd4bd9 --- /dev/null +++ b/bbtreeview.css @@ -0,0 +1,72 @@ +ul.bbtreeview { + background-image: url("line.png"); + background-position: 4px 8px; + background-repeat: repeat-y; + list-style: none; + padding: 0; + margin: 0 0 0 8px; +} +ul.bbtreeview ul { + background-image: url("line.png"); + background-position: 4px 8px; + background-repeat: repeat-y; + list-style: none; + margin: 0 0 0 8px; + padding: 0; +} +ul.bbtreeview li { + background-position: 0px calc((1.2em - 9px)/2); + background-repeat: no-repeat; + cursor: default; + display: block; + padding-left: 14px; + width: 100%; +} +ul.bbtreeview li.c { + background-image: url("expand.png"); +} +ul.bbtreeview li.e { + background-image: url("collapse.png"); +} +ul.bbtreeview li.hidden { + display: none; +} +ul.bbtreeview div.li { + display: block; + height: 1.2em; + padding-left: 4px; +} +ul.bbtreeview div.li.highlighted { + background-color: rgb(169, 201, 249, 0.7); +} +ul.bbtreeview div.li > div.icon { + background-position: 0px center; + background-repeat: no-repeat; + display: inline-block; + height: 100%; + width: calc(16px); +} +ul.bbtreeview div.li > div.folder { + background-image: url("folder.png"); +} + +ul.bbtreeview li > div.li > div.checkbox { + background-image: url("folder.png"); +} +ul.bbtreeview li.x > div.li > div.checkbox { + background-image: url("folder.png"); +} + +ul.bbtreeview div.li > span { + -webkit-user-select: none; + -ms-user-select: none; + user-select: none; + display: inline-block; + height: 1.2em; + line-height: 1.2em; + overflow: hidden; + padding-left: 6px; + text-overflow: ellipsis; + vertical-align: top; + white-space: nowrap; +} \ No newline at end of file diff --git a/bbtreeview.js b/bbtreeview.js new file mode 100644 index 0000000..686759e --- /dev/null +++ b/bbtreeview.js @@ -0,0 +1,386 @@ +/** + * BBTreeview + * @version v0.1.0.223 (2023/09/08 2027) + */ +function BBTreeview(options) +{ + const a = this; + + a.initialise(options); +}; + +BBTreeview.prototype.AddItem = function(options) { + const a = this; + const _options = a.getOptions(options); + + // Don't add duplicate + if (a.Find(_options.ID) != null) { + return false; + } + + // Check parent exists + let parentNode = null; + if (_options.ParentID != null) { + parentNode = a.Find(_options.ParentID); + if (parentNode == null) { + return false; + } + } + + if (parentNode == null) { + parentNode = a.Container; + } else { + parentNode = parentNode.ChildNode; + } + + const nodeHtml = a.generateNodeHtml(_options); + + // Add node + a.appendHtml(parentNode, nodeHtml); + + const node = a.Find(_options.ID); + + // Events + node.Node.addEventListener("click", function(e){ + e.stopPropagation(); + e.preventDefault(); + + if (!a.isTag(e.target, "li")) { + return; + } + + if ((e.offsetX < 0) || (e.offsetX > 16) || (e.offsetY < 0) || (e.offsetY > 16)) { + return; + } + + const myNode = a.getNode(e.target); + if (myNode == null) { + return; + } + + a.Toggle(myNode); + }); + + // node.Label.addEventListener("click", function(e){ + // e.stopPropagation(); + // e.preventDefault(); + + // }); + + // Highlighting + node.Container.addEventListener("mousedown", function(e){ + e.stopPropagation(); + e.preventDefault(); + + const myNode = a.getNode(e.target); + if (myNode == null) { + return; + } + + a.Container.querySelectorAll("div.highlighted").forEach(function(e) { + e.classList.remove("highlighted"); + }); + + myNode.Container.classList.add("highlighted"); + }); + + // Toggle + node.Container.addEventListener("dblclick", function(e){ + e.stopPropagation(); + e.preventDefault(); + + const myNode = a.getNode(e.target); + if (myNode == null) { + return; + } + + a.Toggle(myNode); + }); + + // Invalidate state + if (node.ParentNode != null) { + if (node.ParentNode.classList.contains("c")) { + node.Node.classList.add("hidden"); + } else if (node.ParentNode.classList.contains("e")) { + node.Node.classList.remove("hidden"); + } else { + node.ParentNode.classList.add("e"); + node.Node.classList.remove("hidden"); + } + } + + return true; +}; + +BBTreeview.prototype.Remove = function(id) { + const a = this; + + const node = a.Find(id); + if (node == null) { + return false; + } + + node.Node.parentNode.removeChild(node.Node); + + if (node.ParentNode != null) { + if (node.ParentNode.classList.contains("e")) { + node.ParentNode.classList.remove("e"); + } + + if (node.ParentNode.classList.contains("c")) { + node.ParentNode.classList.remove("c"); + } + } + + return true; +}; + + +BBTreeview.prototype.Default = function() { + return { + TreeviewOptions: { + ID: null, + ShowCheckbox: false + }, + TreeNodeOptions: { + ID: null, + ParentID: null, + Name: "", + Hint: "", + Icon: "folder", + Checked: false + } + }; +}; + + +BBTreeview.prototype.CollapseNode = function(node) { + const a = this; + + node.Node.classList.remove("e"); + node.Node.classList.add("c"); + + node.Items.forEach(function(e) { + e.classList.add("hidden"); + }); +}; + +BBTreeview.prototype.ExpandNode = function(node) { + const a = this; + + node.Node.classList.remove("c"); + node.Node.classList.add("e"); + + node.Items.forEach(function(e) { + e.classList.remove("hidden"); + }); +}; + +BBTreeview.prototype.Find = function(id) { + const a = this; + + const node = a.Container.querySelectorAll("li[data-bbtv-id='" + id + "']"); + + if (node.length <= 0) { + return null; + } + + let response = { + ID: id, + Node: node[0], + ParentNode: a.getParentNode(node[0]), + ChildNode: a.getChildNode(node[0]), + Container: node[0].querySelectorAll("div.li")[0], + Label: node[0].querySelectorAll("span")[0], + Items: a.getChildren(node[0]) + }; + + // console.log(response); + + return response; +}; +BBTreeview.prototype.Toggle = function(node) { + const a = this; + + if (node.Node.classList.contains("c")) { + a.ExpandNode(node); + } else if (node.Node.classList.contains("e")) { + a.CollapseNode(node); + } else { + // do nothing + } +}; + + +BBTreeview.prototype.initialise = function(options) { + var a = this; + + a.Options = Object.assign(a.Default().TreeviewOptions, options); + + a.Container = null; + + let treeview = document.getElementsByTagName("body")[0].querySelectorAll(a.Options.ID); + if (treeview.length <= 0) { + return; + } + + if (treeview[0] == null) { + return; + } + + a.Container = treeview[0]; + + a.Container.innerHTML = ""; + + a.Container = a.Container.querySelectorAll("ul.bbtreeview")[0]; +}; + +BBTreeview.prototype.appendHtml = function(el, html) { + let node = document.createElement('template'); + node.innerHTML = html; + + node = node.content.firstChild; + + el.appendChild(node); +}; + +BBTreeview.prototype.generateID = function() { + return "treeviewItem" + (Math.floor(Math.random() * 1000001) + 100).toString(); +}; + +BBTreeview.prototype.generateNodeHtml = function(options) { + const a = this; + + let html = '
  • '; + html += '
    ' + + if (a.Options.ShowCheckbox) { + html += '
    '; + } + + html += '
    '; + html += '' + options.Name + ''; + html += '
    '; + html += ''; + html += '
  • '; + + return html; +}; + +BBTreeview.prototype.getChildNode = function(node) { + const a = this; + + let result = node.querySelectorAll("ul"); + if (result.length <= 0) { + return null; + } + + return result[0]; +}; + +BBTreeview.prototype.getChildren = function(node) { + const a = this; + + const childNode = a.getChildNode(node); + if (childNode == null) { + return []; + } + + let nodes = childNode.querySelectorAll("li"); + if (nodes.length <= 0) { + return []; + } + + let result = []; + nodes.forEach(function(e) { + if (typeof(e.parentNode) == "undefined") { + return; + } + + if (e.parentNode != childNode) { + return; + } + + result.push(e); + }); + + return result; +}; + +BBTreeview.prototype.getNode = function(el) { + const a = this; + + let node = null; + if (a.isTag(el, "li")) { + node = el; + } else { + node = a.parentsUntilTagName(el, "li"); + } + + const id = node.getAttribute("data-bbtv-id"); + + if (a.isNullOrWhitespace(id)) { + return null; + } + + return a.Find(id); +}; + +BBTreeview.prototype.getOptions = function(options) { + const a = this; + + let _options = Object.assign(a.Default().TreeNodeOptions, options); + if (_options.ID == null) { + _options.ID = a.generateID(); + } + + return _options; +}; + +BBTreeview.prototype.getParentNode = function(node) { + const a = this; + + return a.parentsUntilTagName(node, "li"); +}; + +BBTreeview.prototype.isNullOrWhitespace = function(value) { + if (typeof (value) == "undefined") { + return true; + } + + if (value == null) { + return true; + } + + return (value.trim().length <= 0); +}; + +BBTreeview.prototype.isTag = function(el, tagName) { + return (el.tagName.toLowerCase() == tagName); +}; + +BBTreeview.prototype.parentsUntilTagName = function(el, tagName) { + const a = this; + + let node = el; + + while (true) { + node = node.parentNode; + + if (typeof(node) == "undefined") { + break; + } + + if (a.isTag(node, "ul")) { + if (node.classList.contains("bbtreeview")) { + return null; + } + } + + if (a.isTag(node, tagName)) { + break; + } + } + + return node; +}; \ No newline at end of file diff --git a/collapse.png b/collapse.png new file mode 100644 index 0000000..d8328c3 Binary files /dev/null and b/collapse.png differ diff --git a/demo-test.html b/demo-test.html new file mode 100644 index 0000000..c27ac33 --- /dev/null +++ b/demo-test.html @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + +
    + + + + + + + \ No newline at end of file diff --git a/expand.png b/expand.png new file mode 100644 index 0000000..72f7767 Binary files /dev/null and b/expand.png differ diff --git a/folder.png b/folder.png new file mode 100644 index 0000000..8527862 Binary files /dev/null and b/folder.png differ diff --git a/line.png b/line.png new file mode 100644 index 0000000..7deb6c7 Binary files /dev/null and b/line.png differ diff --git a/src/collapse.png b/src/collapse.png new file mode 100644 index 0000000..9307b79 Binary files /dev/null and b/src/collapse.png differ diff --git a/src/expand.png b/src/expand.png new file mode 100644 index 0000000..8d92b45 Binary files /dev/null and b/src/expand.png differ diff --git a/src/folder.svg b/src/folder.svg new file mode 100644 index 0000000..197ea74 --- /dev/null +++ b/src/folder.svg @@ -0,0 +1,44 @@ + + + + + + diff --git a/src/icon.svg b/src/icon.svg new file mode 100644 index 0000000..852332a --- /dev/null +++ b/src/icon.svg @@ -0,0 +1,62 @@ + + + + + + +