import { LightningElement, api, track } from "lwc"; import cx from "classnames"; import { ContentElement } from "typings/custom"; import { toJson } from "dxUtils/normalizers"; import { track as sendGtm } from "dxUtils/analytics"; import { handleScroll } from "dxUtils/handleScroll"; export default class Toc extends LightningElement { // For showing shadow at the top private showBoxShadow: boolean = false; private scrolling: boolean = false; handleScroll = handleScroll.bind(this); // For showing shadow at the bottom private showBottomShadow: boolean = false; private scrollingToTop: boolean = false; @api header!: string; @api get value() { return this._value!; } set value(value: string) { this._value = value; } @api get options() { const actualValue = this.value || (this._options && this._options.length > 0 && this._options[0].id); return this._options.map((option) => { const level = option.level ?? 2; return { ...option, className: cx( "content-button", `toc-level-${level}`, option.id === actualValue && "selected" ) }; }); } set options(value: any) { this._options = toJson(value); } private _value?: string = undefined; @track _options!: Array; // to show shadow box at bottom of list container private showShadowAtBottom = (event: any) => { const list = event.target; if (!this.scrollingToTop) { this.scrollingToTop = true; // Set a timeout to handle scroll event after a delay setTimeout(() => { const isScrollable = list.scrollHeight > list.clientHeight; const isAtBottom = list.scrollTop + list.clientHeight >= list.scrollHeight - parseInt( getComputedStyle( this.template.host ).getPropertyValue("--dx-c-toc-padding-bottom"), 10 ); this.showBottomShadow = isScrollable && !isAtBottom; // Reset scrolling back to false after handling the scroll this.scrollingToTop = false; }, 200); } }; renderedCallback(): void { const list = this.template.querySelector(".toc-items"); list?.addEventListener("scroll", this.showShadowAtBottom); } disconnectedCallback(): void { const list = this.template.querySelector(".toc-items"); list?.removeEventListener("scroll", this.showShadowAtBottom); } private onClick(e: Event) { const target = e.currentTarget as HTMLElement; const id = target.getAttribute("contentid"); const text = target.getAttribute("data-text"); const href = target.getAttribute("href"); this.dispatchEvent( new CustomEvent("selectedcontent", { detail: { name: id }, bubbles: true, composed: true }) ); this._value = id!; sendGtm(e.currentTarget!, "custEv_tableOfContents", { click_text: text, clickAction: "click", click_url: `${window.location.href}${href}`, element_title: this.header, element_type: "link", content_category: "cta" }); } }