Cat/elements/cat-tree.html

311 lines
9.1 KiB
HTML

<cat-template>
<cat-tree-cell><cat-checkbox><cat-inherits checked=folded></cat-inherits></cat-checkbox></cat-tree-cell>
<cat-children></cat-children>
</cat-template>
<script>
/*
<a-tree>
<a-structure>
<a-cell> Name </a-cell>
<a-cell> Data </a-cell>
</a-structure>
<a-row>
<a-cell> Things </a-cell>
<a-cell> Woo </a-cell>
<a-row>
<a-cell> Things 2 </a-cell>
<a-cell> Woo 2 </a-cell>
<a-row>
</a-row>
</a-tree>
*/
customElements.define('cat-tree', class extends HTMLElement {
static get observedAttributes() { return []; }
attributeChangedCallback(attr, oldValue, newValue) { this[attr] = newValue; }
constructor() {
super();
}
connectedCallback() {
//
var rows = this.querySelectorAll('cat-tree-row');
// Set the depth attribute of each row.
for (var i = 0; i < rows.length; i++) {
if (!rows[i].hasAttribute('depth')) {
var depth = 0;
var parent = rows[i].parentNode;
while (parent && parent.tagName !== 'CAT-TREE') {
depth++;
parent = parent.parentNode;
}
rows[i].setAttribute('depth', depth);
}
}
// Move all declared rows to be as direct children to the tree.
for (var i = 0; i < rows.length; i++) {
this.appendChild(rows[i]);
}
// Set up observer for added rows
new MutationObserver(e => {
for (var i = 0; i < e[0].addedNodes.length; i++) {
var node = e[0].addedNodes[i];
if (node.tagName === 'CAT-TREE-ROW') {
if (!node.hasAttribute('depth')) node.setAttribute('depth', 0);
}
}
}).observe(this, { childList: true });
}
setHeadCells(properties=[]) {
this.properties = properties;
this.clear(true);
var head = document.createElement('cat-tree-head');
// folding
head.appendChild(document.createElement('cat-tree-cell'));
for (let i = 0; i < properties.length; i++) {
var cell = document.createElement('cat-tree-cell');
cell.innerHTML = properties[i];
head.appendChild(cell);
}
this.appendChild(head);
}
cloneDomToRows(el, properties=[]) {
this.properties = properties;
// Remove old children
this.clear(true);
//
var head = document.createElement('cat-tree-head');
// folding
head.appendChild(document.createElement('cat-tree-cell'));
for (let i = 0; i < properties.length; i++) {
var cell = document.createElement('cat-tree-cell');
cell.innerHTML = properties[i];
head.appendChild(cell);
}
this.appendChild(head);
// Iterate over the target dom and create rows for each element
for (let i = 0; i < el.children.length; i++) {
var row = document.createElement('cat-tree-row');
this.appendChild(row);
row.targetNode = el.children[i];
row.cloneDomToRows(el.children[i], properties);
}
this.flattenRows();
this.setupRowsCallbacks();
}
flattenRows() {
let rows = this.querySelectorAll('cat-tree-row');
var last = null;
var rowlist = [];
for (let i = 0; i < rows.length; i++) {
rows[i].setAttribute('depth', rows[i].getDepth());
rowlist.push(rows[i]);
}
for (let i = 0; i < rowlist.length; i++) {
this.appendChild(rowlist[i]);
}
}
setupRowsCallbacks() {
let rows = this.querySelectorAll('cat-tree-row');
for (let i = 0; i < rows.length; i++) {
this.setupRowCallbacks(rows[i]);
}
}
setupRowCallbacks(row) {
console.log(row);
row.addEventListener('click', e => {
this.dispatchEvent(new CustomEvent('click-row', { detail: row }));
this.selectedRow = row;
}, false);
row.addEventListener('contextmenu', e => {
this.dispatchEvent(new CustomEvent('contextmenu-row', { detail: row }));
}, false);
}
getMatchingRow(el) {
let rows = this.querySelectorAll('cat-tree-row');
for (let i = 0; i < rows.length; i++) {
if (rows[i].targetNode === el) return rows[i];
}
}
removeRow(row) {
if (row.getFirstChild()) {
this.removeRow(row.getFirstChild());
}
this.dispatchEvent(new CustomEvent('remove-row', { detail: {row: row }}));
this.removeChild(row);
if (this.selectedRow === row) this.selectedRow = null;
}
addRow(properties=[], pos) {
var row = document.createElement('cat-tree-row');
this.appendChild(row);
for (var p = 0; p < this.properties.length; p++) {
var cell = document.createElement('cat-tree-cell');
if (properties[p]) {
cell.innerHTML = properties[p];
}
row.appendChild(cell);
}
this.setupRowCallbacks(row);
return row;
}
clear(removeHead=false) {
if (removeHead) {
while (this.firstChild) this.removeChild(this.firstChild);
} else {
for (var i = 0; i < this.children.length; i++) {
if (this.children[i].tagName === 'CAT-TREE-HEAD') continue;
this.removeChild(this.children[i]);
i--;
}
}
}
get selectedRow() {
return this._selectedRow;
}
set selectedRow(row) {
if (this._selectedRow) {
this._selectedRow.removeAttribute('selected');
}
this._selectedRow = row;
if (row) {
this._selectedRow.setAttribute('selected', '');
}
this.dispatchEvent(new CustomEvent('selected-row', { detail: row }));
}
});
customElements.define('cat-tree-head', class extends HTMLElement {
constructor() {
super();
}
connectedCallback() {
}
});
(function() {
let template = document.currentScript.ownerDocument.querySelector('cat-template');
customElements.define('cat-tree-row', class extends HTMLElement {
static get observedAttributes() { return ['depth', 'folded', 'selected']; }
attributeChangedCallback(attr, oldValue, newValue) {
if (attr == 'depth') this.depth = parseInt(newValue);
else if (attr == 'folded') this.folded = newValue;
}
constructor() {
super();
this.depth = 0;
}
connectedCallback() {
template.cloneTo(this);
}
templatedCallback() {
if (this.getFirstChild()) {
this.enableFoldButton();
} else {
this.disableFoldButton();
}
this.querySelector('cat-checkbox').addEventListener('click', e => {
if (this.hasAttribute('folded')) {
this.unfold();
} else {
this.fold();
}
e.preventDefault();
e.stopPropagation();
}, true);
/*new MutationObserver(e => {
console.log('wow');
for (var i = 0; i < e[0].addedNodes.length; i++) {
var node = e[0].addedNodes[i];
console.log(node.tagName);
if (node.tagName === 'CAT-TREE-ROW') {
this.enableFoldButton();
node.setAttribute('depth', this.depth+1);
/*let parent = this.parentNode;
while (parent && parent.tagName !== 'CAT-TREE') {
parent = parent.parentNode;
}
parent.insertBefore(node, this.getToLastSibling());
}
}
}).observe(this, { childList: true });*/
}
enableFoldButton() {
this.querySelector('cat-checkbox').removeAttribute('hidden');
}
disableFoldButton() {
this.querySelector('cat-checkbox').setAttribute('hidden', '');
}
fold() {
let next = this.nextSibling;
while (next && next.depth >= this.depth) {
next.setAttribute('hidden', '');
next = next.nextSibling;
}
this.setAttribute('folded', '');
}
unfold() {
let next = this.nextSibling;
while (next && next.depth >= this.depth) {
next.removeAttribute('hidden');
next = next.nextSibling;
}
this.removeAttribute('folded');
}
getToLastSibling() {
let next = this.nextSibling;
while (next && next.depth >= this.depth) {
next = next.nextSibling;
}
return next;
}
getFirstChild() {
if (this.nextSibling && parseInt(this.nextSibling.getAttribute('depth')) > this.depth) {
return this.nextSibling;
}
return null;
}
getLastChild() {
var first = this.getFirstChild();
if (!first) return null;
return first.getToLastSibling();
}
getDepth() {
var depth = 0;
var parent = this.parentNode;
while (parent && parent.tagName !== 'CAT-TREE') {
depth++;
parent = parent.parentNode;
}
return depth;
}
cloneDomToRows(el, properties=[]) {
this.targetNode = el;
for (var p = 0; p < properties.length; p++) {
var cell = document.createElement('cat-tree-cell');
if (properties[p] === 'tagName') {
cell.innerHTML = el.tagName.toLowerCase();
} else {
cell.innerHTML = el.getAttribute(properties[p]);
}
this.appendChild(cell);
}
for (let i = 0; i < el.children.length; i++) {
let row = document.createElement('cat-tree-row');
this.addRow(row);
row.cloneDomToRows(el.children[i], properties);
}
}
addRow(row) {
this.enableFoldButton();
row.setAttribute('depth', this.depth+1);
this.appendChild(row);
}
});
customElements.define('cat-tree-cell', class extends HTMLElement {
constructor() {
super();
}
});
})();
</script>