UNPKG

@davebaol/angular-formio-editor

Version:

Angular component integrating Form.io builder and renderer with a json editor

1,286 lines (1,272 loc) 83.5 kB
import { __values, __extends, __decorate } from 'tslib'; import { Input, ViewChild, Component as Component$1, EventEmitter, Output, NgModule } from '@angular/core'; import { BsModalService, ModalModule } from 'ngx-bootstrap/modal'; import { FormsModule } from '@angular/forms'; import { BrowserModule } from '@angular/platform-browser'; import { FormioModule } from 'angular-formio'; import { AlertModule } from 'ngx-bootstrap/alert'; import JsonEditor from 'jsoneditor'; var _this = this; /* This is heavily inspired by https://github.com/schnittstabil/merge-options */ var _a = Object.prototype, hasOwnProperty = _a.hasOwnProperty, toString = _a.toString; var propertyIsEnumerable = Object.propertyIsEnumerable; var globalThis = this; var defaultMergeOpts = { ignoreUndefined: false }; var isPlainObject = function (value) { if (toString.call(value) !== '[object Object]') { return false; } var prototype = Object.getPrototypeOf(value); return prototype === null || prototype === Object.prototype; }; var ɵ0 = isPlainObject; var defineProperty = function (obj, name, value) { Object.defineProperty(obj, name, { value: value, writable: true, enumerable: true, configurable: true }); }; var ɵ1 = defineProperty; var getEnumerableOwnPropertyKeys = function (value) { var e_1, _a; var keys = []; for (var key in value) { if (hasOwnProperty.call(value, key)) { keys.push(key); } } if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(value); try { for (var symbols_1 = __values(symbols), symbols_1_1 = symbols_1.next(); !symbols_1_1.done; symbols_1_1 = symbols_1.next()) { var symbol = symbols_1_1.value; if (propertyIsEnumerable.call(value, symbol)) { keys.push(symbol); } } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (symbols_1_1 && !symbols_1_1.done && (_a = symbols_1.return)) _a.call(symbols_1); } finally { if (e_1) throw e_1.error; } } } return keys; }; var ɵ2 = getEnumerableOwnPropertyKeys; var clone = function (value) { if (Array.isArray(value)) { return cloneArray(value); } if (isPlainObject(value)) { return clonePlainObject(value); } return value; }; var cloneArray = function (array) { var result = array.slice(0, 0); getEnumerableOwnPropertyKeys(array).forEach(function (key) { defineProperty(result, key, clone(array[key])); }); return result; }; var ɵ3 = cloneArray; var clonePlainObject = function (obj) { var result = Object.getPrototypeOf(obj) === null ? Object.create(null) : {}; getEnumerableOwnPropertyKeys(obj).forEach(function (key) { defineProperty(result, key, clone(obj[key])); }); return result; }; var ɵ4 = clonePlainObject; var mergeKeys = function (merged, source, keys, config) { keys.forEach(function (key) { if (typeof source[key] === 'undefined' && config.ignoreUndefined) { return; } // Do not recurse into prototype chain of merged if (key in merged && merged[key] !== Object.getPrototypeOf(merged)) { defineProperty(merged, key, _merge(merged[key], source[key], config)); } else { defineProperty(merged, key, clone(source[key])); } }); return merged; }; var ɵ5 = mergeKeys; // tslint:disable-next-line:variable-name var _merge = function (merged, source, config) { if (!isPlainObject(source) || !isPlainObject(merged)) { return clone(source); } return mergeKeys(merged, source, getEnumerableOwnPropertyKeys(source), config); }; var ɵ6 = _merge; var merge = function () { var e_2, _a; var options = []; for (var _i = 0; _i < arguments.length; _i++) { options[_i] = arguments[_i]; } var config = _merge(clone(defaultMergeOpts), (_this !== globalThis && _this) || {}, defaultMergeOpts); var merged = { _: {} }; try { for (var options_1 = __values(options), options_1_1 = options_1.next(); !options_1_1.done; options_1_1 = options_1.next()) { var option = options_1_1.value; if (option === undefined) { continue; } if (!isPlainObject(option)) { throw new TypeError('`' + option + '` is not a plain Object'); } merged = _merge(merged, { _: option }, config); } } catch (e_2_1) { e_2 = { error: e_2_1 }; } finally { try { if (options_1_1 && !options_1_1.done && (_a = options_1.return)) _a.call(options_1); } finally { if (e_2) throw e_2.error; } } return merged._; }; var hasOwnProperty$1 = Object.prototype.hasOwnProperty; // ------------------------------- // SCHEMAS // ------------------------------- var Schema = /** @class */ (function () { function Schema(component) { this.component = component; this.conditions = []; this.required = false; this.dataType = {}; if (component && component.formioComponent) { if (component.formioComponent.conditional) { // Add non-empty condition from the component var cnd = component.formioComponent.conditional; if (typeof cnd.show === 'boolean' && cnd.when) { // console.log(component.formioComponent.type, "Pushing condition") var c = { show: cnd.show, when: cnd.when, eq: cnd.eq }; c.key = this.generateSingleConditionKey(c); this.conditions.push(c); } } if (component.formioComponent.validate) { this.required = component.formioComponent.validate.required; } } } /*private*/ Schema.prototype.generateSingleConditionKey = function (condition) { return JSON.stringify(condition); }; /*private*/ Schema.prototype.generateConditionsKey = function () { return JSON.stringify(this.conditions, function (k, v) { return k === 'key' ? undefined : v; }); }; Schema.prototype.prepareConditions = function () { // Ensure the array has unique conditions this.conditions = this.conditions.sort(function (c1, c2) { return c1.key.compare(c2.key); }) .filter(function (x, i, a) { return i === 0 || x.key !== a[i - 1].key; }); this.conditions.key = this.generateConditionsKey(); }; Schema.prototype.shrink = function () { for (var k in this.properties) { if (hasOwnProperty$1.call(this.properties, k)) { var propSchema = this.properties[k]; if (propSchema instanceof MergeableObjectSchema && propSchema.component && propSchema.component.shrinkable()) { // console.log('Shrink', propSchema.component.formioComponent.type); propSchema.shrink(); delete this.properties[k]; // Remove shribkable schema from parent this.merge(propSchema); // merge its properties and conditions with parent } } } return this; }; // Subclasses overriding this method MUST call super.toJsonSchema() Schema.prototype.toJsonSchema = function () { return Object.assign({}, this.dataType); }; return Schema; }()); var ObjectSchema = /** @class */ (function (_super) { __extends(ObjectSchema, _super); function ObjectSchema(component) { var _this = _super.call(this, component) || this; _this.dataType.type = 'object'; _this.properties = {}; return _this; } ObjectSchema.prototype.addProperty = function (name, schema, required) { this.properties[name] = schema; schema.required = required; return this; }; ObjectSchema.prototype.toJsonSchema = function () { var jsonSchema = _super.prototype.toJsonSchema.call(this); jsonSchema.properties = {}; var required = []; var condPropMap = {}; var conditionsMap = {}; for (var pk in this.properties) { if (hasOwnProperty$1.call(this.properties, pk)) { var childSchema = this.properties[pk]; if (childSchema.conditions.length === 0) { if (childSchema.required) { required.push(pk); } jsonSchema.properties[pk] = childSchema.toJsonSchema(); continue; } childSchema.prepareConditions(); var ck = childSchema.conditions.key; conditionsMap[ck] = childSchema.conditions; if (!(ck in condPropMap)) { condPropMap[ck] = {}; } condPropMap[ck][pk] = childSchema; } } // Add required to jsonSchema if not empty if (required.length > 0) { jsonSchema.required = required; } // Generate allOf from conditional properties var allOf = []; for (var ck in condPropMap) { if (hasOwnProperty$1.call(condPropMap, ck)) { var conds = conditionsMap[ck]; var _if = { properties: conds.reduce(function (acc, c) { acc[c.when] = c.show ? { const: c.eq } : { not: { const: c.eq } }; return acc; }, {}) }; var then = { required: [], properties: {} }; for (var pk in condPropMap[ck]) { if (hasOwnProperty$1.call(condPropMap[ck], pk)) { var childSchema = condPropMap[ck][pk]; if (childSchema.required) { then.required.push(pk); } then.properties[pk] = childSchema.toJsonSchema(); } } // Remove empty required if (then.required.length === 0) { delete then.required; } // Add if/then to allOf allOf.push({ if: _if, then: then }); } } // Add allOf to jsonSchema if not empty if (allOf.length > 0) { jsonSchema.allOf = allOf; } return jsonSchema; }; return ObjectSchema; }(Schema)); var MergeableObjectSchema = /** @class */ (function (_super) { __extends(MergeableObjectSchema, _super); function MergeableObjectSchema(component) { return _super.call(this, component) || this; } MergeableObjectSchema.prototype.merge = function () { var sources = []; for (var _i = 0; _i < arguments.length; _i++) { sources[_i] = arguments[_i]; } var targetProps = this.properties; for (var i = 0, len = sources.length; i < len; i++) { var source = sources[i]; if (source instanceof MergeableObjectSchema) { // merge properties var sourceProps = source.properties; for (var key in sourceProps) { if (hasOwnProperty$1.call(sourceProps, key)) { // Append source schema conditions to the conditions of its sub-schemas Array.prototype.push.apply(sourceProps[key].conditions, source.conditions); // Merge properties recursively if (targetProps[key] && sourceProps[key] instanceof MergeableObjectSchema) { targetProps[key].merge(sourceProps[key]); } else { targetProps[key] = sourceProps[key]; } } } } } return this; }; return MergeableObjectSchema; }(ObjectSchema)); var ArraySchema = /** @class */ (function (_super) { __extends(ArraySchema, _super); function ArraySchema(component, items) { var _this = _super.call(this, component) || this; _this.dataType.type = 'array'; _this.dataType.items = items; return _this; } ArraySchema.prototype.toJsonSchema = function () { var jsonSchema = _super.prototype.toJsonSchema.call(this); jsonSchema.items = this.dataType.items.toJsonSchema(); return jsonSchema; }; return ArraySchema; }(Schema)); var PrimitiveSchema = /** @class */ (function (_super) { __extends(PrimitiveSchema, _super); function PrimitiveSchema(component, type) { var _this = _super.call(this, component) || this; _this.dataType.type = type; return _this; } return PrimitiveSchema; }(Schema)); var BooleanSchema = /** @class */ (function (_super) { __extends(BooleanSchema, _super); function BooleanSchema(component) { return _super.call(this, component, 'boolean') || this; } return BooleanSchema; }(PrimitiveSchema)); var NumberSchema = /** @class */ (function (_super) { __extends(NumberSchema, _super); function NumberSchema(component) { var _this = _super.call(this, component, 'number') || this; if (component && component.formioComponent && component.formioComponent.validate) { var validate = component.formioComponent.validate; if (validate.min || typeof validate.min === 'number') _this.dataType.minimum = Number(validate.min); if (validate.max || typeof validate.max === 'number') _this.dataType.maximum = Number(validate.max); if (validate.integer) _this.dataType.type = 'integer'; } return _this; } return NumberSchema; }(PrimitiveSchema)); var StringSchema = /** @class */ (function (_super) { __extends(StringSchema, _super); function StringSchema(component) { var _this = _super.call(this, component, 'string') || this; if (component && component.formioComponent && component.formioComponent.validate) { var validate = component.formioComponent.validate; if (validate.minLength) _this.dataType.minLength = Number(validate.minLength); if (validate.maxLength) _this.dataType.maxLength = Number(validate.maxLength); if (validate.pattern) _this.dataType.pattern = validate.pattern; } return _this; } return StringSchema; }(PrimitiveSchema)); var EnumSchema = /** @class */ (function (_super) { __extends(EnumSchema, _super); function EnumSchema(component, values) { var _this = _super.call(this, component) || this; _this.dataType.enum = values; return _this; } return EnumSchema; }(Schema)); // ------------------------------- // COMPONENT BASE CLASSES // ------------------------------- var Component = /** @class */ (function () { function Component(formioComponent) { this.formioComponent = formioComponent; } Component.prototype.schema = function () { throw new Error('Subclasses of \'Component\' have to implement the method \'schema\'!'); }; // Layout components are view-only components. From resource perspective, they are to be // shrinked, because they don't have any value neither implicit nor expressed by user. // So they don't contribute to the underlying resource because their 'API key' does not // match any field inside the resource itself. // Howewer, shrink process propagates component's condition (show/when/eq) to child components. Component.prototype.shrinkable = function () { return !(this.formioComponent && this.formioComponent.input); }; return Component; }()); var AtomicComponent = /** @class */ (function (_super) { __extends(AtomicComponent, _super); function AtomicComponent() { return _super !== null && _super.apply(this, arguments) || this; } AtomicComponent.prototype.schema = function () { var schema = this.baseSchema(); if (this.formioComponent.multiple) { if (this.formioComponent.validate && !this.formioComponent.validate.required) { // With multiple values enabled the component can generate null items if required is false schema.dataType = { anyOf: [schema.dataType, { type: 'null' }] }; } return new ArraySchema(this, schema); } return schema; }; AtomicComponent.prototype.baseSchema = function () { throw new Error('Subclasses of \'AtomicComponent\' have to implement the method \'baseSchema\'!'); }; AtomicComponent.prototype.isDefaultCastToString = function () { return false; // cast defaults to 'auto' }; AtomicComponent.prototype.cast = function (val, to) { switch (to) { case 'boolean': return val.toLowerCase() === 'true'; case 'number': return Number(val); case 'object': return JSON.parse(val); case 'string': return val; case 'auto': default: // Either autotype or string if (to !== 'auto' && this.isDefaultCastToString()) return val; if (val === "true") return true; if (val === "false") return false; if (val === "") return val; var v = Number(val); return isNaN(v) ? val : v; } }; return AtomicComponent; }(Component)); var CompoundComponent = /** @class */ (function (_super) { __extends(CompoundComponent, _super); function CompoundComponent() { return _super !== null && _super.apply(this, arguments) || this; } CompoundComponent.prototype.schema = function () { var schema = new MergeableObjectSchema(this); this.childrenSchema(schema); return schema.shrink(); }; /*prorected*/ CompoundComponent.prototype.children = function () { return this.formioComponent.components; }; // Subclasses can override this method to provide a default class // for children that don't have a type /*prorected*/ CompoundComponent.prototype.defaultChildClass = function () { return undefined; }; /*prorected*/ CompoundComponent.prototype.childrenSchema = function (parentSchema) { var children = this.children(); for (var i = 0, len = children.length; i < len; i++) { var c = children[i]; // console.log(this.formioComponent.type, 'child', c) var type = MAP[c.type] || this.defaultChildClass(); if (type) { var schema = new (type)(c).schema(); var required = c.validate && c.validate.required; // Dotted key means nested schema var keyParts = c.key.split('.'); for (var j = keyParts.length - 1; j > 0; j--) { schema = new MergeableObjectSchema(undefined).addProperty(keyParts[j], schema, required); } parentSchema.merge(new MergeableObjectSchema(undefined).addProperty(keyParts[0], schema, required)); } else { // console.log(this.formioComponent.type, ": skipping child with unknown type", c.type); } } return parentSchema; }; return CompoundComponent; }(Component)); // ------------------------------- // ABSTRACT COMPONENT CLASSES // ------------------------------- var StringComponent = /** @class */ (function (_super) { __extends(StringComponent, _super); function StringComponent() { return _super !== null && _super.apply(this, arguments) || this; } StringComponent.prototype.baseSchema = function () { return new StringSchema(this); }; return StringComponent; }(AtomicComponent)); var EnumComponent = /** @class */ (function (_super) { __extends(EnumComponent, _super); function EnumComponent(formioComponent) { var additionalValuesIfNotRequired = []; for (var _i = 1; _i < arguments.length; _i++) { additionalValuesIfNotRequired[_i - 1] = arguments[_i]; } var _this = _super.call(this, formioComponent) || this; _this.additionalValuesIfNotRequired = additionalValuesIfNotRequired; return _this; } // This is needed because different components take values from different path EnumComponent.prototype.values = function () { throw new Error('Subclasses of \'EnumComponent\' have to implement the method \'values\'!'); }; EnumComponent.prototype.baseSchema = function () { var _this = this; var values = this.values().map(function (v) { return _this.cast(v.value, _this.formioComponent.dataType); }); if (this.formioComponent && this.formioComponent.validate && !this.formioComponent.validate.required) { Array.prototype.push.apply(values, this.additionalValuesIfNotRequired); } return new EnumSchema(this, values); }; return EnumComponent; }(AtomicComponent)); // ------------------------------- // BASIC COMPONENTS // ------------------------------- var CheckboxComponent = /** @class */ (function (_super) { __extends(CheckboxComponent, _super); function CheckboxComponent() { return _super !== null && _super.apply(this, arguments) || this; } CheckboxComponent.prototype.baseSchema = function () { return new BooleanSchema(this); }; return CheckboxComponent; }(AtomicComponent)); var NumberComponent = /** @class */ (function (_super) { __extends(NumberComponent, _super); function NumberComponent() { return _super !== null && _super.apply(this, arguments) || this; } NumberComponent.prototype.baseSchema = function () { return new NumberSchema(this); }; return NumberComponent; }(AtomicComponent)); var PasswordComponent = /** @class */ (function (_super) { __extends(PasswordComponent, _super); function PasswordComponent() { return _super !== null && _super.apply(this, arguments) || this; } return PasswordComponent; }(StringComponent)); var RadioComponent = /** @class */ (function (_super) { __extends(RadioComponent, _super); function RadioComponent(formioComponent) { // Empty string and null are valid values if the component is not required return _super.call(this, formioComponent, '', null) || this; } RadioComponent.prototype.values = function () { return this.formioComponent.values; }; return RadioComponent; }(EnumComponent)); var SelectComponent = /** @class */ (function (_super) { __extends(SelectComponent, _super); function SelectComponent(formioComponent) { // Empty string and null are valid values if the component is not required return _super.call(this, formioComponent, '', null) || this; } SelectComponent.prototype.values = function () { return this.formioComponent.data.values; }; SelectComponent.prototype.schema = function () { var schema = _super.prototype.schema.call(this); // If multiple values are enabled ensure uniqueness if (schema instanceof ArraySchema) { schema.dataType.uniqueItems = true; } return schema; }; SelectComponent.prototype.isDefaultCastToString = function () { return true; // cast defaults to 'string' }; return SelectComponent; }(EnumComponent)); var SelectBoxesComponent = /** @class */ (function (_super) { __extends(SelectBoxesComponent, _super); function SelectBoxesComponent() { return _super !== null && _super.apply(this, arguments) || this; } SelectBoxesComponent.prototype.baseSchema = function () { var schema = new ObjectSchema(this); schema.dataType.additionalProperties = false; var values = this.formioComponent.values .forEach(function (v) { return schema.addProperty(v.value, new BooleanSchema(undefined), true); }); if (this.formioComponent.validate && !this.formioComponent.validate.required) { // This is needed for compatibility. // Formio adds a boolean property with name "" when the component is not required. // The property itself must not be required schema.addProperty('', new BooleanSchema(undefined), false); } return schema; }; return SelectBoxesComponent; }(AtomicComponent)); var TextAreaComponent = /** @class */ (function (_super) { __extends(TextAreaComponent, _super); function TextAreaComponent() { return _super !== null && _super.apply(this, arguments) || this; } return TextAreaComponent; }(StringComponent)); var TextFieldComponent = /** @class */ (function (_super) { __extends(TextFieldComponent, _super); function TextFieldComponent() { return _super !== null && _super.apply(this, arguments) || this; } return TextFieldComponent; }(StringComponent)); // ------------------------------- // ADVANCED COMPONENTS // ------------------------------- var DateTimeComponent = /** @class */ (function (_super) { __extends(DateTimeComponent, _super); function DateTimeComponent() { return _super !== null && _super.apply(this, arguments) || this; } return DateTimeComponent; }(StringComponent)); var EmailComponent = /** @class */ (function (_super) { __extends(EmailComponent, _super); function EmailComponent() { return _super !== null && _super.apply(this, arguments) || this; } return EmailComponent; }(StringComponent)); var UrlComponent = /** @class */ (function (_super) { __extends(UrlComponent, _super); function UrlComponent() { return _super !== null && _super.apply(this, arguments) || this; } return UrlComponent; }(StringComponent)); var TagsComponent = /** @class */ (function (_super) { __extends(TagsComponent, _super); function TagsComponent() { return _super !== null && _super.apply(this, arguments) || this; } TagsComponent.prototype.schema = function () { return this.formioComponent.storeas === 'array' ? new ArraySchema(this, this.baseSchema()) : this.baseSchema(); }; TagsComponent.prototype.baseSchema = function () { return new StringSchema(this); }; return TagsComponent; }(AtomicComponent)); // ------------------------------- // LAYOUT COMPONENTS // ------------------------------- var ColumnsComponent = /** @class */ (function (_super) { __extends(ColumnsComponent, _super); function ColumnsComponent() { return _super !== null && _super.apply(this, arguments) || this; } // Determines children from columns. // Children are calculated lazily and cached into this instance. ColumnsComponent.prototype.children = function () { var _this = this; if (!this.components) { this.components = []; this.formioComponent.columns.forEach(function (col) { return Array.prototype.push.apply(_this.components, col.components); }); } return this.components; }; return ColumnsComponent; }(CompoundComponent)); var ContentComponent = /** @class */ (function (_super) { __extends(ContentComponent, _super); function ContentComponent() { return _super !== null && _super.apply(this, arguments) || this; } ContentComponent.prototype.children = function () { return []; // This component never has children }; return ContentComponent; }(CompoundComponent)); var FieldSetComponent = /** @class */ (function (_super) { __extends(FieldSetComponent, _super); function FieldSetComponent() { return _super !== null && _super.apply(this, arguments) || this; } return FieldSetComponent; }(CompoundComponent)); var PanelComponent = /** @class */ (function (_super) { __extends(PanelComponent, _super); function PanelComponent() { return _super !== null && _super.apply(this, arguments) || this; } return PanelComponent; }(CompoundComponent)); var TableComponent = /** @class */ (function (_super) { __extends(TableComponent, _super); function TableComponent() { return _super !== null && _super.apply(this, arguments) || this; } // Determines children from table's rows and columns. // Children are calculated lazily and cached into this instance. TableComponent.prototype.children = function () { var _this = this; if (!this.components) { this.components = []; this.formioComponent.rows.forEach(function (row) { row.forEach(function (col) { return Array.prototype.push.apply(_this.components, col.components); }); }); } return this.components; }; return TableComponent; }(CompoundComponent)); var TabsComponent = /** @class */ (function (_super) { __extends(TabsComponent, _super); function TabsComponent() { return _super !== null && _super.apply(this, arguments) || this; } /*prorected*/ TabsComponent.prototype.defaultChildClass = function () { return CompoundComponent; // Needed because children don't have a type :( }; return TabsComponent; }(CompoundComponent)); var WellComponent = /** @class */ (function (_super) { __extends(WellComponent, _super); function WellComponent() { return _super !== null && _super.apply(this, arguments) || this; } return WellComponent; }(CompoundComponent)); // ------------------------------- // DATA COMPONENTS // ------------------------------- var EditGridComponent = /** @class */ (function (_super) { __extends(EditGridComponent, _super); function EditGridComponent() { return _super !== null && _super.apply(this, arguments) || this; } EditGridComponent.prototype.schema = function () { return new ArraySchema(this, _super.prototype.schema.call(this)); }; return EditGridComponent; }(CompoundComponent)); // ------------------------------- // FORM COMPONENT // ------------------------------- var FormComponent = /** @class */ (function (_super) { __extends(FormComponent, _super); function FormComponent() { return _super !== null && _super.apply(this, arguments) || this; } return FormComponent; }(CompoundComponent)); var MAP = { editgrid: EditGridComponent, checkbox: CheckboxComponent, columns: ColumnsComponent, content: ContentComponent, datetime: DateTimeComponent, email: EmailComponent, fieldset: FieldSetComponent, number: NumberComponent, password: PasswordComponent, panel: PanelComponent, radio: RadioComponent, select: SelectComponent, selectboxes: SelectBoxesComponent, table: TableComponent, tabs: TabsComponent, tags: TagsComponent, textarea: TextAreaComponent, textfield: TextFieldComponent, url: UrlComponent, well: WellComponent }; function generateFormJsonSchema(form) { return new FormComponent(form).schema().toJsonSchema(); } // tslint:disable:object-literal-key-quotes quotemark semicolon var schema = { "title": "Form", "description": "Object containing a form.io form", "type": "object", "required": ["components"], "properties": { "display": { "title": "Display mode", "description": "The given name.", "enum": ["form", "wizard"] }, "components": { "$ref": "components" } } }; // tslint:disable:object-literal-key-quotes quotemark semicolon var components = { "title": "Component List", "description": "The list of all components", "type": "array", "items": { "$ref": "component" } }; // tslint:disable:object-literal-key-quotes quotemark semicolon var componentStrict = { "title": "Component", "description": "Object containing a form.io component", "type": "object", "required": ["type", "key", "input"], "properties": { "type": { "title": "Component Type", "description": "The type of this component", "type": "string" }, "key": { "title": "Component Key", "description": "The API key for this component", "type": "string" }, "label": { "title": "Component Label", "description": "The HTML label to give this component", "type": "string" }, "placeholder": { "title": "Component Placeholder", "description": "The text to show in the input before they type", "type": "string" }, "input": { "title": "User Input?", "description": "Determines if this is an input from the user", "type": "boolean" }, "tableView": { "title": "Component TableView", "description": "Determines if this field will show in the data tables output", "type": "boolean" }, "multiple": { "title": "Component Multiple", "description": "If this field should collect multiple values, creating an array of values", "type": "boolean" }, "protected": { "title": "Component Protected", "description": "If the value of this field should be shown to the end user via API once it is saved", "type": "boolean" }, "prefix": { "title": "Component Prefix", "description": "The prefix text to put in front of the input", "type": "string" }, "suffix": { "title": "Component Suffix", "description": "The suffix text to put after the input", "type": "string" }, "defaultValue": { "title": "Default Value", "description": "The default value to provide to this component. Its type depends on the specific component" }, "clearOnHide": { "title": "Clear on Hide", "description": "If the value of this field should be cleared when it is conditionally hidden", "type": "boolean" }, "unique": { "title": "Unique", "description": "Validates if this field should be unique amongst other submissions in the same form", "type": "boolean" }, "persistent": { "title": "Persistent", "description": "Determines if the value of this field should be saved as persistent", "type": "boolean" }, "hidden": { "title": "Hidden", "description": "Determines if this field should be hidden from view by default. This can be overridden with the conditionals.", "type": "boolean" }, "validate": { "title": "Validate", "description": "Determines validation criteria for this component.", "type": "object", "properties": { "required": { "title": "Required", "description": "Specifies if the field is required.", "type": "boolean" }, "minLength": { "title": "Min Lenngth", "description": "For text input, this checks the minimum length of text for valid input.", "type": ["number", "string"] }, "maxLength": { "title": "Max Lenngth", "description": "For text input, this checks the maximum length of text for valid input.", "type": ["number", "string"] }, "pattern": { "title": "Pattern", "description": "For text input, this checks the text agains a Regular expression pattern.", "type": "string" }, "custom": { "title": "Custom", "description": "A custom javascript based validation or a JSON object for using JSON Logic.", "type": ["string", "object"] } } }, "conditional": { "$ref": "conditional" }, "errors": { "title": "Errors", "description": "Allows customizable errors to be displayed for each component when an error occurs.", "type": "object", "properties": { "required": { "title": "Required", "description": "Error message for error 'required'.", "type": "string" }, "min": { "title": "Min", "description": "Error message for error 'min'.", "type": "string" }, "max": { "title": "Min", "description": "Error message for error 'max'.", "type": "string" }, "minLength": { "title": "Min Length", "description": "Error message for error 'minLength'.", "type": "string" }, "maxLength": { "title": "Max Length", "description": "Error message for error 'maxLength'.", "type": "string" }, "invalid_email": { "title": "Invalid Email", "description": "Error message for error 'invalid_email'.", "type": "string" }, "invalid_date": { "title": "Invalid Date", "description": "Error message for error 'invalid_date'.", "type": "string" }, "pattern": { "title": "Pattern", "description": "Error message for error 'pattern'.", "type": "string" }, "custom": { "title": "Custom", "description": "Error message for error 'custom'.", "type": ["string", "object"] } } }, "logic": { "title": "Logic", "description": "Allows changing the component definition in reaction to data entered in a form. For example, changing a field to required, disabled or hidden when a value is entered.", "type": "array", "items": { "$ref": "logic" } } }, "allOf": [ { "if": { "properties": { "type": { "const": "columns" } } }, "then": { "$ref": "columns" } }, { "if": { "properties": { "type": { "const": "table" } } }, "then": { "$ref": "table" } }, { "if": { "properties": { "type": { "const": "tabs" } } }, "then": { "$ref": "tabs" }, "else": { "properties": { "components": { "$ref": "components" } } } } ] }; var componentLoose = Object.assign({}, componentStrict, { required: ['type'] }); // tslint:disable:object-literal-key-quotes quotemark semicolon var logic = { "title": "Logic", "description": "...", "type": "object", "required": ["trigger", "actions"], "properties": { "trigger": { "$ref": "trigger" }, "actions": { "title": "Actions", "description": "The actions to perform when the logic is triggered", "type": "array", "items": { "$ref": "action" } } } }; // tslint:disable:object-literal-key-quotes quotemark semicolon var trigger = { "title": "Trigger", "description": "Determines when the logic should be triggered", "type": "object", "required": ["type"], "properties": { "type": { "title": "Type", "description": "The type of the trigger.", "enum": ["simple", "javascript", "json", "event"] } }, "allOf": [ { "if": { "properties": { "type": { "const": "simple" } } }, "then": { "required": ["simple"], "properties": { "simple": { "title": "Simple", "description": "Defines a simple trigger.", "required": ["when", "eq", "show"], "type": "object", "properties": { "when": { "title": "When", "description": "The trigger field key.", "type": "string" }, "eq": { "title": "Eq", "description": "The value to equal.", "type": "string" }, "show": { "title": "Show", "description": "Whether to trigger or not when the value is equal.", "type": "boolean" } } } } } }, { "if": { "properties": { "type": { "const": "javascript" } } }, "then": { "required": ["javascript"], "properties": { "javascript": { "title": "Javascript", "description": "Javascript logic.", "type": "string" } } } }, { "if": { "properties": { "type": { "const": "json" } } }, "then": { "required": ["json"], "properties": { "json": { "title": "Json", "description": "JSON Logic object that returns true or false.", "type": "object" } } } }, { "if": { "properties": { "type": { "const": "event" } } }, "then": { "required": ["event"], "properties": { "event": { "title": "Event", "description": "The name of the event that will trigger this logic.", "type": "string" } } } } ] }; // tslint:disable:object-literal-key-quotes quotemark semicolon var action = { "title": "Action", "description": "An action to perform when the logic is triggered", "required": ["type"], "type": "object", "properties": { "type": { "title": "Type", "description": "The type of the action.", "enum": ["property", "value"] } }, "allOf": [ { "if": { "properties": { "type": { "const": "property" } } }, "then": { "properties": { "property": { "title": "Property", "description": "The property action.", "required": ["type", "value"], "type": "object", "properties": { "type": { "title": "Property", "description": "The type of the property action (either 'boolean' or 'string').", "enum": ["boolean", "string"] }, "value": { "title": "Value", "description": "The path to the property on the component definition.", "type": "string" } } } }, "allOf": [ { "if": { "properties": { "type": { "const": "boolean" } } }, "then": { "properties": { "state": { "title": "Boolean State", "description": "Used if the type of the property action is boolean.", "type": "boolean" } } } }, { "if": { "properties": { "type": { "const": "string" } } }, "then": { "properties": { "text": { "title": "String Text", "description": "Used if the type of the property action is string.", "type": "string" } } } } ] } }, { "if": { "properties": { "type": { "const": "value" } } }, "then": { "properties": { "value": { "title": "Value", "description": "The javascript that returns the new value. It Will be evaluated with available variables of row, data, component and result (returned from trigger).", "type": "string" } } } } ] }; // tslint:disable:object-literal-key-quotes quotemark semicolon var conditional = { "title": "Conditional", "description": "Determines when this component should be added to the form for both processing and input.", "type": "object", "properties": { "show": { "$ref": "show", }, "when": { "title": "When", "description": "The field API key that it should compare its value against to determine if the condition is triggered.", "type": ["string", "null"] }, "eq": { "title": "Eq", "description": "The value that should be checked against the comparison component.", "type": "string" }, "json": { "title": "Json", "description": "The JSON Logic to determine if this component is conditionally available.", "type": "string" } } }; // tslint:disable:object-literal-key-quotes quotemark semicolon var showStrict = { "title": "Show", "description": "If the field should show if the condition is true.", "type": ["boolean", "null"] }; // tslint:disable:object-literal-key-quotes quotemark semicolon var showLoose = { "title": "Show", "description": "If the field should show if the condition is true.", "enum": [true, false, "true", "false", "", null] }; // tslint:disable:object-literal-key-quotes quotemark semicolon var columns = { "required": ["columns"], "not": { "required": ["components"] }, "properties": { "columns": { "type": "array", "items": { "required": ["components"],