import type { Validation } from '@vuelidate/core'; import type { VNode } from 'vue'; import type { DropdownButtonItemArgs } from '../dropdown-button/dropdown-button-item'; import type { FormItemWrapperArgs, MarginType } from '../form/form-item-wrapper'; import { Prop, toNative, Watch } from 'vue-facing-decorator'; import PowerduckState from '../../app/powerduck-state'; import TsxComponent, { Component } from '../../app/vuetsx'; import { isNullOrEmpty } from '../../common/utils/is-null-or-empty'; import FormItemWrapper from '../form/form-item-wrapper'; import './css/bootstrap-toggle.css'; interface BootstrapToggleArgs extends Omit { value: boolean; enabled?: boolean; captionTrue?: string; captionFalse?: string; size?: BootstrapToggleSize; cssClassRoot?: string; changed: (newValue: boolean) => void; validationProperty?: Validation & any; } export enum BootstrapToggleSize { Large = 'btn-lg', Normal = '', Small = 'btn-sm', Mini = 'btn-xs', } export class BootstrapToggleConfig { static getOnStyle() { return PowerduckState.getBootstrapOnStyle(); } } @Component class BootstrapToggleComponent extends TsxComponent implements BootstrapToggleArgs { @Prop() label!: string | VNode; @Prop() labelButtons!: DropdownButtonItemArgs[]; @Prop() subtitle!: string; @Prop() value!: boolean; @Prop() wrap!: boolean; @Prop() mandatory!: boolean; @Prop() hint: string; @Prop() appendIcon: string; @Prop() prependIcon: string; @Prop() cssClass!: string; @Prop() cssClassRoot!: string; @Prop() maxWidth?: number; @Prop() appendClicked: () => void; @Prop() prependClicked: () => void; @Prop() changed: (newValue: boolean) => void; @Prop({ default: true }) enabled!: boolean; @Prop() captionTrue!: string; @Prop() captionFalse!: string; @Prop() marginType?: MarginType; @Prop() size!: BootstrapToggleSize; _sizeCache: { key: string; width: number }; _skipNoTrans: boolean; raiseChangeEvent(newValue: boolean) { this.populateValidationDeclaration(); if (this.changed != null) { this._skipNoTrans = true; this.changed(newValue); } } getBootstrapToggleElement(): HTMLElement { return this.$el.querySelector('input'); } mounted() { } @Watch('value') onValueChanged() { this.$forceUpdate(); } getCaptionTrue(): string { return this.captionTrue || PowerduckState.getResourceValue('yes'); } getCaptionFalse(): string { return this.captionFalse || PowerduckState.getResourceValue('no'); } private get errorId(): string { return `toggle-error-${this.$.uid}`; } getMinWidthCssClass(): string { if (this.getCaptionFalse().length > 5 || this.getCaptionTrue().length > 5) { return 'toggle-min-100'; } return ''; } handleValueToggle() { if (this.value == true) { this.raiseChangeEvent(false); } else { this.raiseChangeEvent(true); } } getCacheKey(): string { return `${this.getCaptionTrue()}-${this.getCaptionFalse()}`; } getSizes(): { width: number } { const key = this.getCacheKey(); if (key != this._sizeCache?.key) { this.invalidateDimensionsCache(); } return this._sizeCache; } invalidateDimensionsCache() { const newEl = document.createElement('label'); newEl.className = `btn btn-light ${this.size || ''}`.trim(); newEl.style.position = 'absolute'; newEl.style.left = '-9999px'; document.body.appendChild(newEl); newEl.textContent = this.getCaptionTrue(); let width = newEl.offsetWidth; newEl.textContent = this.getCaptionFalse(); const itemWidth = newEl.offsetWidth; newEl.remove(); if (itemWidth > width) { width = itemWidth; } this._sizeCache = { key: this.getCacheKey(), width: width + 15, }; } beforeUpdate(): void { if (!this.$el?.getAttribute) { return; } if (!this._skipNoTrans) { const prevVal = (this.$el as HTMLElement).getAttribute('data-value') == '1'; if (prevVal != this.value) { const toggleGroup: HTMLElement = (this.$el as HTMLElement).querySelector('.bs-toggle-group'); if (toggleGroup != null) { toggleGroup.classList.add('no-bs-toggle-trans'); this.$nextTick(() => { setTimeout(() => { (this.$el as HTMLElement).querySelector('.bs-toggle-group').classList.remove('no-bs-toggle-trans'); }, 150); }); } } } this._skipNoTrans = false; } render(h) { const { width } = this.getSizes(); return (
{ if (this.enabled != false) { this.handleValueToggle(); } }} onKeydown={(e: KeyboardEvent) => { if ((e.key === ' ' || e.key === 'Enter') && this.enabled !== false) { e.preventDefault(); this.handleValueToggle(); } }} >
); } } const BootstrapToggle = toNative(BootstrapToggleComponent); export default BootstrapToggle;