@silexlabs/grapesjs-data-source
Version:
Grapesjs Data Source
991 lines • 37.6 kB
JavaScript
;
/*
* Silex website builder, free/libre no-code tool for makers.
* Copyright (c) 2023 lexoyo and Silex Labs foundation
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.isString = isString;
exports.isDate = isDate;
exports.default = default_1;
const lit_1 = require("lit");
const utils_1 = require("../utils");
/**
* Check if a field is a number
*/
function isNumber(field, scalarOnly = true) {
if (!field || (scalarOnly && field.kind !== 'scalar'))
return false;
const typeIds = field.typeIds.map(typeId => typeId.toLowerCase());
return ['number', 'int', 'float', 'decimal', 'bigint', 'double', 'long', 'short', 'byte', 'integer', 'numeric'].some(t => typeIds.includes(t));
}
/**
* Check if a field is a string
* Exported for testing
*/
function isString(field, scalarOnly = true) {
if (!field || (scalarOnly && field.kind !== 'scalar'))
return false;
return field.typeIds
.map(typeId => typeId.toLowerCase())
.some(typeId => typeId.includes('string') ||
// In WP for example
typeId === 'id');
}
/**
* Check if a field is a date
* Exported for testing
*/
function isDate(field, scalarOnly = true) {
if (!field || (scalarOnly && field.kind !== 'scalar'))
return false;
return field.typeIds
.map(typeId => typeId.toLowerCase())
.some(typeId => typeId.includes('date') ||
typeId.includes('datetime') ||
typeId.includes('time') ||
typeId.includes('timestamp') ||
typeId.includes('instant') ||
typeId.includes('timestamptz') ||
typeId.includes('zoned') ||
// In WP for example
typeId.includes('string'));
}
/**
* Liquid filters
*/
function default_1(editor) {
return [
{
type: 'filter',
id: 'strip_html',
label: 'strip_html',
validate: (field) => isString(field),
output: type => type,
apply: (str) => str.replace(/<[^>]*>/g, ''),
options: {},
}, {
type: 'filter',
id: 'append',
label: 'append',
validate: (field) => isString(field),
output: type => type,
apply: (str, options) => `${str}${options.value}`,
options: {
value: '',
},
optionsForm: (selected, field, options, stateName) => (0, lit_1.html) `
<state-editor
.selected=${selected}
.editor=${editor}
name="value"
parent-name=${stateName}
data-is-input
no-filters
class="ds-state-editor__options"
value=${options.value || '[]'}
>
<label slot="label">Suffix</label>
</state-editor>
`,
}, {
type: 'filter',
id: 'prepend',
label: 'prepend',
validate: (field) => isString(field),
output: type => type,
apply: (str, options) => `${options.value}${str}`,
options: {
value: '',
},
optionsForm: (selected, field, options, stateName) => (0, lit_1.html) `
<state-editor
.selected=${selected}
.editor=${editor}
name="value"
parent-name=${stateName}
data-is-input
no-filters
class="ds-state-editor__options"
value=${options.value || '[]'}
>
<label slot="label">Prefix</label>
</state-editor>
`,
}, {
type: 'filter',
id: 'where',
label: 'where',
validate: (field) => !!field && field.kind === 'list',
output: field => field,
apply: (arr, options) => {
const { key, value } = options;
return arr.filter(item => item[key] === value);
},
options: {
key: '',
value: '',
},
quotedOptions: ['key'],
optionsKeys: ['key', 'value'],
optionsForm: (selected, field, options, stateName) => {
var _a;
return (0, lit_1.html) `
<state-editor
.selected=${selected}
.editor=${editor}
no-filters
data-is-input
class="ds-state-editor__options"
value=${options.key || []}
name="key"
root-type=${(_a = field === null || field === void 0 ? void 0 : field.typeIds[0]) !== null && _a !== void 0 ? _a : ''}
>
<label slot="label">Key to filter on</label>
</state-editor>
<p>==</p>
<state-editor
.selected=${selected}
.editor=${editor}
no-filters
parent-name=${stateName}
data-is-input
class="ds-state-editor__options"
value=${options.value || []}
name="value"
>
<label slot="label">Value to match</label>
</state-editor>
`;
},
}, {
// FIXME: the fields used in the expression are not available in the query
// // https://liquidjs.com/filters/where_exp.html
// type: 'filter',
// id: 'where_exp',
// label: 'where_exp',
// validate: (field: Field | null) => !!field && field.kind === 'list',
// output: field => field,
// apply: (arr, options) => {
// const { objectName, expression } = options as { objectName: string, expression: string }
// return (arr as Record<string, unknown>[]).filter(item => {
// // eslint-disable-next-line no-new-func
// const fn = new Function(objectName, `return ${expression}`)
// return fn(item)
// })
// },
// options: {
// objectName: 'item',
// expression: 'item.key === "value"',
// },
// quotedOptions: ['objectName', 'expression'],
// optionsKeys: ['objectName', 'expression'],
// optionsForm: (selected: Component, field: Field | null, options: Options) => html`
// <label>Object name
// <input type="text" name="objectName" placeholder="Object name" .value=${options.objectName || 'item'}/>
// </label>
// <label>Expression (JS)
// <input type="text" name="expression" placeholder="Expression" .value=${options.expression || 'item.key === "value"'}/>
// </label>
// `,
// }, {
// https://liquidjs.com/filters/find.html
type: 'filter',
id: 'find',
label: 'find',
validate: (field) => !!field && field.kind === 'list',
output: field => (0, utils_1.convertKind)(field, 'list', 'object'),
apply: (arr, options) => {
const { key, value } = options;
return arr.find(item => item[key] === value);
},
options: {
key: '',
value: '',
},
quotedOptions: ['key'],
optionsKeys: ['key', 'value'],
optionsForm: (selected, field, options, stateName) => {
var _a;
return (0, lit_1.html) `
<state-editor
.selected=${selected}
.editor=${editor}
no-filters
data-is-input
class="ds-state-editor__options"
value=${options.key || []}
name="key"
root-type=${(_a = field === null || field === void 0 ? void 0 : field.typeIds[0]) !== null && _a !== void 0 ? _a : ''}
>
<label slot="label">Key to filter on</label>
</state-editor>
<p>==</p>
<state-editor
.selected=${selected}
.editor=${editor}
no-filters
parent-name=${stateName}
data-is-input
class="ds-state-editor__options"
value=${options.value || []}
name="value"
>
<label slot="label">Value to match</label>
</state-editor>
`;
},
}, {
// FIXME: the fields used in the expression are not available in the query
// // https://liquidjs.com/filters/find_exp.html
// type: 'filter',
// id: 'find_exp',
// label: 'find_exp',
// validate: (field: Field | null) => !!field && field.kind === 'list',
// output: field => convertKind(field, 'list', 'object'),
// apply: (arr, options) => {
// const { objectName, expression } = options as { objectName: string, expression: string }
// return (arr as Record<string, unknown>[]).find(item => {
// // eslint-disable-next-line no-new-func
// const fn = new Function(objectName, `return ${expression}`)
// return fn(item)
// })
// },
// options: {
// objectName: 'item',
// expression: 'item.key === "value"',
// },
// quotedOptions: ['objectName', 'expression'],
// optionsKeys: ['objectName', 'expression'],
// optionsForm: (selected: Component, field: Field | null, options: Options) => html`
// <label>Object name
// <input type="text" name="objectName" placeholder="Object name" .value=${options.objectName || 'item'}/>
// </label>
// <label>Expression (JS)
// <input type="text" name="expression" placeholder="Expression" .value=${options.expression || 'item.key === "value"'}/>
// </label>
// `,
// }, {
type: 'filter',
id: 'first',
label: 'first',
validate: (field) => !!field && field.kind === 'list',
output: (field) => (0, utils_1.convertKind)(field, 'list', 'object'),
apply: (arr) => arr[0],
options: {},
}, {
type: 'filter',
id: 'last',
label: 'last',
validate: (field) => !!field && field.kind === 'list',
output: (field) => (0, utils_1.convertKind)(field, 'list', 'object'),
apply: (arr) => arr[arr.length - 1],
options: {},
}, {
type: 'filter',
id: 'join',
label: 'join',
validate: (field) => isString(field, false) && (field === null || field === void 0 ? void 0 : field.kind) === 'list',
output: (field) => (0, utils_1.convertKind)(field, 'list', 'scalar'),
apply: (arr, options) => { var _a; return arr.join((_a = options.separator) !== null && _a !== void 0 ? _a : ','); },
options: {
separator: ',',
},
quotedOptions: ['separator'],
optionsForm: (selected, field, options, stateName) => (0, lit_1.html) `
<state-editor
.selected=${selected}
.editor=${editor}
no-filters
parent-name=${stateName}
data-is-input
class="ds-state-editor__options"
value=${options.separator || []}
name="separator"
>
<label slot="label">Separator</label>
</state-editor>
`,
}, {
type: 'filter',
id: 'split',
label: 'split',
validate: (field) => isString(field),
output: (field) => (0, utils_1.convertKind)(field, 'scalar', 'list'),
apply: (str, options) => { var _a; return str.split((_a = options.separator) !== null && _a !== void 0 ? _a : ','); },
options: {
separator: ',',
},
quotedOptions: ['separator'],
optionsForm: (selected, field, options, stateName) => (0, lit_1.html) `
<state-editor
.selected=${selected}
.editor=${editor}
no-filters
parent-name=${stateName}
data-is-input
class="ds-state-editor__options"
value=${options.separator || []}
name="separator"
>
<label slot="label">Separator</label>
</state-editor>
`,
}, {
type: 'filter',
id: 'map',
label: 'map',
validate: (field) => !!field && (field.kind === 'list' || field.kind === 'object'),
output: (field, options) => (0, utils_1.getFieldType)(editor, field, options['key'], null),
apply: (arr, options) => arr.map(item => item[options.key]),
options: {
key: '',
},
quotedOptions: ['key'],
optionsForm: (selected, field, options) => {
var _a;
return (0, lit_1.html) `
<state-editor
.selected=${selected}
.editor=${editor}
no-filters
data-is-input
class="ds-state-editor__options"
value=${options.key || []}
name="key"
root-type=${(_a = field === null || field === void 0 ? void 0 : field.typeIds[0]) !== null && _a !== void 0 ? _a : ''}
>
<label slot="label">Key to map</label>
</state-editor>
`;
},
// This is a dynamic key, but it's not working yet
// The problem is that output method can only return a single field, but we need to return a list of fields
// This was an attempt returning the first field only but this makes it impossible to select fields inside the result object and the query will not include the content of the fields we should return
// }, {
// type: 'filter',
// id: 'map-dynamic',
// filterName: 'map',
// label: 'map (dynamic key)',
// validate: (field: Field | null) => !!field && (field.kind === 'list' || field.kind === 'object'),
// // Any field can be chosen, so we return the first one
// // Is multiple fields necessary? We will probably always have the same data structure there
// output: (field) => field ? editor.DataSourceManager.getDataTree()
// .getType(field.typeIds[0], field.dataSourceId ?? null)?.fields[0] ?? null : null,
// apply: (arr, options) => (arr as Record<string, unknown>[]).map(item => item[options.key as string]),
// options: {
// key: '',
// },
// quotedOptions: [],
// optionsForm: (field: Field | null, options: Options) => html`
// <state-editor
// no-filters
// data-is-input
// class="ds-state-editor__options"
// value=${options.key || []}
// name="key"
// ${ref(el => el && (el as StateEditor).setEditor(editor))}
// >
// <label slot="label">Key to map (dyanamic)</label>
// </state-editor>
// `,
}, {
type: 'filter',
id: 'reverse',
label: 'reverse',
validate: (field) => !!field && field.kind === 'list',
output: field => field,
apply: (arr) => [...arr].reverse(),
options: {},
}, {
type: 'filter',
id: 'size',
label: 'size',
validate: (field) => !!field && field.kind === 'list',
output: () => ({
id: 'Int',
label: 'Int',
typeIds: ['Int'],
kind: 'scalar',
}),
apply: (arr) => arr.length,
options: {},
}, {
type: 'filter',
id: 'slice',
label: 'slice',
validate: (field) => !!field && field.kind === 'list',
output: field => field,
apply: (arr, options) => arr.slice(options.start, options.end),
options: {
start: 0,
end: 0,
},
optionsKeys: ['start', 'end'],
optionsForm: (selected, field, options, stateName) => (0, lit_1.html) `
<state-editor
.selected=${selected}
.editor=${editor}
no-filters
parent-name=${stateName}
data-is-input
class="ds-state-editor__options"
value=${options.start || []}
name="start"
>
<label slot="label">Start index</label>
</state-editor>
<state-editor
.selected=${selected}
.editor=${editor}
no-filters
parent-name=${stateName}
data-is-input
class="ds-state-editor__options"
value=${options.end || []}
name="end"
>
<label slot="label">End index</label>
</state-editor>
`,
}, {
type: 'filter',
id: 'sort',
label: 'sort',
validate: (field) => !!field && field.kind === 'list',
output: field => field,
apply: (arr, options) => arr.sort((a, b) => {
if (a[options.key] < b[options.key]) {
return -1;
}
if (a[options.key] > b[options.key]) {
return 1;
}
return 0;
}),
quotedOptions: ['key'],
options: {
key: '',
},
optionsForm: (selected, field, options) => {
var _a;
return (0, lit_1.html) `
<state-editor
.selected=${selected}
.editor=${editor}
no-filters
data-is-input
class="ds-state-editor__options"
value=${options.key || []}
name="key"
root-type=${(_a = field === null || field === void 0 ? void 0 : field.typeIds[0]) !== null && _a !== void 0 ? _a : ''}
>
<label slot="label">Key to sort on</label>
</state-editor>
`;
},
}, {
type: 'filter',
id: 'plus',
label: 'plus',
validate: (field) => isNumber(field),
output: type => type,
apply: (num, options) => num + options.value,
options: {
value: 0,
},
optionsForm: (selected, field, options) => (0, lit_1.html) `
<label>Value
<input type="number" name="value" placeholder="Value" .value=${options.value || 0}/>
</label>
`,
}, {
type: 'filter',
id: 'minus',
label: 'minus',
validate: (field) => isNumber(field),
output: type => type,
apply: (num, options) => num - options.value,
options: {
value: 0,
},
optionsForm: (selected, field, options) => (0, lit_1.html) `
<label>Value
<input type="number" name="value" placeholder="Value" .value=${options.value || 0}/>
</label>
`,
}, {
type: 'filter',
id: 'times',
label: 'times',
validate: (field) => isNumber(field),
output: type => type,
apply: (num, options) => num * options.value,
options: {
value: 0,
},
optionsForm: (selected, field, options) => (0, lit_1.html) `
<label>Value
<input type="number" name="value" placeholder="Value" .value=${options.value || 0}/>
</label>
`,
}, {
type: 'filter',
id: 'divided_by',
label: 'divided_by',
validate: (field) => isNumber(field),
output: type => type,
apply: (num, options) => num / options.value,
options: {
value: 0,
},
optionsForm: (selected, field, options) => (0, lit_1.html) `
<label>Value
<input type="number" name="value" placeholder="Value" .value=${options.value || 0}/>
</label>
`,
}, {
type: 'filter',
id: 'modulo',
label: 'modulo',
validate: (field) => isNumber(field),
output: type => type,
apply: (num, options) => (num % options.value),
options: {
value: 0,
},
optionsForm: (selected, field, options) => (0, lit_1.html) `
<label>Value
<input type="number" name="value" placeholder="Value" .value=${options.value || 0}/>
</label>
`,
}, {
type: 'filter',
id: 'abs',
label: 'abs',
validate: (field) => isNumber(field),
output: type => type,
apply: (num) => Math.abs(num),
options: {},
}, {
type: 'filter',
id: 'ceil',
label: 'ceil',
validate: (field) => isNumber(field),
output: type => type,
apply: (num) => Math.ceil(num),
options: {},
}, {
type: 'filter',
id: 'floor',
label: 'floor',
validate: (field) => isNumber(field),
output: type => type,
apply: (num) => Math.floor(num),
options: {},
}, {
type: 'filter',
id: 'round',
label: 'round',
validate: (field) => isNumber(field),
output: type => type,
apply: (num) => Math.round(num),
options: {},
}, {
type: 'filter',
id: 'at_least',
label: 'at_least',
validate: (field) => isNumber(field),
output: type => type,
apply: (num, options) => Math.max(num, options.value),
options: {
value: 0,
},
optionsForm: (selected, field, options) => (0, lit_1.html) `
<label>Value
<input type="number" name="value" placeholder="Value" .value=${options.value || 0}/>
</label>
`,
}, {
type: 'filter',
id: 'at_most',
label: 'at_most',
validate: (field) => isNumber(field),
output: type => type,
apply: (num, options) => Math.min(num, options.value),
options: {
value: 0,
},
optionsForm: (selected, field, options) => (0, lit_1.html) `
<label>Value
<input type="number" name="value" placeholder="Value" .value=${options.value || 0}/>
</label>
`,
}, {
type: 'filter',
id: 'compact',
label: 'compact',
validate: (field) => !!field && field.kind === 'list',
output: field => field,
apply: (arr) => arr.filter(item => !!item),
options: {},
}, {
type: 'filter',
id: 'default',
label: 'default',
validate: (field) => !!field && field.kind === 'scalar',
output: field => field,
apply: (value, options) => value || options.value,
options: {
value: '',
},
optionsForm: (selected, field, options, stateName) => (0, lit_1.html) `
<state-editor
.selected=${selected}
.editor=${editor}
name="value"
parent-name=${stateName}
data-is-input
no-filters
class="ds-state-editor__options"
value=${options.value || '[]'}
>
<label slot="label">Default value</label>
</state-editor>
`,
}, {
type: 'filter',
id: 'escape',
label: 'escape',
validate: (field) => isString(field),
output: type => type,
apply: (str) => str.replace(/"/g, '\\"'),
options: {},
}, {
type: 'filter',
id: 'escape_once',
label: 'escape_once',
validate: (field) => isString(field),
output: type => type,
apply: (str) => str.replace(/"/g, '\\"'),
options: {},
}, {
type: 'filter',
id: 'newline_to_br',
label: 'newline_to_br',
validate: (field) => isString(field),
output: type => type,
apply: (str) => str.replace(/\n/g, '<br />'),
options: {},
}, {
type: 'filter',
id: 'strip_newlines',
label: 'strip_newlines',
validate: (field) => isString(field),
output: type => type,
apply: (str) => str.replace(/\n/g, ''),
options: {},
}, {
type: 'filter',
id: 'truncate',
label: 'truncate',
validate: (field) => isString(field),
output: type => type,
apply: (str, options) => str.slice(0, options.length),
options: {
length: 50,
},
optionsForm: (selected, field, options) => (0, lit_1.html) `
<label>Length
<input type="number" name="length" placeholder="Length" .value=${options.length || 50}/>
</label>
`,
}, {
type: 'filter',
id: 'truncatewords',
label: 'truncatewords',
validate: (field) => isString(field),
output: type => type,
apply: (str, options) => str.split(' ').slice(0, options.length).join(' '),
options: {
length: 15,
},
optionsForm: (selected, field, options) => (0, lit_1.html) `
<label>Length
<input type="number" name="length" placeholder="Length" .value=${options.length || 15}/>
</label>
`,
}, {
type: 'filter',
id: 'date',
label: 'date',
validate: (field) => isDate(field),
output: () => ({
id: 'String',
label: 'String',
typeIds: ['String'],
kind: 'scalar',
}),
// Simple strftime implementation for preview
// See liquidjs's full implementation: https://github.com/harttle/liquidjs/blob/master/src/util/strftime.ts
apply: (date, options) => {
const d = new Date(date);
const tz = options.timeZone || 'UTC';
// Get date parts in the specified timezone
const parts = new Intl.DateTimeFormat('en-US', {
timeZone: tz,
weekday: 'short',
year: 'numeric',
month: 'short',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
hour12: false,
}).formatToParts(d);
const get = (type) => { var _a; return ((_a = parts.find(p => p.type === type)) === null || _a === void 0 ? void 0 : _a.value) || ''; };
const monthNum = String(new Date(d.toLocaleString('en-US', { timeZone: tz })).getMonth() + 1).padStart(2, '0');
const tokens = {
'%a': get('weekday'), // Sun
'%b': get('month'), // Jan
'%d': get('day'), // 01
'%y': get('year').slice(-2), // 25
'%Y': get('year'), // 2025
'%m': monthNum, // 01
'%H': get('hour'), // 14
'%M': get('minute'), // 30
'%S': get('second'), // 05
'%%': '%',
};
return options.format.replace(/%[a-zA-Z%]/g, match => { var _a; return (_a = tokens[match]) !== null && _a !== void 0 ? _a : match; });
},
options: {
format: '%a, %b %d, %y', // Fri, Jul 17, 15
timeZone: 'UTC',
},
optionsKeys: ['format', 'timeZone'],
quotedOptions: ['format', 'timeZone'],
optionsForm: (selected, field, options) => (0, lit_1.html) `
<div>
<label>Format<br>
<input type="text" name="format" placeholder="Format" .value=${options.format || '%a, %b %d, %y'}/>
</label>
</div>
<br><br>
<div>
<label>Timezone<br>
<input type="text" name="timeZone" aria-describedby="tz-help" list="tz-list" placeholder="e.g. Europe/Paris, UTC, America/New_York" .value=${options.timeZone || 'UTC'}/>
</label>
</div>
<datalist id="tz-list">
<option value="UTC"></option>
<option value="Europe/Paris"></option>
<option value="Europe/London"></option>
<option value="America/New_York"></option>
<option value="America/Los_Angeles"></option>
<option value="America/Chicago"></option>
<option value="Asia/Tokyo"></option>
<option value="Asia/Shanghai"></option>
<option value="Asia/Kolkata"></option>
<option value="Australia/Sydney"></option>
<option value="Africa/Johannesburg"></option>
<option value="America/Sao_Paulo"></option>
</datalist>
<details id="tz-help">
<summary>Timezone help</summary>
<p>Use a valid IANA time zone.</p>
<ul>
<li>Expected format: IANA time zone (Area/City)</li>
<li>Examples: Europe/Paris, UTC, America/New_York</li>
<li>Required field — cannot be empty</li>
</ul>
<p>See the recommended list:
<a href="https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List" target="_blank" rel="noopener">IANA TZ database time zones</a>.
</p>
</details>
`,
}, {
type: 'filter',
id: 'replace',
label: 'replace',
validate: (field) => isString(field),
output: type => type,
apply: (str, options) => str.replace(options.search, options.replace),
options: {
search: '',
replace: '',
},
quotedOptions: ['search', 'replace'],
optionsKeys: ['search', 'replace'],
optionsForm: (selected, field, options) => (0, lit_1.html) `
<label>Search
<input type="text" name="search" placeholder="Search" .value=${options.search || ''}/>
</label>
<label>Replace
<input type="text" name="replace" placeholder="Replace" .value=${options.replace || ''}/>
</label>
`,
}, {
type: 'filter',
id: 'replace_first',
label: 'replace_first',
validate: (field) => isString(field),
output: type => type,
apply: (str, options) => str.replace(options.search, options.replace),
options: {
search: '',
replace: '',
},
quotedOptions: ['search', 'replace'],
optionsKeys: ['search', 'replace'],
optionsForm: (selected, field, options) => (0, lit_1.html) `
<label>Search
<input type="text" name="search" placeholder="Search" .value=${options.search || ''}/>
</label>
<label>Replace
<input type="text" name="replace" placeholder="Replace" .value=${options.replace || ''}/>
</label>
`,
}, {
type: 'filter',
id: 'replace_last',
label: 'replace_last',
validate: (field) => isString(field),
output: type => type,
apply: (str, options) => {
const index = str.lastIndexOf(options.search);
if (index === -1)
return str;
return str.slice(0, index) + options.replace + str.slice(index + options.search.length);
},
options: {
search: '',
replace: '',
},
quotedOptions: ['search', 'replace'],
optionsKeys: ['search', 'replace'],
optionsForm: (selected, field, options) => (0, lit_1.html) `
<label>Search
<input type="text" name="search" placeholder="Search" .value=${options.search || ''}/>
</label>
<label>Replace
<input type="text" name="replace" placeholder="Replace" .value=${options.replace || ''}/>
</label>
`,
}, {
type: 'filter',
id: 'remove',
label: 'remove',
validate: (field) => isString(field),
output: type => type,
apply: (str, options) => str.replace(options.search, ''),
options: {
search: 'delete this text',
},
quotedOptions: ['search'],
optionsKeys: ['search'],
optionsForm: (selected, field, options) => (0, lit_1.html) `
<label>Text to remove
<input type="text" name="search" placeholder="Delete this text" .value=${options.search || 'delete this text'}/>
</label>
`,
}, {
type: 'filter',
id: 'remove_first',
label: 'remove_first',
validate: (field) => isString(field),
output: type => type,
apply: (str, options) => str.replace(options.search, ''),
options: {
search: 'delete this text',
},
quotedOptions: ['search'],
optionsKeys: ['search'],
optionsForm: (selected, field, options) => (0, lit_1.html) `
<label>Text to remove
<input type="text" name="search" placeholder="Delete this text" .value=${options.search || 'delete this text'}/>
</label>
`,
}, {
type: 'filter',
id: 'remove_last',
label: 'remove_last',
validate: (field) => isString(field),
output: type => type,
apply: (str, options) => {
const index = str.lastIndexOf(options.search);
if (index === -1)
return str;
return str.slice(0, index) + str.slice(index + options.search.length);
},
options: {
search: 'delete this text',
},
quotedOptions: ['search'],
optionsKeys: ['search'],
optionsForm: (selected, field, options) => (0, lit_1.html) `
<label>Text to remove
<input type="text" name="search" placeholder="Delete this text" .value=${options.search || 'delete this text'}/>
</label>
`,
}, {
type: 'filter',
id: 'downcase',
label: 'downcase',
validate: (field) => isString(field),
output: type => type,
apply: (str) => str ? str.toLowerCase() : '',
options: {},
}, {
type: 'filter',
id: 'upcase',
label: 'upcase',
validate: (field) => isString(field),
output: type => type,
apply: (str) => str ? str.toUpperCase() : '',
options: {},
}, {
type: 'filter',
id: 'capitalize',
label: 'capitalize',
validate: (field) => isString(field),
output: type => type,
apply: (str) => str.charAt(0).toUpperCase() + str.slice(1).toLowerCase(),
options: {},
}, {
// Pick a random value from an array. Optionally, pick multiple values, default is 1 value.
// https://jekyllrb.com/docs/liquid/filters/
type: 'filter',
id: 'sample',
label: 'sample',
validate: (field) => !!field && field.kind === 'list',
output: field => field,
apply: (arr, options) => {
const count = parseInt(options.count || '1');
return (arr || [])
.sort(() => 0.5 - Math.random())
.slice(0, count);
},
options: {
count: '1',
},
optionsForm: (selected, field, options) => (0, lit_1.html) `
<label>Count
<input type="number" name="count" placeholder="Count" .value=${options.count}/>
</label>
`,
},
];
}
//# sourceMappingURL=liquid.js.map