File: src/components/Tree/Leaf.ts

Recommend this page to a friend!
  Classes of Dom Hastings   JS Webdav Client   src/components/Tree/Leaf.ts   Download  
File: src/components/Tree/Leaf.ts
Role: Class source
Content type: text/plain
Description: Class source
Class: JS Webdav Client
Access files of a Webdav server
Author: By
Last change:
Date: 1 year ago
Size: 3,478 bytes
 

Contents

Class file image Download
import Element, { empty, on, s, t } from '@dom111/element'; import DataProvider from './DataProvider'; import Node from './Node'; const template = (node: Node): string => ` <div class="leaf" tabindex="0" aria-selected="false" aria-expanded="false" > <span class="toggle"></span> <span class="name"></span> <section class="children"></section> </div> `; export type LeafEvents = { 'leaf-collapsed': [Leaf]; 'leaf-deselected': [Leaf]; 'leaf-expanded': [Leaf]; 'leaf-selected': [Leaf]; }; export class Leaf extends Element<HTMLDivElement, LeafEvents> { #dataProvider: DataProvider; #node: Node; constructor(node: Node, dataProvider: DataProvider) { super(s(template(node))); this.query('.name').append(t(node.name())); this.#dataProvider = dataProvider; this.#node = node; this.bindEvents(); this.update(); } private bindEvents(): void { const getChildren = async (node: Node) => { if (node.hasChildren() === null) { await this.#dataProvider.getChildren(this.#node); } if (node.hasChildren()) { this.#node .children() .forEach((childNode) => this.#dataProvider.getChildren(childNode)); } }, expand = () => { this.emit( new CustomEvent<[Leaf]>( this.expanded() ? 'leaf-collapsed' : 'leaf-expanded', { bubbles: true, detail: [this], } ) ); this.element().setAttribute( 'aria-expanded', this.expanded() ? 'false' : 'true' ); getChildren(this.#node); }, select = () => { this.emit( new CustomEvent<[Leaf]>( this.selected() ? 'leaf-deselected' : 'leaf-selected', { bubbles: true, detail: [this], } ) ); this.element().setAttribute( 'aria-selected', this.selected() ? 'false' : 'true' ); getChildren(this.#node); }; on(this.toggle(), 'click', (event) => { event.preventDefault(); event.stopPropagation(); expand(); }); this.on('click', (event) => { if (event.button) { return; } event.preventDefault(); event.stopPropagation(); select(); if ( this.#node.hasChildren() && this.element().matches('[aria-expanded="false"]') ) { expand(); } }); this.#node.on('updated', () => this.update()); } private children(): HTMLDivElement { return this.query<HTMLDivElement>('.children'); } private expanded(): boolean { return this.element().getAttribute('aria-expanded') === 'true'; } node(): Node { return this.#node; } private selected(): boolean { return this.element().getAttribute('aria-selected') === 'true'; } private toggle(): HTMLSpanElement { return this.query<HTMLSpanElement>('.toggle'); } private update(): void { if (this.#node.hasChildren() === null) { return; } if (this.#node.hasChildren()) { this.addClass('hasChildren'); empty(this.children()); this.#node.children().forEach((child) => { const leaf = new Leaf(child, this.#dataProvider); this.children().append(leaf.element()); }); return; } this.addClass('hasNoChildren'); } } export default Leaf;