import type { RecursivePartial, TomSettings } from "tom-select/src/types"; import { AutoCompleteSelectBase } from "#core:core/components/ajax-select-base"; import { registerComponent } from "#core:utils/web-components"; const productParsingRegex = /^(\d+x)?(.*)/i; const codeParsingRegex = / \((\w+)\)$/; function parseProduct(query: string): [number, string] { const parsed = productParsingRegex.exec(query); return [Number.parseInt(parsed[1] || "1", 10), parsed[2]]; } @registerComponent("counter-product-select") export class CounterProductSelect extends AutoCompleteSelectBase { public getOperationCodes(): string[] { return ["FIN", "ANN"]; } public getSelectedProduct(): [number, string] { return parseProduct(this.widget.getValue() as string); } protected attachBehaviors(): void { this.allowMultipleProducts(); this.parseCodes(); } private parseCodes(): void { // We guess the code from the product name so we can prioritize search on it // If no code is found, we just ignore it and everything still is fine for (const option of Object.values(this.widget.options)) { const match = codeParsingRegex.exec(option.text); if (match !== null) { option.code = match[1]; } } } private allowMultipleProducts(): void { const search = this.widget.search; const onOptionSelect = this.widget.onOptionSelect; this.widget.hook("instead", "search", (query: string) => { return search.call(this.widget, parseProduct(query)[1]); }); this.widget.hook( "instead", "onOptionSelect", (evt: MouseEvent | KeyboardEvent, option: HTMLElement) => { const [quantity, _] = parseProduct(this.widget.inputValue()); const originalValue = option.getAttribute("data-value") ?? option.innerText; if (quantity === 1 || this.getOperationCodes().includes(originalValue)) { return onOptionSelect.call(this.widget, evt, option); } const value = `${quantity}x${originalValue}`; const label = `${quantity}x${option.innerText}`; this.widget.addOption({ value: value, text: label }, true); return onOptionSelect.call( this.widget, evt, this.widget.getOption(value, true), ); }, ); } protected tomSelectSettings(): RecursivePartial { /* We disable the dropdown on focus because we're going to always autofocus the widget */ return { ...super.tomSelectSettings(), openOnFocus: false, // We make searching on exact code matching a higher priority // We need to manually set weights or it results on an inconsistent // behavior between production and development environment searchField: [ { field: "code", weight: 2 }, { field: "text", weight: 0.5 }, ], }; } }