import type { BxIcon } from "@utils/bx-icon"; import { setNearby } from "./navigation-utils"; import type { NavigationNearbyElements } from "@/modules/ui/dialog/navigation-dialog"; import type { PresetRecord, AllPresets } from "@/types/presets"; import { t } from "./translation"; export enum ButtonStyle { PRIMARY = 1, WARNING = 1 << 1, DANGER = 1 << 2, GHOST = 1 << 3, FROSTED = 1 << 4, DROP_SHADOW = 1 << 5, FOCUSABLE = 1 << 6, FULL_WIDTH = 1 << 7, FULL_HEIGHT = 1 << 8, TALL = 1 << 9, CIRCULAR = 1 << 10, NORMAL_CASE = 1 << 11, NORMAL_LINK = 1 << 12, } const ButtonStyleClass = { [ButtonStyle.PRIMARY]: 'bx-primary', [ButtonStyle.WARNING]: 'bx-warning', [ButtonStyle.DANGER]: 'bx-danger', [ButtonStyle.GHOST]: 'bx-ghost', [ButtonStyle.FROSTED]: 'bx-frosted', [ButtonStyle.DROP_SHADOW]: 'bx-drop-shadow', [ButtonStyle.FOCUSABLE]: 'bx-focusable', [ButtonStyle.FULL_WIDTH]: 'bx-full-width', [ButtonStyle.FULL_HEIGHT]: 'bx-full-height', [ButtonStyle.TALL]: 'bx-tall', [ButtonStyle.CIRCULAR]: 'bx-circular', [ButtonStyle.NORMAL_CASE]: 'bx-normal-case', [ButtonStyle.NORMAL_LINK]: 'bx-normal-link', } export type BxButtonOptions = Partial<{ style: ButtonStyle; url: string; classes: string[]; icon: typeof BxIcon; label: string; secondaryText: HTMLElement | string; title: string; disabled: boolean; onClick: EventListener; tabIndex: number; attributes: {[key: string]: any}, }>; export type SettingsRowOptions = Partial<{ multiLines: boolean; $note: HTMLElement; }>; // Quickly create a tree of elements without having to use innerHTML type CreateElementOptions = { [index: string]: any; _on?: { [ key: string ]: (e: Event) => void; }; _dataset?: { [ key: string ]: string | number; }; _nearby?: NavigationNearbyElements; }; function createElement(elmName: string, props: CreateElementOptions={}, ..._: any): T { let $elm; const hasNs = 'xmlns' in props; // console.trace('createElement', elmName, props); if (hasNs) { $elm = document.createElementNS(props.xmlns, elmName); delete props.xmlns; } else { $elm = document.createElement(elmName); } if (props._nearby) { setNearby($elm, props._nearby); delete props._nearby; } if (props._on) { for (const name in props._on) { $elm.addEventListener(name, props._on[name]); } delete props._on; } if (props._dataset) { for (const name in props._dataset) { $elm.dataset[name] = props._dataset[name] as string; } delete props._dataset; } for (const key in props) { if ($elm.hasOwnProperty(key)) { continue; } const value = props[key]; if (hasNs) { $elm.setAttributeNS(null, key, value); } else { $elm.setAttribute(key, value); } } for (let i = 2, size = arguments.length; i < size; i++) { const arg = arguments[i]; if (arg !== null && arg !== false && typeof arg !== 'undefined') { $elm.append(arg); } } return $elm as T; } const domParser = new DOMParser(); export function createSvgIcon(icon: typeof BxIcon) { return domParser.parseFromString(icon.toString(), 'image/svg+xml').documentElement; } const ButtonStyleIndices = Object.keys(ButtonStyleClass).map(i => parseInt(i)); export function createButton(options: BxButtonOptions): T { let $btn; // Create base button element if (options.url) { $btn = CE('a', { class: 'bx-button', href: options.url, target: '_blank', }); } else { $btn = CE('button', { class: 'bx-button', type: 'button', }); options.disabled && ($btn.disabled = true); } // Add button styles const style = (options.style || 0) as number; if (style) { let index: keyof typeof ButtonStyleClass; for (index of ButtonStyleIndices) { (style & index) && $btn.classList.add(ButtonStyleClass[index] as string); } } options.classes && $btn.classList.add(...options.classes); options.icon && $btn.appendChild(createSvgIcon(options.icon)); options.label && $btn.appendChild(CE('span', {}, options.label)); options.title && $btn.setAttribute('title', options.title); options.onClick && $btn.addEventListener('click', options.onClick); $btn.tabIndex = typeof options.tabIndex === 'number' ? options.tabIndex : 0; if (options.secondaryText) { $btn.classList.add('bx-button-multi-lines'); $btn.appendChild(CE('span', {}, options.secondaryText)); } for (const key in options.attributes) { if (!$btn.hasOwnProperty(key)) { $btn.setAttribute(key, options.attributes[key]); } } return $btn as T; } export function createSettingRow(label: string, $control: HTMLElement | false | undefined, options: SettingsRowOptions={}) { let $label: HTMLElement; const $row = CE('label', { class: 'bx-settings-row' }, $label = CE('span', {class: 'bx-settings-label'}, label, options.$note, ), $control, ); // Make link inside