import { generateID } from './helpers' export class Option { id: string value: string text: string html: string defaultSelected: boolean selected: boolean display: boolean disabled: boolean placeholder: boolean class: string style: string data: { [key: string]: string } mandatory: boolean constructor(option: Partial) { this.id = !optgroup.id || optgroup.id === '' ? generateID() : optgroup.id this.label = optgroup.label || '' this.selectAll = optgroup.selectAll === undefined ? false : optgroup.selectAll this.selectAllText = optgroup.selectAllText || 'Select All' this.closable = optgroup.closable || 'off' // If options exist, loop through options and create new option class // and set the options to the optgroup options field this.options = [] if (optgroup.options) { for (const o of optgroup.options) { this.options.push(new Option(o)) } } } } export default class Store { private selectType: 'single' | 'multiple' = 'single' // Main data set, never null private data: (Option | Optgroup)[] = [] private selectedOrder: string[] = [] constructor(type: 'single' | 'multiple', data: (Partial)[]) { this.selectType = type this.setData(data) } // Validate DataArrayPartial public validateDataArray(data: (Partial)[]): Error | null { if (!Array.isArray(data)) { return new Error('Data must be an array') } // Loop through each data object for (let dataObj of data) { if (!dataObj) continue // Optgroup if (dataObj instanceof Optgroup || 'label' in dataObj) { if (!('label' in dataObj)) { return new Error('Optgroup must have a label') } if ('options' in dataObj && dataObj.options) { for (let option of dataObj.options) { const validationError = this.validateOption(option) if (validationError) { return validationError } } } } else if (dataObj instanceof Option || 'text' in dataObj) { const validationError = this.validateOption(dataObj) if (validationError) { return validationError } } else { return new Error('Data object must be a valid optgroup or option') } } return null } // Validate Option public validateOption(option: Partial)[]): (Option | Optgroup)[] { let dataFinal: (Option | Optgroup)[] = [] data.forEach((dataObj) => { if (!dataObj) return // Optgroup if (dataObj instanceof Optgroup || 'label' in dataObj) { let optOptions: Option[] = [] if ('options' in dataObj && dataObj.options) { dataObj.options.forEach((option: Partial)) } } // Option if (dataObj instanceof Option || 'text' in dataObj) { dataFinal.push(new Option(dataObj as Partial)[], preserveSelected: boolean = false) { // Convert new data to full data array const newData = this.partialToFullData(data) let selectedOptionsBeforeUpdate: Option[] = [] if (preserveSelected) { // Get currently selected options before updating data selectedOptionsBeforeUpdate = this.getSelectedOptions() // Check which selected options are missing from new data const missingSelected: (Option | Optgroup)[] = [] selectedOptionsBeforeUpdate.forEach((selectedOption) => { let found = false // Check if this selected option exists in new data for (const newItem of newData) { if (newItem instanceof Option && newItem.id === selectedOption.id) { found = true break } if (newItem instanceof Optgroup) { for (const opt of newItem.options) { if (opt.id === selectedOption.id) { found = true break } } } } if (!found) { missingSelected.push(selectedOption) } }) // Add missing selected options to the beginning of the data this.data = [...missingSelected, ...newData] } else { this.data = newData } // Run this.data through setSelected by value // to set the selected property and clean any wrong selected if (this.selectType === 'single') { // When search returns new data and user had nothing selected, don't auto-select first option const allowEmptySelection = preserveSelected && selectedOptionsBeforeUpdate.length === 0 this.setSelectedBy('id', this.getSelected(), allowEmptySelection) } } // Get data will return all the data public getData(): Option[] | Optgroup[] { return this.filter(null, true) as Option[] | Optgroup[] } // Get data options will return the data as a // flat array of just options public getDataOptions(): Option[] { return this.filter(null, false) as Option[] } public addOption(option: Partial