@blinkk/selective-edit
Version:
Selective structured text editor.
200 lines • 7.15 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Fields = void 0;
const preview_1 = require("../utility/preview");
const lit_html_1 = require("lit-html");
const mixins_1 = require("../mixins");
const data_1 = require("../mixins/data");
const deepObject_1 = require("../utility/deepObject");
const uuid_1 = require("../mixins/uuid");
const lodash_merge_1 = __importDefault(require("lodash.merge"));
const repeat_js_1 = require("lit-html/directives/repeat.js");
/**
* Fields control the display of a list of fields in the editor.
*/
class Fields extends (0, uuid_1.UuidMixin)((0, data_1.DataMixin)(mixins_1.Base)) {
constructor(types, config, globalConfig) {
super();
this.types = types;
this.config = config;
this.globalConfig = globalConfig;
this.isLocked = false;
this.fields = [];
// Create the fields based on the config.
for (const fieldConfig of this.config.fields || []) {
this.addField(fieldConfig);
}
}
addField(fieldConfig) {
fieldConfig.parentKey = this.config.parentKey;
fieldConfig.isGuessed = this.config.isGuessed;
const newField = this.types.fields.newFromKey(fieldConfig.type, this.types, fieldConfig, this.globalConfig);
if (!newField) {
console.error(`Unable to add field for unknown field type: ${fieldConfig.type}.`);
return;
}
this.fields.push(newField);
}
get allowSimple() {
return !this.config.previewField && !this.config.previewFields;
}
/**
* When there is no value, guess based on the known information about
* the fields.
*/
guessDefaultValue() {
// When there are multiple fields, default is an object.
if (this.fields.length > 1) {
return {};
}
return '';
}
/**
* Checks if the value is clean (unchanged) from the original value.
*/
get isClean() {
for (const field of this.fields) {
if (!field.isClean) {
return false;
}
}
return true;
}
/**
* Checks if the fields are simple and can be simplified in the display.
*/
get isSimple() {
// Cannot be simple if there are more than one field.
if (this.fields.length > 1) {
return false;
}
// Allow the field to mark it as complex.
for (const field of this.fields) {
if (!field.isSimple) {
return false;
}
}
return true;
}
/**
* Checks all the fields to find out if there are invalid fields.
*/
get isValid() {
for (const field of this.fields) {
if (!field.isValid) {
return false;
}
}
return true;
}
/**
* Certain cases require the field to be locked while updating to prevent bad
* data mixing. This allows for manually locking the fields.
*/
lock() {
this.isLocked = true;
// Lock all the fields to prevent them from being updated.
for (const field of this.fields) {
field.lock();
}
}
get previewFields() {
return (0, preview_1.combinePreviewKeys)(this.config.previewFields, this.config.previewField);
}
reset() {
this.fields = [];
}
/**
* Template for determining how to render the fields.
*
* @param editor Selective editor used to render the template.
* @param data Data provided to render the template.
*/
template(editor, data) {
if (!this.fields.length) {
return (0, lit_html_1.html) ``;
}
if (this.isSimple) {
return (0, lit_html_1.html) ` ${this.updateOriginal(editor, data)}
${this.fields[0].template(editor, data)}`;
}
return (0, lit_html_1.html) `<div class="selective__fields">
${this.updateOriginal(editor, data)}
${(0, repeat_js_1.repeat)(this.fields, (field) => field.uuid, (field) => (0, lit_html_1.html) ` ${field.template(editor, data)} `)}
</div>`;
}
/**
* Template for how to render a preview.
*
* @param editor Selective editor used to render the template.
* @param data Data provided to render the template.
*/
templatePreviewValue(
// eslint-disable-next-line @typescript-eslint/no-unused-vars
editor,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
data, index) {
const defaultValue = 'Untitled item';
const previewValue = (0, preview_1.findOrGuessPreviewValue)(this.value, this.previewFields, defaultValue);
return (0, preview_1.templatePreviewValue)(previewValue, this.config.previewType ? this.config.previewType : preview_1.PreviewTypes.Text, defaultValue, index);
}
/**
* Certain cases require the field to be locked while updating to prevent bad
* data mixing. This allows for manually unlocking the fields.
*/
unlock() {
this.isLocked = false;
// Lock all the fields to prevent them from being updated.
for (const field of this.fields) {
field.unlock();
}
}
/**
* The data is not known to the fields until the rendering is done.
*
* Updated the original value from the data provided during rendering.
* This gives a base set of values for clean checks and validation to use.
*
* @param editor Selective editor used to render the template.
* @param data Data provided to render the template.
* @param deep Update in fields as well, such as when the field is not visible.
*/
updateOriginal(editor, data, deep = false) {
// Manual locking prevents the original value overwriting the value
// in special cases when it should not.
if (this.isLocked) {
return;
}
this.originalValue = data;
if (deep) {
// Update all the fields since they may not get rendered.
// Ex: a collapsed list would not get the update.
for (const field of this.fields) {
field.updateOriginal(editor, data);
}
}
}
/**
* Returns the value from all of the fields in a single object.
*/
get value() {
if (!this.fields.length) {
return null;
}
if (this.allowSimple && this.isSimple && !this.fields[0].key) {
return this.fields[0].value;
}
// Merging with the original value after setting values causes
// issues where blank arrays are replaced by the original arrays.
const value = new deepObject_1.DeepObject((0, lodash_merge_1.default)({}, this?.originalValue?.obj));
for (const field of this.fields) {
value.set(field.key, field.value);
}
return value.obj;
}
}
exports.Fields = Fields;
//# sourceMappingURL=fields.js.map