Files
mixtape/zero.Web.UI/App/core/editor-field.js
T

462 lines
12 KiB
JavaScript

import Text from '../editor/fields/text.vue';
import Currency from '../editor/fields/currency.vue';
import Number from '../editor/fields/number.vue';
import Rte from '../editor/fields/rte.vue';
import Select from '../editor/fields/select.vue';
import Textarea from '../editor/fields/textarea.vue';
import Toggle from '../editor/fields/toggle.vue';
import Alias from '../editor/fields/alias.vue';
import Output from '../editor/fields/output.vue';
import Checklist from '../editor/fields/checklist.vue';
import ColorPicker from '../editor/fields/colorpicker.vue';
import CountryPicker from '../editor/fields/countrypicker.vue';
import CulturePicker from '../editor/fields/culturepicker.vue';
import DatePicker from '../editor/fields/datepicker.vue';
import DateRangePicker from '../editor/fields/daterangepicker.vue';
import IconPicker from '../editor/fields/iconPicker.vue';
import LanguagePicker from '../editor/fields/language.vue';
import InputList from '../editor/fields/inputlist.vue';
import Media from '../editor/fields/media.vue';
import Modules from '../editor/fields/modules.vue';
import Nested from '../editor/fields/nested.vue';
import State from '../editor/fields/state.vue';
import Tags from '../editor/fields/tags.vue';
class EditorField
{
path = null;
options = {
label: null,
hideLabel: false,
description: null,
helpText: null,
condition: null,
disabled: false,
tab: null,
class: ''
};
#preview = {
icon: 'fth-filter',
preview: x => x,
hasValue: x => !!x
};
#component = null;
#componentOptions = {};
#required = false;
#isReadOnly = false;
constructor(path, options)
{
this.path = path;
this.options = { ...this.options, ...options };
}
get component()
{
return this.#component;
}
get componentOptions()
{
return this.#componentOptions;
}
get isRequired()
{
return this.#required;
}
get previewOptions()
{
return this.#preview;
}
/**
*
*/
_setComponent(component, options)
{
this.#component = component;
this.#componentOptions = options || {};
return this;
}
/**
* Set this field as required
* @param {function|boolean} [condition] - Optionally only require this field when a condition is fulfilled or reset the required state with true/false
*/
required(condition)
{
if (typeof condition === 'function')
{
this.#required = condition;
}
else if (typeof condition === 'boolean')
{
this.#required = condition;
}
else
{
this.#required = true;
}
return this;
}
/**
* Conditionally render this field (this is an alternative method to the field options 'condition')
* @param {function} condition - function which returns a boolean and gets passed the current model
*/
when(condition)
{
this.options.condition = condition;
return this;
}
/**
* Render a custom component
* @param {object} component - The custom vue component
* @param {object} [options] - Custom options
* @returns {EditorField}
*/
custom(component, options)
{
return this._setComponent(component, { ...options });
}
/**
* Render a text input field
* @param {number} [maxLength] - Maximum length of the input
* @param {string} [placeholder] - Placeholder text (can be a translation)
* @returns {EditorField}
*/
text(maxLength, placeholder)
{
return this._setComponent(Text, { maxLength, placeholder });
}
/**
* Render a currency input field
* @param {string} [placeholder] - Placeholder text (can be a translation)
* @returns {EditorField}
*/
currency(placeholder)
{
return this._setComponent(Currency, { placeholder });
}
/**
* Render a number input field
* @param {number} [maxLength] - Maximum length of the input
* @param {string} [placeholder] - Placeholder text (can be a translation)
* @returns {EditorField}
*/
number(maxLength, placeholder)
{
return this._setComponent(Number, { maxLength, placeholder });
}
/**
* Render a rich-text editor field
* @returns {EditorField}
*/
rte()
{
return this._setComponent(Rte);
}
/**
* @typedef {object} EditorSelectItem
* @param {object} key - Key/Id of the item
* @param {string} value - Label/Value of the item (can be a translation)
*/
/**
* Render a select dropdown with the specified items
* @param {EditorSelectItem[]} items - Set items to pick from
* @returns {EditorField}
*/
select(items)
{
return this._setComponent(Select, { items });
}
/**
* Render a text area
* @param {number} [maxLength] - Maximum length of the input
* @returns {EditorField}
*/
textarea(maxLength)
{
return this._setComponent(Textarea, { maxLength });
}
/**
* Render a toggle
* @param {boolean} [negative] - Toggle with a negative color / red background
* @returns {EditorField}
*/
toggle(negative)
{
return this._setComponent(Toggle, { negative });
}
/**
* Renders the field value
* @param {function} [render] - Render the output based on the given function
* @returns {EditorField}
*/
output(render)
{
this.#isReadOnly = true;
return this._setComponent(Output, { render });
}
/**
* Renders an input which generates an alias for a given name or an alternative custom alias
* @param {string} [namePath] - Optional path to the name value which is used to auto-generate the alias
* @returns {EditorField}
*/
alias(namePath)
{
return this._setComponent(Alias, { namePath });
}
/**
* Renders an input which generates an alias for a given name or an alternative custom alias
* @param {EditorSelectItem[]|function} items - Set items to choose from, either via an array or a promise which returns such array
* @param {object} [options] - Custom options
* @param {number} [options.limit=100] - Maximum items to be checked
* @param {boolean} [options.reverse=false] - Reverse the checklist behaviour, so all items are checked by default and unchecking them adds them to the result list
* @param {string} [options.labelKey=value] - Object key to get the label
* @param {string} [options.idKey=key] - Object key to get the id
* @returns {EditorField}
*/
checkList(items, options)
{
return this._setComponent(Checklist, { items, ...options });
}
/**
* Renders a HEX color picker
* @returns {EditorField}
*/
colorPicker()
{
return this._setComponent(ColorPicker);
}
/**
* Renders a country picker
* @param {number} [limit=1] - Maximum items to be selected
* @returns {EditorField}
*/
countryPicker(limit)
{
return this._setComponent(CountryPicker, { limit });
}
/**
* Renders a culture picker
* @returns {EditorField}
*/
culturePicker()
{
return this._setComponent(CulturePicker);
}
/**
* Renders a date picker
* @param {object} [options] - Custom options
* @param {string} [options.format] - Format the date output
* @param {boolean} [options.time=false] - Allow time input
* @param {string|Date} [options.maxDate] - Maximum selectable date
* @param {string|Date} [options.minDate] - Minimum selectable date
* @param {string} [options.amPm] - Render time as AM/PM
* @returns {EditorField}
*/
datePicker(options)
{
return this._setComponent(DatePicker, { ...options });
}
/**
* Renders a date range picker
* @param {object} [options] - Custom options
* @param {string} [options.format] - Format the date output
* @param {boolean} [options.time=false] - Allow time input
* @param {string|Date} [options.maxDate] - Maximum selectable date
* @param {string|Date} [options.minDate] - Minimum selectable date
* @param {string} [options.fromLabel] - Label next to the "from" date input
* @param {string} [options.toLabel] - Label next to the "to" date input
* @param {string} [options.amPm] - Render time as AM/PM
* @param {string} [options.inline] - Don't render the range picker on an overlay
* @returns {EditorField}
*/
dateRangePicker(options)
{
return this._setComponent(DateRangePicker, { ...options });
}
/**
* Pick an icon from the specified icon collection
* @param {string[]} [icons] - Custom icon set with icon class names
* @returns {EditorField}
*/
iconPicker(icons)
{
return this._setComponent(IconPicker, { icons });
}
/**
* Create a list of strings
* @param {number} [limit=10] - Limit the inputs
* @param {number} [maxItemLength=200] - Maximum length for an item input
* @param {string} [addLabel] - Label for the add button
* @returns {EditorField}
*/
inputList(limit, maxItemLength, addLabel)
{
return this._setComponent(InputList, { limit, maxItemLength, addLabel });
}
/**
* Append tags to an entity
* @param {number} [limit=10] - Limit the tags
* @param {number} [maxItemLength=200] - Maximum length for a tag
* @returns {EditorField}
*/
tags(limit, maxItemLength)
{
return this._setComponent(Tags, { limit, maxItemLength });
}
/**
* Pick a language
* @returns {EditorField}
*/
languagePicker()
{
return this._setComponent(LanguagePicker);
}
/**
* Display a module renderer which allows you to select from defined modules
* @param {string[]} [tags] - Only allow selection of modules which match defined tags
* @returns {EditorField}
*/
modules(tags)
{
return this._setComponent(Modules, { tags });
}
/**
* Display a module renderer which allows you to select from defined modules
* @param {Editor} [editor] - Use the specified editor for each item
* @param {object} [options] - Custom options
* @param {number} [options.limit=100] - Limit the creation of items
* @param {string} [options.title] - Headline in the editor overlay
* @param {string} [options.addLabel] - Label for the add button
* @param {function} [options.itemLabel] - Function which generates the label for the current item
* @param {function} [options.itemDescription] - Function which generates the description for the current item
* @param {string|function} [options.itemIcon] - Static icon or function which generates the icon for the current item
* @param {object} [options.template] - Template which is used when adding an item
* @returns {EditorField}
*/
nested(editor, options)
{
return this._setComponent(Nested, { editor, ...options });
}
/**
* Render a select as a button group
* @param {EditorSelectItem[]} items - Set items to choose from
* @returns {EditorField}
*/
state(items)
{
return this._setComponent(State, { items });
}
/**
* Render a media upload + picker
* @param {object} [options] - Custom options
* @param {number} [options.limit=1] - Limit the media select count
* @param {boolean} [options.disallowSelect=false] - Disallow the selection (only upload) of media items
* @param {boolean} [options.disallowUpload=false] - Disallow upload (only selection) of media items
* @param {string[]} [options.fileExtensions] - Allow upload + selection only for the specified file extensions
* @param {number} [options.maxFileSize=10] - Maximum allowed file size for uploads in Mibibytes
* @returns {EditorField}
*/
media(options)
{
return this._setComponent(Media, { ...options });
}
/**
* Render a media upload + picker
* @param {object} [options] - Custom options
* @param {number} [options.limit=1] - Limit the media select count
* @param {boolean} [options.disallowSelect=false] - Disallow the selection (only upload) of media items
* @param {boolean} [options.disallowUpload=false] - Disallow upload (only selection) of media items
* @param {string[]} [options.fileExtensions] - Allow upload + selection only for the specified file extensions
* @param {number} [options.maxFileSize=10] - Maximum allowed file size for uploads in Mibibytes
* @returns {EditorField}
*/
image(options)
{
return this._setComponent(Media, { ...options, fileExtensions: ['.jpg', '.jpeg', '.png', '.webp', '.svg'] });
}
/**
* Create a preview for this field
* This is only used in list filters, ...
* @param {object} options - Custom options
* @param {number} options.icon - Custom icon
* @param {number} options.preview - Render the preview when this filter has been filled out
* @param {number} options.hasValue - Determine if the filter has a value or not
* @returns {EditorField}
*/
preview(options)
{
this.#preview = { ...this.preview, ...options };
return this;
}
}
export default EditorField;