diff --git a/client/style/style.scss b/client/style/style.scss
index 562fe4d7..1b0159a8 100644
--- a/client/style/style.scss
+++ b/client/style/style.scss
@@ -4,7 +4,6 @@
@import "node_modules/flatpickr/dist/themes/airbnb";
@import "node_modules/codemirror/lib/codemirror";
@import "node_modules/frappe-datatable/dist/frappe-datatable";
-// @import "node_modules/octicons/build/build.css";
@import "./variables.scss";
@import "./indicators.scss";
diff --git a/client/style/tree.scss b/client/style/tree.scss
index 1df585db..c3f9a670 100644
--- a/client/style/tree.scss
+++ b/client/style/tree.scss
@@ -1,111 +1,123 @@
@import "./variables.scss";
-.tree {
+.tree-body {
padding: $spacer-3 $spacer-4;
}
-.tree li {
- list-style: none;
+f-tree, f-tree-node {
+ display: block;
}
-ul.tree-children {
- padding-left: $spacer-4;
-}
-
-.tree-link {
- cursor: pointer;
- display: flex;
- align-items: center;
- width: 100%;
-}
-
-.tree-link:hover {
+f-tree-node:hover {
background-color: $gray-100;
+ cursor: pointer;
}
-.tree-link .node-parent {
- color: $gray-600;
- width: 24px;
- height: 24px;
- text-align: center;
-}
+// .tree {
+// padding: $spacer-3 $spacer-4;
+// }
-.tree-link .node-leaf {
- color: $gray-400;
-}
+// .tree li {
+// list-style: none;
+// }
-.tree-link .node-parent, .tree-link .node-leaf {
- padding: $spacer-2;
-}
+// ul.tree-children {
+// padding-left: $spacer-4;
+// }
-.tree-link.active {
- a {
- color: $gray-600;
- }
-}
+// .tree-link {
+// cursor: pointer;
+// display: flex;
+// align-items: center;
+// width: 100%;
+// }
-.tree-hover {
- background-color: $gray-200;
- min-height: 20px;
- border: 1px solid $gray-600;
-}
+// .tree-link:hover {
+// background-color: $gray-100;
+// }
-.tree-node-toolbar {
- display: inline-block;
- padding: 0px 5px;
- margin-left: 15px;
- margin-bottom: -4px;
- margin-top: -8px;
-}
+// .tree-link .node-parent {
+// color: $gray-200;
+// width: 24px;
+// height: 24px;
+// }
-// @media (max-width: @screen-xs) {
-// ul.tree-children {
-// padding-left: 10px;
+// .tree-link .node-leaf {
+// color: $gray-400;
+// }
+
+// .tree-link .node-parent, .tree-link .node-leaf {
+// padding: $spacer-2;
+// }
+
+// .tree-link.active {
+// a {
+// color: $gray-600;
// }
// }
-// decoration
-// .tree, .tree-node {
-.tree.with-skeleton, .tree.with-skeleton .tree-node {
- position: relative;
+// .tree-hover {
+// background-color: $gray-200;
+// min-height: 20px;
+// border: 1px solid $gray-600;
+// }
- &.opened::before, &:last-child::after {
- content: '';
- position: absolute;
- top: 12px;
- left: 7px;
- height: calc(100% - 23px);
- width: 1px;
- background: $gray-400;
- z-index: -1;
- }
+// .tree-node-toolbar {
+// display: inline-block;
+// padding: 0px 5px;
+// margin-left: 15px;
+// margin-bottom: -4px;
+// margin-top: -8px;
+// }
- &:last-child::after {
- top: 11px;
- left: -13px;
- height: calc(100% - 15px);
- width: 3px;
- background: #fff;
- }
+// // @media (max-width: @screen-xs) {
+// // ul.tree-children {
+// // padding-left: 10px;
+// // }
+// // }
- &.opened > .tree-children > .tree-node > .tree-link::before {
- content: '';
- position: absolute;
- width: 18px;
- height: 1px;
- top: 10px;
- left: -12px;
- z-index: -1;
- background: $gray-400;
- }
-}
+// // decoration
+// // .tree, .tree-node {
+// .tree.with-skeleton, .tree.with-skeleton .tree-node {
+// position: relative;
-.tree.with-skeleton.opened::before {
- left: 22px;
- top: 33px;
- height: calc(100% - 67px);
-}
+// &.opened::before, &:last-child::after {
+// content: '';
+// position: absolute;
+// top: 12px;
+// left: 7px;
+// height: calc(100% - 23px);
+// width: 1px;
+// background: $gray-400;
+// z-index: -1;
+// }
-.tree-link.active ~ .balance-area {
- color: $gray-600 !important;
-}
+// &:last-child::after {
+// top: 11px;
+// left: -13px;
+// height: calc(100% - 15px);
+// width: 3px;
+// background: #fff;
+// }
+
+// &.opened > .tree-children > .tree-node > .tree-link::before {
+// content: '';
+// position: absolute;
+// width: 18px;
+// height: 1px;
+// top: 10px;
+// left: -12px;
+// z-index: -1;
+// background: $gray-400;
+// }
+// }
+
+// .tree.with-skeleton.opened::before {
+// left: 22px;
+// top: 33px;
+// height: calc(100% - 67px);
+// }
+
+// .tree-link.active ~ .balance-area {
+// color: $gray-600 !important;
+// }
diff --git a/client/ui/index.js b/client/ui/index.js
index e00074b8..5200cac0 100644
--- a/client/ui/index.js
+++ b/client/ui/index.js
@@ -64,6 +64,35 @@ module.exports = {
element.parentNode.removeChild(element);
},
+ on(element, event, selector, handler) {
+ if (!handler) {
+ handler = selector;
+ this.bind(element, event, handler);
+ } else {
+ this.delegate(element, event, selector, handler);
+ }
+ },
+
+ off(element, event, handler) {
+ element.removeEventListener(event, handler);
+ },
+
+ bind(element, event, callback) {
+ event.split(/\s+/).forEach(function (event) {
+ element.addEventListener(event, callback);
+ });
+ },
+
+ delegate(element, event, selector, callback) {
+ element.addEventListener(event, function (e) {
+ const delegatedTarget = e.target.closest(selector);
+ if (delegatedTarget) {
+ e.delegatedTarget = delegatedTarget;
+ callback.call(this, e, delegatedTarget);
+ }
+ });
+ },
+
empty(element) {
while (element.firstChild) {
element.removeChild(element.firstChild);
diff --git a/client/ui/tree.js b/client/ui/tree.js
index 10f731b1..6a8f171a 100644
--- a/client/ui/tree.js
+++ b/client/ui/tree.js
@@ -2,15 +2,106 @@ const frappe = require('frappejs');
const octicons = require('octicons');
const utils = require('frappejs/client/ui/utils');
-class Tree {
- constructor({parent, label, iconSet, withSkeleton, method}) {
+const iconSet = {
+ open: octicons["triangle-down"].toSVG({ width: "12", height: "12", "class": "tree-icon-open" }),
+ close: octicons["triangle-right"].toSVG({ width: "12", height: "12", "class": "tree-icon-closed" })
+};
+
+let TreeTemplate = document.createElement('template');
+TreeTemplate.innerHTML = `
+
+
+
+`;
+
+class Tree extends HTMLElement {
+ constructor() {
+ super();
+
+ this.attachShadow({ mode: 'open' })
+ .appendChild(TreeTemplate.content.cloneNode(true));
+ }
+}
+
+window.customElements.define('f-tree', Tree);
+
+let TreeNodeTemplate = document.createElement('template');
+TreeNodeTemplate.innerHTML = `
+
+
+
+`;
+
+
+class TreeNode extends HTMLElement {
+ static get observedAttributes() {
+ return ['label', 'expanded']
+ }
+
+ constructor() {
+ super();
+
+ let shadowRoot = this.attachShadow({ mode: 'open' });
+ shadowRoot.appendChild(TreeNodeTemplate.content.cloneNode(true));
+ this.iconEl = shadowRoot.querySelector('.tree-node-icon');
+ this.labelEl = shadowRoot.querySelector('.tree-node-label');
+ this.actionsEl = shadowRoot.querySelector('.tree-node-actions');
+ }
+
+ attributeChangedCallback(name, oldValue, newValue) {
+ console.log(name, oldValue, newValue);
+
+ switch(name) {
+ case 'label': {
+ this.labelEl.innerHTML = newValue || '';
+ break;
+ }
+
+ case 'expanded': {
+ this.expanded = this.hasAttribute('expanded');
+
+ if (this.expanded) {
+ this.iconEl.innerHTML = iconSet.open;
+ } else {
+ this.iconEl.innerHTML = iconSet.close;
+ }
+ break;
+ }
+
+ default: break;
+ }
+ }
+}
+
+window.customElements.define('f-tree-node', TreeNode);
+
+class TreeOld {
+ constructor({ parent, label, iconSet, withSkeleton, method }) {
Object.assign(this, arguments[0]);
this.nodes = {};
- if(!iconSet) {
+ if (!iconSet) {
this.iconSet = {
- open: octicons["triangle-down"].toSVG({ "width": 10, "class": "node-parent"}),
- closed: octicons["triangle-right"].toSVG({ "width": 5, "class": "node-parent"}),
- leaf: octicons["primitive-dot"].toSVG({ "width": 7, "class": "node-leaf"})
+ open: octicons["triangle-down"].toSVG({ "width": 10, "class": "node-parent" }),
+ closed: octicons["triangle-right"].toSVG({ "width": 5, "class": "node-parent" }),
+ leaf: octicons["primitive-dot"].toSVG({ "width": 7, "class": "node-leaf" })
};
}
this.make();
@@ -31,7 +122,7 @@ class Tree {
// this.loadChildren(this.selectedNode.parentNode, true);
}
- async loadChildren(node, deep=false) {
+ async loadChildren(node, deep = false) {
let children = !deep ? await this.method(node) : await this.getAllNodes(node);
this.renderNodeChildren(node, children);
}
@@ -40,7 +131,7 @@ class Tree {
dataList.map(d => { this.renderNodeChildren(this.nodes[d.parent], d.data); });
}
- renderNodeChildren(node, dataSet=[]) {
+ renderNodeChildren(node, dataSet = []) {
frappe.ui.empty(node.childrenList);
dataSet.forEach(data => {
@@ -67,7 +158,7 @@ class Tree {
expandable: expandable,
};
- if(parentNode){
+ if (parentNode) {
node.parentNode = parentNode;
node.parent = parentNode.childrenList;
node.isRoot = 0;
@@ -90,8 +181,8 @@ class Tree {
});
let iconHtml = '';
- if(this.iconSet) {
- iconHtml = node.expandable ? this.iconSet.closed : this.iconSet.leaf;
+ if (this.iconSet) {
+ iconHtml = node.expandable ? this.iconSet.closed : '';
}
let labelEl = ` ${node.label}`;
@@ -118,17 +209,17 @@ class Tree {
async onNodeClick(node, click = true) {
this.setSelectedNode(node);
- if(click) {
+ if (click) {
this.onClick && this.onClick(node);
}
await this.expandNode(node);
// select link
utils.activate(this.tree, node.treeLink, 'tree-link', 'active');
- if(node.toolbar) this.showToolbar(node);
+ if (node.toolbar) this.showToolbar(node);
}
async expandNode(node) {
- if(node.expandable) {
+ if (node.expandable) {
await this.toggleNode(node);
}
@@ -139,11 +230,11 @@ class Tree {
}
async toggleNode(node) {
- if(!node.loaded) await this.loadChildren(node);
+ if (!node.loaded) await this.loadChildren(node);
// expand children
- if(node.childrenList) {
- if(node.childrenList.innerHTML.length) {
+ if (node.childrenList) {
+ if (node.childrenList.innerHTML.length) {
if (node.expanded) {
node.childrenList.classList.add('hide');
} else {
@@ -152,7 +243,7 @@ class Tree {
}
// open close icon
- if(this.iconSet) {
+ if (this.iconSet) {
const oldIcon = node.treeLink.querySelector('svg');
const newIconKey = node.expanded ? 'closed' : 'open';
const newIcon = frappe.ui.create(this.iconSet[newIconKey]);
diff --git a/client/view/tree.js b/client/view/tree.js
index 58262119..d61d6fed 100644
--- a/client/view/tree.js
+++ b/client/view/tree.js
@@ -56,18 +56,83 @@ module.exports = class BaseTree extends BaseList {
}
renderTree(rootLabel) {
- this.tree = new Tree({
+ // const tree = new Tree();
+ // tree.getChildNodes = async node => {
+ // const children = await this.getData(node) || [];
+ // return children.map(d => ({
+ // label: d.name,
+ // value: d.name,
+ // expandable: d.isGroup
+ // }));
+ // }
+ // tree.rootNode = {
+ // label: rootLabel,
+ // value: rootLabel,
+ // isRoot: 1,
+ // expandable: 1
+ // }
+ // this.body.appendChild(tree);
+
+ this.rootNode = {
label: rootLabel,
- parent: this.body,
- method: async node => {
- const children = await this.getData(node) || [];
- return children.map(d => ({
- label: d.name,
- value: d.name,
- expandable: d.isGroup
- }));
- }
+ value: rootLabel,
+ isRoot: true,
+ expanded: true,
+ children: []
+ }
+
+ const getNodeHTML = node =>
+ `
+ `;
+
+ this.treeWrapper = frappe.ui.create('f-tree');
+
+ this.rootNode.el = frappe.ui.create(getNodeHTML(this.rootNode), {
+ inside: this.treeWrapper
});
+
+ this.treeWrapper = frappe.ui.create(`
+
+ ${getNodeHTML(this.rootNode)}
+
+ `);
+
+ this.body.appendChild(this.treeWrapper);
+
+ frappe.ui.on(this.treeWrapper, 'click', 'f-tree-node', async (e, treeNode) => {
+ if (treeNode.expanded) {
+ treeNode.removeAttribute('expanded');
+ } else {
+ treeNode.setAttribute('expanded', '');
+ }
+
+ let node = null;
+ // if (treeNode.hasAttribute('is-root')) {
+ // node = this.rootNode;
+ // } else {
+
+ // }
+
+
+ });
+
+
+ // this.tree = new Tree({
+ // label: rootLabel,
+ // parent: this.body,
+ // method: async node => {
+ // const children = await this.getData(node) || [];
+ // return children.map(d => ({
+ // label: d.name,
+ // value: d.name,
+ // expandable: d.isGroup
+ // }));
+ // }
+ // });
}
async getData(node) {
@@ -119,7 +184,7 @@ module.exports = class BaseTree extends BaseList {
});
this.page.body.addEventListener('click', (event) => {
- if(event.target.classList.contains('checkbox')) {
+ if (event.target.classList.contains('checkbox')) {
this.trigger('state-change');
}
})
@@ -138,7 +203,7 @@ module.exports = class BaseTree extends BaseList {
this.searchInput = this.toolbar.querySelector('input');
this.searchInput.addEventListener('keypress', (event) => {
- if (event.keyCode===13) {
+ if (event.keyCode === 13) {
this.refresh();
}
});
diff --git a/config/rollup.config.style.js b/config/rollup.config.style.js
index 2606b955..b219aa95 100644
--- a/config/rollup.config.style.js
+++ b/config/rollup.config.style.js
@@ -5,7 +5,6 @@ module.exports = {
format: 'cjs'
},
plugins: [
- require('rollup-plugin-sass')(),
require('rollup-plugin-postcss')({
extract: true,
plugins: [