import { LightningElement, api } from "lwc"; import { InternalTreeNode } from "typings/custom"; import { track } from "dxUtils/analytics"; import { isInViewport } from "dxUtils/browser"; const DEFAULT_TARGET = "_self"; export default class TreeItem extends LightningElement { @api selectedKey?: string; @api isRoot: boolean = false; @api public get treeNode() { return this._treeNode; } public set treeNode(node) { this._treeNode = node; this.isExpanded = (node && node.isExpanded) || false; this.isChildrenLoading = (node && node.isChildrenLoading) || false; } private _treeNode!: InternalTreeNode; private isExpanded: boolean = false; private isChildrenLoading: boolean = false; private rootParentLabel: string = ""; private get isExternalLink(): boolean { return this._treeNode?.link?.target === "_blank"; } private get isSelected(): boolean { return this._treeNode.key === this.selectedKey && !this.isExternalLink; } private get hasChildren(): boolean { return !!( this.treeNode && this.treeNode.children && this.treeNode.children.length > 0 ); } private get showChildrenLoading(): boolean { return this.isExpanded && !this.hasChildren && this.isChildrenLoading; } private get isParent(): boolean { return this.hasChildren || this.isChildrenLoading; } private get showChildren(): boolean { return this.isExpanded && this.hasChildren; } private get treeLabels(): string { let parentEl = ( this.template.querySelector("dx-tree-tile")?.getRootNode() as any ).host; if (!parentEl) { return ""; } const parentLabels = []; while (parentEl) { parentEl = parentEl?.getRootNode()?.host; if (parentEl && parentEl.treeNode) { parentLabels.push(parentEl.treeNode.label); } } if (parentEl?.isRoot) { this.rootParentLabel = parentEl.treeNode.label; } return `${parentLabels.reverse().join(":")}:${this.treeNode.label}`; } private get href(): string | undefined { return ( (this._treeNode.link && this._treeNode.link.href) || this._treeNode.name || "" ); } private get target(): string { return ( (this._treeNode.link && this._treeNode.link.target) || DEFAULT_TARGET ); } connectedCallback(): void { if (this.isParent) { this.fireEvent("register", { setExpanded: this.setExpanded.bind(this) }); } } renderedCallback(): void { this.sendEventToParentIfSelected(); } private sendEventToParentIfSelected(): void { /** * This is to send selected element reference to parent if it's not visible in the viewport * Parent component will use the elements offsetTop scrollTo that element's position */ if (this.isSelected) { const element = this.template.querySelector("dx-tree-tile"); if (element && !isInViewport(element)) { this.fireEvent("selecteditemrendered", { element }); } } } private onIconClick(event: CustomEvent): void { const isSelectAction = false; this.doExpand(isSelectAction); this.sendGtm(event); } private preventDefaultLinkBehavior(event: Event) { // prevent page refresh if href isn't present or link is already active if ( !this._treeNode.link?.href || this._treeNode.link?.href === window.location.pathname ) { event.preventDefault(); } } private onLinkClick(event: Event): void { this.preventDefaultLinkBehavior(event); if (this.isParent) { const isSelectAction = true; this.doExpand(isSelectAction); } this.sendGtm(event); this.fireEvent("tileselected", { name: this._treeNode.name, isExternalLink: this.isExternalLink }); } private doExpand(isSelectAction: boolean): void { this.isExpanded = !this.isExpanded; this.fireEvent("expandcollapse", { name: this._treeNode.name, isSelectAction, isExpanded: this.isExpanded }); } private fireEvent(type: string, detail = {}): void { this.dispatchEvent( new CustomEvent(type, { detail: { ...detail, key: this._treeNode.key }, bubbles: true, composed: true }) ); } private setExpanded(value: boolean): void { this.isExpanded = value; } private sendGtm(event: Event) { track(event.currentTarget!, "custEv_leftNavLinkClick", { click_text: this._treeNode.label, click_url: this.href!.includes("/docs/") ? `${window.location.origin}${this.href}` : // TODO: this is a hack to get the correct url for the left nav window.location.href.replace(/[^/]+$/, this.href!), nav_level: this._treeNode.level + 1, nav_item: this.treeLabels, nav_type: "left nav bar", element_type: "link" }); track(event.currentTarget!, "custEv_linkClick", { click_text: this._treeNode.label, element_title: this.rootParentLabel, click_url: this.href!.includes("/docs/") ? `${window.location.origin}${this.href}` : // TODO: this is a hack to get the correct url for the left nav window.location.href.replace(/[^/]+$/, this.href!), element_type: "link", content_category: "cta" }); } }