Skip to content

Instantly share code, notes, and snippets.

@aaronanderson
Last active May 22, 2017 00:57
Show Gist options
  • Save aaronanderson/7e6b4dc881a3b9aff25fa926152a33f7 to your computer and use it in GitHub Desktop.
Save aaronanderson/7e6b4dc881a3b9aff25fa926152a33f7 to your computer and use it in GitHub Desktop.
A simple Polymer 2.0 collapsible tree
<link rel="import" href="../polymer/polymer-element.html">
<link rel="import" href="../iron-collapse/iron-collapse.html">
<link rel="import" href="../paper-item/paper-icon-item.html">
<link rel="import" href="../paper-item/paper-item-body.html">
<link rel="import" href="../iron-flex-layout/iron-flex-layout-classes.html">
<link rel="import" href="../iron-icons/iron-icons.html">
<link rel="import" href="../iron-icon/iron-icon.html">
<dom-module id="intworkspace-tree">
<template id="treeView">
<style include="iron-flex iron-flex-alignment">
paper-icon-item {
--paper-item-min-height: var(--intworkspace-tree-margin,30px);
--paper-item-icon-width : var(--intworkspace-tree-margin,30px);
}
paper-icon-item:focus::before,
paper-icon-item:focus::after {
color: inherit;
opacity: 0;
}
.node {
margin-left: var(--intworkspace-tree-margin,30px);;
}
</style>
<slot id="labelView"></slot>
<template id="nodeView">
<div class="layout vertical">
<paper-icon-item on-tap="nodeSelected">
<iron-icon icon="expand-less" slot="item-icon" hidden$="[[!hasNodes(node)]]"></iron-icon>
<!-- label goes here-->
</paper-icon-item>
<iron-collapse class="node" opened hidden$="[[!hasNodes(node)]]">
<intworkspace-tree tree="[[node.nodes]]" embedded></intworkspace-tree>
</iron-collapse>
</div>
</template>
</template>
<script>
class IntTree extends Polymer.OptionalMutableData(Polymer.Element) {
static get is() {
return 'intworkspace-tree';
}
static get properties() {
return {
tree: {
type: Array,
value: []
},
viewTemplateClass: {
type: Object
},
labelTemplateClass: {
type: Object
}
};
}
static get observers() {
return [
'_renderTreeChanged(tree.*)',
]
}
_renderTreeChanged() {
if (!this.viewTemplateClass || !this.labelTemplateClass) {
return;
}
//clear out previous nodes in case of refresh
Array.from(this.shadowRoot.children).forEach((c) => {
if (c instanceof HTMLDivElement) {
this.shadowRoot.removeChild(c);
}
});
if (!this.tree) {
return;
}
for (var i = 0; i < this.tree.length; i++) {
let viewInstance = new this.viewTemplateClass({
n: i,
node: this.tree[i]
});
viewInstance.node = this.tree[i];
viewInstance.n = i;
let labelInstance = new this.labelTemplateClass({
n: i,
node: this.tree[i]
});
labelInstance.node = this.tree[i];
labelInstance.n = i;
var labelInsert = viewInstance.root.querySelector("paper-icon-item");
labelInsert.appendChild(labelInstance.root);
var subTreeInsert = viewInstance.root.querySelector("intworkspace-tree[embedded]");
subTreeInsert.viewTemplateClass = this.viewTemplateClass;
subTreeInsert.labelTemplateClass = this.labelTemplateClass;
subTreeInsert._debouncer = Polymer.Debouncer.debounce(
subTreeInsert._debouncer,
Polymer.Async.timeOut.after(100),
subTreeInsert._renderTreeChanged.bind(subTreeInsert));
this.shadowRoot.appendChild(viewInstance.root);
}
}
ready() {
super.ready();
if (!this.hasAttribute("embedded")) {
//http://t-code.pl/blog/2015/08/polymer-templatizer/
let labelView = this.$.labelView.assignedNodes().find((e) => {
return e instanceof HTMLTemplateElement;
});
if (!labelView) {
throw new Error('intworkspace-tree requires a <template> child');
}
this.viewTemplateClass = Polymer.Templatize.templatize(this.$.nodeView, this, {
mutableData: true,
parentModel: true,
});
this.labelTemplateClass = Polymer.Templatize.templatize(labelView, this, {
mutableData: true,
parentModel: true,
});
this._debouncer = Polymer.Debouncer.debounce(
this._debouncer,
Polymer.Async.timeOut.after(100),
this._renderTreeChanged.bind(this));
}
}
hasNodes(node) {
//console.log('hasNodes', node, node.nodes != null);
return node.nodes != null && node.nodes.length > 0;
}
nodeSelected(e) {
let collapse = e.currentTarget.parentNode.querySelector("iron-collapse");
let nodeIcon = e.currentTarget.parentNode.querySelector("iron-icon");
//console.log('Node clicked', e, collapse, e.model.node);
if (collapse && nodeIcon) {
//collapse.style.backgroundColor = '#FF6600';
collapse.toggle();
if (collapse.opened) {
nodeIcon.icon = "expand-less";
} else {
nodeIcon.icon = "expand-more";
}
}
}
}
window.customElements.define(IntTree.is, IntTree);
</script>
</dom-module>
<link rel="import" href="../polymer/polymer-element.html">
<!--<link rel="import" href="../polymer/lib/elements/dom-if.html">-->
<!--<link rel="import" href="../polymer/lib/elements/dom-repeat.html">-->
<link rel="import" href="../paper-item/paper-item-body.html">
<link rel="import" href="../paper-button/paper-button.html">
<link rel="import" href="intworkspace-tree.html">
<!--
`tree-test`
@demo demo/index.html
-->
<dom-module id="tree-test">
<template>
<style>
:host {
display: block;
}
</style>
<intworkspace-tree tree="{{testTree}}">
<template><paper-item-body>[[node.name]]</paper-item-body></template>
</intworkspace-tree>
<div>
<paper-button raised on-tap="reload">Reload</paper-button>
</div>
</template>
<script>
/** @polymerElement */
class TreeTest extends Polymer.Element {
static get is() {
return 'tree-test';
}
random(min, max) {
return Math.random() * (max - min) + min;
}
createLevel(newTree, currentDepth) {
if (currentDepth == 4) {
return;
}
var numNodes = this.random(currentDepth == 0 ? 1 : 0, 4);
var newDepth = currentDepth + 1;
for (var i = 1; i <= numNodes; i++) {
var id = this.testNodeId++;
var childTree = [];
this.createLevel(childTree, newDepth);
var node = {
id: id,
name: `Node ${id}`,
nodes: childTree
}
newTree.push(node);
}
}
reload() {
this.testNodeId = 1;
var newTree = [];
this.createLevel(newTree, 0);
console.log("new tree", JSON.stringify(newTree));
this.set("testTree", newTree);
}
static get properties() {
return {
testTree: {
type: Array,
value: []
},
testNodeId: {
type: Number
}
};
}
ready() {
super.ready();
this.reload();
}
}
window.customElements.define(TreeTest.is, TreeTest);
</script>
</dom-module>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment