/** * Copyright (c) 2023 MERCENARIES.AI PTE. LTD. * All rights reserved. */ // See https://rete.readthedocs.io/en/latest/Controls/ import Tagify from '@yaireo/tagify'; const controls = import.meta.glob('./*.hbs', { as: 'raw', eager: true }); function controlsShared(initialValue, control, inputTemplate, formatter) { return { value: initialValue, previousValue: initialValue, key: '', title: '', opts: { readonly: false, placeholder: initialValue, default: initialValue, choices: ['(default)'] }, control: null, error: null, controlUid: '', required: false, tooltip: '', change(e) { let newValue = e.target.value; if (typeof this.value === 'number') { newValue = +e.target.value; console.log('changeNumber', Date.now(), e, newValue); } if (formatter && this.value != null) { try { newValue = formatter(newValue); } catch (ex) { this.error = 'Error: ' + ex.message; console.warn('Formatter failed to parse value', newValue, this.value); return; } } this.error = null; this.value = newValue; }, updateConstraints() { if (this.value === '(Default)') { this.value = this.opts.default ?? initialValue; } if (typeof initialValue === 'number') { if (this.opts.minimum !== undefined) { if (this.value < this.opts.minimum) { this.value = this.opts.minimum; } } if (this.opts.maximum !== undefined) { if (this.value > this.opts.maximum) { this.value = this.opts.maximum; } } } if (typeof initialValue === 'string') { this.value = typeof this.value === 'string' ? this.value.trim() : ''; } }, update() { this.updateConstraints(); if (this.key) { this.control.putData(this.key, this.value); if (this.previousValue !== this.value) { this.previousValue = this.value; this.emitter.trigger('nodeupdated', this); } } }, async getInputTemplate() { // Compile the template const source = controls[inputTemplate]; if (source === undefined) { return inputTemplate; // throw new Error(`Template ${inputTemplate} not found`) } else { return source; } }, hasValue() { // Caution `this.value` can be 0, 0.0, `0` etc, all of which are "falsey" but valid values. return this.value !== null && this.value !== undefined && this.value !== '' && this.value?.length !== 0; }, custom(key) { return this.control.custom(key); }, init() { this.control = control; this.required = this.control.required; this.key = this.control.key; this.title = this.control.title; this.description = this.control.description ?? this.control.summary; this.tooltip = this.title !== this.description ? (this.title ?? '') + ': ' + (this.description ?? '') : this.title ?? ''; // See also: https://alpinejs.dev/directives/id this.controlUid = this.key + Date.now(); // Must be second-last thing in init() this.opts = this.control.opts; this.opts.readonly = this.control.opts.readonly || !client.workbench.canEdit; this.value = this.control.getData(this.key) ?? this.control.opts.default ?? initialValue; this.previousValue = this.value; this.emitter = this.control.emitter; this.error = null; this._customInit?.(); this.update(); // Must be last thing in init() } }; } const AlpineNumComponent = (control) => { return { ...controlsShared( control.opts.default === 'inf' ? Infinity : control.opts.default, control, './NumControl.hbs', parseFloat ) }; }; const AlpineTextComponent = (control) => { return { ...controlsShared(control.opts.default || '', control, './TextControl.hbs') }; }; const AlpineButtonComponent = (control) => { return { ...controlsShared(control.opts.default || '', control, './ButtonControl.hbs'), runButtonAction(value, args) { if (this.custom('buttonAction') === 'script') { window.client.runScript(value, args); } else { alert('Button action ' + this.custom('buttonAction') + 'not implemented'); } } }; }; const AlpineColorComponent = (control) => { return { ...controlsShared('', control, './ColorControl.hbs') }; }; const AlpineSelectComponent = (control) => { return { _customInit() { this.choices ??= []; }, ...controlsShared('', control, './SelectControl.hbs'), selectedChoice() { return this.choices ? this.choices.find?.((e) => e.toString() === this.value.toString()) : { value: this.default, title: '(default)', description: null }; } }; }; const AlpineSelect2TagComponent = (control) => { return { ...controlsShared([], control, './Select2TagControl.hbs'), ...{ tagify(element) { element.value = this.value; // eslint-disable-next-line no-unused-vars void new Tagify(element, { // enforceWhitelist: true, // whitelist: this.opts.choices.map((e) => e.value), callbacks: { add: (e) => { this.updateTag(e); }, remove: (e) => { this.updateTag(e); } } }); }, updateTag(e) { const tags = e.detail.tagify.value.map((e) => {return e.value[0] === '#' ? e.value : '#' + e.value;}); this.value = tags; console.log('updateTag', tags, this.value); } } }; }; const AlpineBoolComponent = (control) => { return controlsShared(false, control, './BoolControl.hbs', (v) => !!v); }; const AlpineToggleComponent = (control) => { // Unlike other input types, with ``, the state is stored in `this.checked` // this.value == "on"; // Always // (this.checked == true) || (this.checked == false); // State of checkbox return { ...controlsShared(false, control, './ToggleControl.hbs'), ...{ change(e) { this.value = e.target.checked; // Different from `e.target.value` ! See above... } } }; }; const AlpineNumWithSliderComponent = (control) => { return { ...controlsShared(0, control, './NumWithSliderControl.hbs', parseFloat) }; }; const AlpineLabelComponent = (control) => { return controlsShared('', control, './LabelControl.hbs'); }; const AlpineCodeMirrorComponent = (control) => { return { ...controlsShared(null, control, './CodeMirrorControl.hbs', (o) => { if (o != null) { let result; if (typeof o === 'string') { result = JSON.parse(o); } else if (typeof o === 'object') { result = window.Alpine.raw(o); } else { result = null; } return result; } }) }; }; const AlpineDynamicInputComponent = (control) => { return { ...{ doChange(e) { const self = this; const nodeId = self.control.parent.id; this.change(e); window.Alpine.nextTick(() => { self.emitter.trigger('node_dynamic_update', { nodeId, key: self.key, value: self.value }); }); } }, ...controlsShared(null, control, './DynamicInputControl.hbs', (o) => { if (o != null) { let result; if (typeof o === 'string') { result = JSON.parse(o); } else if (typeof o === 'object') { result = window.Alpine.raw(o); } else { result = null; } return result; } }) }; }; const AlpineImageGalleryComponent = (control) => { return { ...controlsShared([], control, './ImageGalleryControl.hbs'), ...{ hasValidImage() {}, update() { if (this.key) { this.value = this.control.getData(this.key); } } } }; }; export { AlpineBoolComponent, AlpineButtonComponent, AlpineCodeMirrorComponent, AlpineColorComponent, AlpineDynamicInputComponent, AlpineImageGalleryComponent, AlpineLabelComponent, AlpineNumComponent, AlpineNumWithSliderComponent, AlpineSelect2TagComponent, AlpineSelectComponent, AlpineTextComponent, AlpineToggleComponent };