@stimulus-library/controllers
Version:
A library of useful controllers for Stimulus
92 lines (91 loc) • 2.76 kB
JavaScript
import { installClassMethods, useMutationObserver } from "@stimulus-library/mixins";
import { BaseController } from "@stimulus-library/utilities";
export class TreeViewController extends BaseController {
get defaultActiveClasses() {
return ["active"];
}
get defaultCollapsedClasses() {
return ["collapsed"];
}
initialize() {
this._nodeClicked = this._nodeClicked.bind(this);
}
connect() {
installClassMethods(this);
useMutationObserver(this, this.el, this.mutate, { subtree: true, childList: true });
this._setup();
}
disconnect() {
this._teardown();
}
_setup() {
this._setupNode(this.el);
}
_setupNode(el) {
const process = (e) => {
const parent = e.parentElement;
if (parent) {
if (!this._nodeActive(parent)) {
this._hideNode(parent);
}
parent.removeEventListener("click", this._nodeClicked);
parent.addEventListener("click", this._nodeClicked);
}
};
if (el.tagName === "UL" || el.tagName === "OL") {
process(el);
}
el.querySelectorAll("ul, ol").forEach(e => process(e));
}
_teardown() {
this.el.querySelectorAll("ul, ol, li").forEach((el) => this._teardownNode(el));
}
_teardownNode(el) {
[el, ...Array.from(el.querySelectorAll("ul, ol, li"))].forEach((x) => {
x.removeEventListener("click", this._nodeClicked);
this.removeActiveClasses(x);
this.removeCollapsedClasses(x);
});
}
_nodeClicked(event) {
if (event) {
event.stopImmediatePropagation();
}
const el = event.target;
if (!el || !this._hasNested(el)) {
return;
}
if (this._nodeActive(el)) {
this._hideNode(el);
}
else {
this._showNode(el);
}
}
_nodeActive(el) {
return this.activeClassesPresent(el);
}
_showNode(el) {
this.removeCollapsedClasses(el);
this.addActiveClasses(el);
}
_hideNode(el) {
this.removeActiveClasses(el);
this.addCollapsedClasses(el);
}
_hasNested(el) {
return el.querySelectorAll("ul, ol").length > 0;
}
mutate(entries) {
for (const mutation of entries) {
if (mutation.type === "childList") {
Array.from(mutation.addedNodes || []).forEach(el => this._setupNode(el));
Array.from(mutation.removedNodes || []).forEach(el => this._teardownNode(el));
}
}
}
}
TreeViewController.classes = [
"active",
"collapsed",
];