/** jsx:pragma h */
import { Component, h, render } from 'preact';
import { ItemRenderer, QueryFunction } from '../../control/src/abstract-select';
import { Dictionary } from '../../control/src/dictionary';
import { MultiSelect } from '../../control/src/multi-select';
import '../../control/src/select25.scss';
import { SingleSelect } from '../../control/src/single-select';
import { extend } from '../../control/src/util';
import { Ajax, createQueryFromAjax } from './ajax';
import { DataFunction, createQueryFromData } from './data';
import { Store } from './store';
const forceImportOfH = h;
enum StoreKeys {
targetElement = 'te'
}
export interface Options {
multiple: boolean;
containerStyle?: string;
containerClass?: string;
hiddenValue?: (values: any, options: Options) => string;
tabIndex?: number;
itemId: ((item: any) => string) | string;
itemLabel: ((item: any) => string) | string;
valueContent?: ItemRenderer;
resultContent?: ItemRenderer;
query?: QueryFunction;
data?: DataFunction;
ajax?: Ajax;
quiet?: number;
minimumCharacters?: number;
openOnFocus?: boolean;
dictionary?: string | Dictionary;
value: any;
values: any[];
allowClear?: boolean;
placeholder?: string;
/** Single Select Label */
label?: string;
/** Multi Select Selected Values Listbox Label */
valuesLabel?: string;
/** Multi Select Add Value Combobox Label */
comboboxLabel?: string;
allowDuplicates: boolean;
}
const DEFAULT_OPTIONS = {
allowClear: false,
dictionary: 'en_us',
hiddenValue: (values: any, options: Options) => {
const id = (item: any) => {
if (typeof options.itemId === 'function') {
return options.itemId(item);
} else {
return '' + item[options.itemId];
}
};
if (values) {
if (Array.isArray(values)) {
if (values.length > 0) {
return values.map(id).join(',');
} else {
return '';
}
} else {
return id(values);
}
} else {
return '';
}
},
itemId: 'id',
itemLabel: 'text',
minimumCharacters: 0,
multiple: false,
openOnFocus: false
};
function triggerOnChange(element: HTMLElement, data: any) {
const event = document.createEvent('HTMLEvents');
event.initEvent('change', false, true);
event[data] = data;
element.dispatchEvent(event);
}
class MultiSelectWrapper extends Component<
{
element: HTMLInputElement;
options: Options;
},
{ values: any }
> {
constructor(props) {
super(props);
this.state = { values: props.options.values };
}
public componentDidUpdate() {
this.setHiddenValue(this.state.values);
}
public componentDidMount() {
this.setHiddenValue(this.state.values);
}
public render(props, state, context) {
const opts = this.props.options;
return (
);
}
public onChange = (values: any[]) => {
this.setState({ values });
this.setHiddenValue(values);
triggerOnChange(this.props.element, values);
};
private setHiddenValue(values: any) {
const { element, options } = this.props;
element.value = options.hiddenValue(values, options);
}
}
class SingleSelectWrapper extends Component<
{
options: Options;
element: HTMLInputElement;
},
{ value: any }
> {
constructor(props) {
super(props);
this.state = { value: props.options.value };
}
public componentDidMount() {
this.setHiddenValue(this.state.value);
}
public componentDidUpdate() {
this.setHiddenValue(this.state.value);
}
public render(props, state, context) {
const opts = this.props.options;
return (
);
}
public onChange = (value: any) => {
this.setState({ value });
this.setHiddenValue(value);
triggerOnChange(this.props.element, value);
};
private setHiddenValue(value: any) {
const { element, options } = this.props;
element.value = options.hiddenValue(value, options);
}
}
function create(element: HTMLInputElement, options: Options) {
// TODO make sure we are attached to hidden input
const store = Store.getStore(element);
options = extend({}, DEFAULT_OPTIONS, options);
if (!options.query) {
if (options.ajax) {
options.query = createQueryFromAjax(options.ajax);
} else if (options.data) {
options.query = createQueryFromData(options.data);
}
}
if (!options.tabIndex && element.tabIndex) {
options.tabIndex = element.tabIndex;
}
if (element.getAttribute('s25-style')) {
let style = options.containerStyle || '';
if (style.length > 0) {
style += ';';
}
style += element.getAttribute('s25-style');
options.containerStyle = style;
}
if (element.getAttribute('s25-class')) {
let clazz = options.containerClass || '';
if (clazz.length > 0) {
clazz += ' ';
}
clazz += element.getAttribute('s25-class');
options.containerClass = clazz;
}
// create placeholder element into which the control will be rendered
const parentElement = element.parentElement;
const targetElement = document.createElement('div');
parentElement.insertBefore(targetElement, element);
store.set(StoreKeys.targetElement, targetElement);
// render the replacement
if (options.multiple) {
render(, parentElement, targetElement);
} else {
render(, parentElement, targetElement);
}
}
function destroy(element: HTMLElement) {
if (!Store.hasStore(element)) {
return;
}
const store = Store.getStore(element);
const targetElement = store.get(StoreKeys.targetElement);
const parentElement = element.parentElement;
render(null, parentElement, targetElement);
parentElement.removeChild(targetElement);
Store.removeStore(element);
}
const select25 = {
create,
destroy
};
export { select25 };
declare global {
interface Window {
select25: typeof select25;
}
}
window.select25 = select25;