Files
mixtape/zero.Backoffice.UI/app/schemas/list/list-column.ts
T
2022-01-04 12:58:42 +01:00

291 lines
6.8 KiB
TypeScript

import { formatDate } from '../../utils/dates';
import { localize } from '../../services/localization';
class ListColumn
{
path = null;
options = {
label: null,
hideLabel: false,
width: null,
canSort: false,
class: '',
primary: false
};
_type = null;
_func = () => { };
_funcOptions = {};
_asHtml = false;
constructor(path, options)
{
this.path = path;
this.options = { ...this.options, ...options };
}
get isHtml()
{
return this._asHtml;
}
get type()
{
return this._type;
}
get func()
{
return this._func;
}
get funcOptions()
{
return this._funcOptions;
}
/**
* Set another list column as the base for this column (copies properties)
* @param {ListColumn} column - Base list column
* @returns {ListColumn}
*/
setBase(column)
{
this.path = column.path;
this.options = { ...column.options };
this._asHtml = column.isHtml;
this._type = column.type;
this._func = column.func;
this._funcOptions = column.funcOptions;
return this;
}
/**
* Render the output by passing the value and the whole entity
* @param {any} value - The value to process
* @param {any} model - The model entity
* @returns {string}
*/
render(value, model)
{
return this._func(value, this._funcOptions, model);
}
/**
* Render a custom component
* @param {Function} renderFunc - The function which renders the output (parameter is value)
* @param {boolean} [asHtml] - Render as a plain string or as HTML
* @param {string} [type] - Pass the type name which will be added in the HTML as [field-type="type"]
* @returns {ListColumn}
*/
custom(renderFunc, asHtml, type)
{
this._type = type || 'custom';
this._asHtml = asHtml || false;
this._func = (value, opts, model) =>
{
return renderFunc(value, model, opts);
};
return this;
}
/**
* Render a text output
* @param {object} [options] - Custom options
* @param {boolean} [options.localize] - Localize the value in case it is a translation
* @param {string} [options.tokens] - For localized values you can pass in replacement tokens here
* @param {boolean} [options.wrap] - Allow text wrapping / multi-line
* @returns {ListColumn}
*/
text(options)
{
this._type = 'text';
this._funcOptions = { localize: false, tokens: {}, wrap: false, ...options };
this._func = (value, opts) =>
{
let result = value;
if (opts.localize)
{
result = localize(value, opts.tokens || {});
}
return result;
}
return this;
}
/**
* Render a text (as HTML) output
* @param {object} [options] - Custom options
* @param {boolean} [options.localize] - Localize the value in case it is a translation
* @param {string} [options.tokens] - For localized values you can pass in replacement tokens here
* @param {boolean} [options.wrap] - Allow text wrapping / multi-line
* @returns {ListColumn}
*/
html(options)
{
this._type = 'html';
this._asHtml = true;
return this.text(options);
}
/**
* Output a date
* @param {object} [options] - Custom options
* @param {string} [options.format] - Date format for the output (can also be "long" for a full date and "short" for full date-time)
* @returns {ListColumn}
*/
date(options)
{
this._type = 'date';
this._funcOptions = { format: 'short', ...options };
this._func = (value, opts) => formatDate(value, opts.format);
return this;
}
/**
* Output a currency value
* @returns {ListColumn}
*/
currency()
{
this._type = 'currency';
this._asHtml = true;
this._func = (value, opts) =>
{
let price = isNaN(value) ? 0 : value;
let hasDecimals = ~~price !== price;
price = hasDecimals ? (price / 1).toFixed(2) : ~~price;
return price.toString().replace(/\B(?=(\d{3})+(?!\d))/g, " ") + " €";
};
return this;
}
/**
* Output a boolean value by displaying a checkmark
* @param {function} [isTrueFunc] - Decide if this boolean is true based on a function with the value as a parameter
* @returns {ListColumn}
*/
boolean(isTrueFunc)
{
this._type = 'boolean';
this._asHtml = true;
this._funcOptions = { isTrueFunc };
this._func = (value, opts) =>
{
let isTrue = typeof opts.isTrueFunc === 'function' ? !!opts.isTrueFunc(value) : !!value;
return `<svg class="ui-icon ui-table-field-bool" width="16" height="16" stroke-width="${isTrue ? '2.5' : '2'}" data-symbol="${isTrue ? 'fth-check' : 'fth-x'}">
<use xlink:href="#${isTrue ? 'fth-check' : 'fth-x'}" />
</svg>`;
}
return this;
}
/**
* Output an image by using the value media ID
* @returns {ListColumn}
*/
image()
{
this._type = 'image';
this._asHtml = true;
// TODO correct app ID
this._func = (value, opts) => value ? `<img src="/zero/api/hofbauer/backoffice/ui/thumbnail/${(value)}-thumb.tmp" onerror="this.classList.add('is-error')" class="ui-table-field-image">` : '';
return this;
}
/**
* Outputs an icon
* @param {string} [icon] - Fixed icon name
* @param {string} [size=17] - Size of the icon
* @returns {ListColumn}
*/
icon(icon, size)
{
size = size || 17;
this._type = 'icon';
this._asHtml = true;
this._func = (value, opts) =>
{
let ico = (icon || value).trim();
let html = `<svg class="ui-icon ui-table-field-image" width="${size}" height="${size}" stroke-width="2" :data-symbol="${ico}">`;
if (ico.indexOf('flag') !== 0)
{
html += `<use xlink:href="#${ico}" />`;
}
return html + `</svg>`;
};
return this;
}
/**
* Shortcut for text() with predefined label and class
* @returns {ListColumn}
*/
name()
{
this.options.label = '@ui.name';
this.options.class = 'is-name is-primary';
this.options.primary = true;
this._type = 'text';
this._asHtml = true;
this._func = (value, opts, model) =>
{
let html = '<b>' + value + '</b>';
if (model.isActive === false)
{
html = value;
}
if (model.blueprint && model.blueprint.id)
{
html += ` <svg class="ui-icon" width="15" height="15" stroke-width="2" :data-symbol="fth-cloud" title="Synchronized"><use xlink:href="#fth-cloud" /></svg>`;
}
return html;
};
return this;
}
/**
* Shortcut for boolean() with predefined label and width
* @returns {ListColumn}
*/
active()
{
this.options.label = '@ui.active';
this.options.width = 150;
return this.boolean();
}
/**
* Shortcut for date() with predefined label and width
* @returns {ListColumn}
*/
created()
{
this.options.label = '@ui.createdDate';
this.options.width = 150;
return this.date();
}
}
export default ListColumn;