import { SettingsManager } from "./settings-manager"; import { Constants } from "adaptivecards-controls"; export interface IToolboxCommand { title: string; iconClass: string; execute: (sender: IToolboxCommand) => void; } export enum ToolboxOrientation { Horizontal, Vertical } export class Toolbox { private _renderedElement: HTMLElement; private _headerRootElement: HTMLElement; private _headerIconElement: HTMLElement; private _expandCollapseButtonElement: HTMLElement; private _customCommandsHost: HTMLElement; private _contentHost: HTMLElement; private _isExpanded: boolean = true; private _content: HTMLElement; private _stretch: boolean = false; private _orientation: ToolboxOrientation; private _isRestoring: boolean = false; private _collapsedTabContainer: HTMLElement; private _isVisible = true; private getDimensionSettingName(): string { return "Toolbox" + this.id + (this._orientation == ToolboxOrientation.Vertical ? "Height" : "Width"); } private updateContent() { if (this._contentHost) { this._contentHost.innerHTML = ""; if (this._content) { this._contentHost.appendChild(this._content); } } } private toggled(saveState: boolean = true) { if (this.onToggled) { this.onToggled(this, saveState); } } private updateVisibility() { if (this._collapsedTabContainer) { if (!this._isVisible) { this.hideToolbox(); } else { this._collapsedTabContainer.appendChild(this._headerRootElement); this.restoreState(); } this._expandCollapseButtonElement.setAttribute("aria-expanded", this._isExpanded.toString()); } } private hideToolbox() { if (this.isExpanded) { this.collapse(false); } this._collapsedTabContainer.removeChild(this._headerRootElement); } onToggled: (sender: Toolbox, saveState?: boolean) => void; readonly id: string; readonly title: string; commands: Array = null; constructor(id: string, title: string) { this.id = id; this.title = title; } render(orientation: ToolboxOrientation, collapsedTabContainer: HTMLElement) { this._orientation = orientation; this._collapsedTabContainer = collapsedTabContainer; this._renderedElement = document.createElement("div"); this._renderedElement.classList.add("acd-toolbox"); this.stretch = this.stretch; // trigger CSS class painting based on defaults this._headerRootElement = document.createElement("div"); this._headerRootElement.innerHTML = ""; this._headerRootElement.className = "acd-toolbox-header"; let headerContentElement = document.createElement("div"); headerContentElement.className = "acd-toolbox-header-content"; let headerTitleElement = document.createElement("span"); headerTitleElement.className = "acd-toolbox-header-title"; headerTitleElement.innerText = this.title; headerContentElement.appendChild(headerTitleElement); let headerCommandsHostElement = document.createElement("span"); headerCommandsHostElement.className = "acd-toolbox-header-commandsHost"; this._customCommandsHost = document.createElement("div"); this._customCommandsHost.style.display = "flex"; if (this.commands) { for (let command of this.commands) { let commandButtonElement = document.createElement("div"); commandButtonElement.className = "acd-toolbox-header-commandButton"; commandButtonElement.title = command.title; commandButtonElement.onclick = (e) => { command.execute(command); } let commandIconElement = document.createElement("div"); commandIconElement.classList.add("acd-icon", command.iconClass); commandButtonElement.appendChild(commandIconElement); this._customCommandsHost.appendChild(commandButtonElement); } } headerCommandsHostElement.appendChild(this._customCommandsHost); this._expandCollapseButtonElement = document.createElement("span"); this._expandCollapseButtonElement.className = "acd-toolbox-header-commandButton"; this._expandCollapseButtonElement.title = "Hide " + this.title; this._expandCollapseButtonElement.tabIndex = 0; this._expandCollapseButtonElement.setAttribute("role", "button"); this._expandCollapseButtonElement.setAttribute("aria-expanded", "true"); this._expandCollapseButtonElement.ariaLabel = this.title; this._headerIconElement = document.createElement("span") this._headerIconElement.classList.add("acd-icon", "acd-icon-header-expanded"); this._expandCollapseButtonElement.appendChild(this._headerIconElement); this._expandCollapseButtonElement.onkeydown = (e) => { if (e.key === Constants.keys.enter || e.key === Constants.keys.space) { this.toggle(); e.preventDefault(); this._expandCollapseButtonElement.focus(); // Add a delay so the focus event has completed setTimeout(() => { this._expandCollapseButtonElement.setAttribute("aria-expanded", this._isExpanded.toString()); }, 1); } if (e.key === Constants.keys.escape) { this.collapse(); e.preventDefault(); this._expandCollapseButtonElement.focus(); // Add a delay so the focus event has completed setTimeout(() => { this._expandCollapseButtonElement.setAttribute("aria-expanded", this._isExpanded.toString()); }, 1); } } this._expandCollapseButtonElement.onclick = (e) => { this.toggle(); this._expandCollapseButtonElement.setAttribute("aria-expanded", this._isExpanded.toString()); e.preventDefault(); return true; } headerCommandsHostElement.appendChild(this._expandCollapseButtonElement); headerContentElement.appendChild(headerCommandsHostElement); this._headerRootElement.appendChild(headerContentElement); this._contentHost = document.createElement("div"); this._contentHost.style.overflow = "auto"; this._renderedElement.appendChild(this._headerRootElement); this._renderedElement.appendChild(this._contentHost); if (!this._isVisible) { this.hideToolbox(); } this.updateContent(); } collapse(saveState: boolean = true) { if (this._isExpanded) { this._headerIconElement.classList.add("acd-icon-header-collapsed"); this._headerIconElement.classList.remove("acd-icon-header-expanded"); this._customCommandsHost.classList.add("acd-hidden"); if (this._collapsedTabContainer) { this._renderedElement.removeChild(this._headerRootElement); this._collapsedTabContainer.appendChild(this._headerRootElement); } this._expandCollapseButtonElement.title = "Show " + this.title; this._isExpanded = false; this.toggled(saveState); } } expand() { if (!this._isExpanded) { this._headerIconElement.classList.add("acd-icon-header-expanded"); this._headerIconElement.classList.remove("acd-icon-header-collapsed"); this._customCommandsHost.classList.remove("acd-hidden"); if (this._collapsedTabContainer) { this._collapsedTabContainer.removeChild(this._headerRootElement); this._renderedElement.insertBefore(this._headerRootElement, this._renderedElement.firstChild); } this._expandCollapseButtonElement.title = "Hide " + this.title; this._isExpanded = true; this.toggled(); } } toggle() { if (this.isExpanded) { this.collapse(); } else { this.expand(); } } getHeaderBoundingRect(): ClientRect { return this._headerRootElement.getBoundingClientRect(); } saveState() { if (!this._isRestoring) { SettingsManager.trySaveSetting("Toolbox" + this.id + "IsExpanded", this.isExpanded.toString()); SettingsManager.trySaveSetting( this.getDimensionSettingName(), this.orientation == ToolboxOrientation.Vertical ? this.renderedElement.style.height : this.renderedElement.style.width); } } restoreState() { if (this.renderedElement && !this._isRestoring && this.isVisible) { this._isRestoring = true; try { let dimensionSetting = SettingsManager.tryLoadStringSetting(this.getDimensionSettingName()); if (dimensionSetting.succeeded && dimensionSetting.value != undefined && dimensionSetting.value != "") { if (this.orientation == ToolboxOrientation.Vertical) { this.renderedElement.style.height = dimensionSetting.value; } else { this.renderedElement.style.width = dimensionSetting.value; } } let isExpandedSetting = SettingsManager.tryLoadBooleanSetting("Toolbox" + this.id + "IsExpanded", true); if (isExpandedSetting.succeeded && this.isVisible) { if (isExpandedSetting.value) { this.expand(); } else { this.collapse(); } this._expandCollapseButtonElement.setAttribute("aria-expanded", this._isExpanded.toString()); } } finally { this._isRestoring = false; } } } get orientation(): ToolboxOrientation { return this._orientation; } get renderedElement(): HTMLElement { return this._renderedElement; } get content(): HTMLElement { return this._content; } set content(value: HTMLElement) { this._content = value; this.updateContent(); } get isExpanded(): boolean { return this._isExpanded; } get stretch(): boolean { return this._stretch; } set stretch(value: boolean) { this._stretch = value; if (this._stretch) { this.renderedElement.classList.add("acd-toolbox-stretch"); this.renderedElement.classList.remove("acd-toolbox-no-stretch"); } else { this.renderedElement.classList.add("acd-toolbox-no-stretch"); this.renderedElement.classList.remove("acd-toolbox-stretch"); } } set isVisible(value: boolean) { if (this._isVisible != value) { this._isVisible = value; this.updateVisibility(); } } get isVisible() { return this._isVisible; } }