UNPKG

@stimulus-library/controllers

Version:

A library of useful controllers for Stimulus

92 lines (91 loc) 2.76 kB
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", ];