311 lines
9.1 KiB
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>
|