@tomino/dynamic-form-semantic-ui
Version:
Semantic UI form renderer based on dynamic form generation
428 lines • 17.4 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const dynamic_form_1 = require("@tomino/dynamic-form");
const mst_middlewares_1 = require("mst-middlewares");
const mobx_state_tree_1 = require("mobx-state-tree");
const editor_common_1 = require("./editor_common");
const common_schemas_1 = require("./common_schemas");
const mobx_1 = require("mobx");
const helpers_1 = require("../helpers");
let undoSet = false;
function mergeProp(schema, localTypes, sharedTypes) {
let item = { ...schema };
if (item.properties) {
item.properties = mergeProperties(item, localTypes, sharedTypes);
}
if (item.$import) {
item.reference = sharedTypes.find(t => t.id === item.$import).id;
}
if (item.$ref) {
item.reference = item.$ref.split('/')[2];
}
return item;
}
function mergeProperties(schema, localTypes, sharedTypes) {
let keys = Object.getOwnPropertyNames(schema.properties);
let newProperties = {};
for (let key of keys) {
let prop = mergeProp(schema.properties[key], localTypes, sharedTypes);
newProperties[key] = mergeSchema(prop, localTypes, sharedTypes);
}
return newProperties;
}
function mergeSchema(schema, localTypes, sharedTypes) {
let newSchema = { ...schema };
if (schema.properties) {
newSchema.properties = mergeProperties(schema, localTypes, sharedTypes);
}
if (schema.items) {
newSchema.items = mergeProp(newSchema.items, localTypes, sharedTypes);
}
return newSchema;
}
function searchJsonSchema(func, schema) {
let queue = [schema];
while (queue.length) {
let current = queue.pop();
if (!current.properties) {
continue;
}
for (let key of Object.getOwnPropertyNames(current.properties)) {
let property = current.properties[key];
if (property.properties) {
queue.push(property);
}
let result = func(property);
if (result) {
return result;
}
}
}
}
exports.searchJsonSchema = searchJsonSchema;
function searchSchema(schema, func) {
let queue = [schema];
while (queue.length) {
let current = queue.pop();
if (!current.properties) {
continue;
}
for (let key of Array.from(current.properties.keys())) {
let property = current.properties.get(key);
if (property.properties) {
queue.push(property);
}
let result = func(property);
if (result) {
return result;
}
}
}
}
exports.searchSchema = searchSchema;
function searchForm(form, func) {
let queue = [form];
while (queue.length) {
let current = queue.pop();
for (let element of current.elements) {
if (element.elements) {
queue.push(element);
}
let result = func(element);
if (result) {
return result;
}
}
}
}
exports.searchForm = searchForm;
function assignArrayIds(schema, schemas) {
let s = schema;
s.imports = {};
searchJsonSchema(property => {
if (property.$import) {
let item = schemas.find(s => s.id === property.$import);
s.imports[item.id] = item.schema;
}
}, schema);
}
function assignSource(props) {
Object.getOwnPropertyNames(props).forEach(key => {
props[key].control.props = {
[props[key].schema.type === 'boolean' ? 'value' : 'value']: { source: key },
...props[key].control.props
};
});
}
function buildProps(props, extraProps = {}) {
assignSource(props);
let schema = new dynamic_form_1.Schema({
type: 'object',
properties: { ...buildPropSchema(props), ...extraProps }
});
return dynamic_form_1.buildStore(schema, {}, false);
}
function buildPropSchema(props) {
let result = {};
for (let key of Object.getOwnPropertyNames(props)) {
result[key] = props[key].schema;
}
return result;
}
function prepareStores(context) {
let id = 0;
let date = Date.now();
function generateId() {
if (process.env.NODE_ENV === 'test') {
return (id++).toString();
}
return (date + id++).toString();
}
let objectMap = {};
const mapModifiers = (self) => ({
afterCreate() {
objectMap[self.uid] = self;
},
beforeDestroy() {
delete objectMap[self.uid];
}
});
const referenceHandlers = {
get(identifier) {
return objectMap[identifier] || null;
},
set(value) {
return value.uid;
}
};
const props = {};
const propNames = {};
let childProps = {
properties: {
control: { type: 'string' },
label: common_schemas_1.boundSchema(),
css: common_schemas_1.boundSchema(),
className: common_schemas_1.boundSchema(),
hidden: common_schemas_1.boundSchema(),
editorLabel: { type: 'string' },
locked: { type: 'boolean' }
}
};
let childPropStore = dynamic_form_1.buildStore(new dynamic_form_1.Schema({ type: 'object', properties: {} }), {}, false);
if (context.editorCatalogue) {
for (let key of Object.getOwnPropertyNames(context.editorCatalogue.components)) {
let c = context.editorCatalogue.components[key];
if (c.childProps) {
assignSource(c.childProps);
childProps = { properties: { ...childProps.properties, ...buildPropSchema(c.childProps) } };
}
}
childPropStore = dynamic_form_1.buildStore(new dynamic_form_1.Schema({ type: 'object', properties: childProps.properties }), {}, false);
for (let key of Object.getOwnPropertyNames(context.editorCatalogue.components)) {
let c = context.editorCatalogue.components[key];
if (c.props) {
props[key] = buildProps(c.props, childProps.properties);
propNames[key] = Object.keys(c.props).concat(Object.keys(childProps.properties));
}
}
}
const elementStore = dynamic_form_1.buildStore(common_schemas_1.elementSchema, {}, false)
.props({
uid: mobx_state_tree_1.types.optional(mobx_state_tree_1.types.string, generateId),
props: mobx_state_tree_1.types.optional(mobx_state_tree_1.types.union({
dispatcher: snapshot => {
if (!snapshot || !snapshot.control) {
return childPropStore;
}
return props[snapshot.control] || childPropStore;
}
}), {}),
elements: mobx_state_tree_1.types.optional(mobx_state_tree_1.types.array(mobx_state_tree_1.types.maybe(mobx_state_tree_1.types.union(mobx_state_tree_1.types.late(() => elementStore), mobx_state_tree_1.types.null))), []),
pages: mobx_state_tree_1.types.optional(mobx_state_tree_1.types.array(mobx_state_tree_1.types.maybe(mobx_state_tree_1.types.union(mobx_state_tree_1.types.late(() => elementStore), mobx_state_tree_1.types.null))), []),
isSelected: mobx_state_tree_1.types.optional(mobx_state_tree_1.types.boolean, false)
})
.actions(mapModifiers)
.actions(() => ({
moveElement(from, to, index) {
from.parent.detach(from);
if (index != null && index >= 0) {
to.insertRow('elements', index, mobx_1.toJS(from));
}
else {
to.addRow('elements', mobx_1.toJS(from));
}
}
}));
const schemaStore = dynamic_form_1.buildStore(common_schemas_1.schemaSchema, {}, false)
.actions(mapModifiers)
.props({
uid: mobx_state_tree_1.types.optional(mobx_state_tree_1.types.string, generateId),
properties: mobx_state_tree_1.types.maybe(mobx_state_tree_1.types.map(mobx_state_tree_1.types.late(() => schemaStore))),
items: mobx_state_tree_1.types.maybe(mobx_state_tree_1.types.late(() => schemaStore)),
reference: mobx_state_tree_1.types.maybe(mobx_state_tree_1.types.reference(mobx_state_tree_1.types.late(() => schemaStore), {
get(identifier, parent) {
let root = parent.root().schema;
if (!root) {
return {};
}
let key = Array.from(root.definitions.keys()).find(f => f === identifier);
if (key) {
return root.definitions.get(key);
}
key = Array.from(root.imports.keys()).find(f => f === identifier);
if (key) {
return root.imports.get(key);
}
throw new Error('Could not find reference to: ' + identifier);
},
set(value) {
let root = value.root().schema;
if (!root) {
return '';
}
let key = Array.from(root.definitions.keys()).find(f => root.definitions.get(f) === value);
if (key) {
return key;
}
key = Array.from(root.imports.keys()).find(f => root.imports.get(f) === value);
if (key) {
return key;
}
throw new Error('WTF');
}
})),
definitions: mobx_state_tree_1.types.optional(mobx_state_tree_1.types.map(mobx_state_tree_1.types.late(() => schemaStore)), {}),
imports: mobx_state_tree_1.types.optional(mobx_state_tree_1.types.map(mobx_state_tree_1.types.late(() => schemaStore)), {}),
anyOf: mobx_state_tree_1.types.optional(mobx_state_tree_1.types.array(mobx_state_tree_1.types.late(() => schemaStore)), []),
allOf: mobx_state_tree_1.types.optional(mobx_state_tree_1.types.array(mobx_state_tree_1.types.late(() => schemaStore)), []),
oneOf: mobx_state_tree_1.types.optional(mobx_state_tree_1.types.array(mobx_state_tree_1.types.late(() => schemaStore)), []),
errorMessage: mobx_state_tree_1.types.maybe(mobx_state_tree_1.types.union(mobx_state_tree_1.types.string, mobx_state_tree_1.types.map(mobx_state_tree_1.types.union(mobx_state_tree_1.types.string, mobx_state_tree_1.types.map(mobx_state_tree_1.types.string)))))
})
.volatile(self => ({
name() {
let parent = self.parent;
let key = Array.from(parent.properties.keys()).find(k => parent.properties.get(k) === self);
if (key) {
return key;
}
return 'unknownArgMessage';
}
}))
.actions(self => ({
changeType: (value, prev) => {
const owner = self;
owner.setValue('$ref', null);
owner.setValue('$import', null);
owner.setValue('reference', undefined);
owner.setValue('type', value);
if (['string', 'number', 'integer', 'boolean'].indexOf(value) >= 0) {
owner.setValue('properties', undefined);
owner.setValue('items', undefined);
return;
}
if (value === 'array' && prev !== 'array') {
owner.setValue('items', { type: 'object', properties: {} });
return;
}
if (value === 'object') {
if (!owner.getValue('properties')) {
owner.setValue('properties', {});
}
return;
}
let elementRoot = editor_common_1.root(owner);
let localTypes = Array.from(elementRoot.definitions.keys());
if (localTypes.indexOf(value) >= 0) {
owner.setValue('reference', value);
owner.setValue('$ref', `#/definitions/${value}`);
owner.setValue('type', 'object');
return;
}
let imports = Array.from(elementRoot.imports.keys());
if (imports.indexOf(value) >= 0) {
owner.setValue('reference', value);
owner.setValue('$import', value);
owner.setValue('type', 'object');
return;
}
}
}));
const stateStore = mobx_state_tree_1.types
.model({
selectedForm: mobx_state_tree_1.types.maybe(mobx_state_tree_1.types.reference(elementStore, referenceHandlers)),
selectedSchema: mobx_state_tree_1.types.maybe(mobx_state_tree_1.types.reference(schemaStore, referenceHandlers)),
selectedSchemaName: mobx_state_tree_1.types.maybe(mobx_state_tree_1.types.string),
selectedElement: mobx_state_tree_1.types.maybe(mobx_state_tree_1.types.reference(elementStore, referenceHandlers)),
selectedLeftPane: mobx_state_tree_1.types.optional(mobx_state_tree_1.types.string, localStorage.getItem('CORPIX_LEFT') || 'pages')
})
.actions(self => ({
setForm(element) {
self.selectedSchema = undefined;
self.selectedElement = element;
self.selectedForm = element;
},
setSchema(schema, name = '') {
self.selectedSchema = schema;
self.selectedSchemaName = name;
self.selectedElement = undefined;
},
setElement(element, schema) {
self.selectedSchema = undefined;
if (self.selectedElement) {
self.selectedElement.setValue('isSelected', false);
}
self.selectedElement = element;
self.selectedElement.setValue('isSelected', true);
context.selectedParentSchema = editor_common_1.findParentSchema(element, schema, context);
},
changeLeftPane(view) {
localStorage.setItem('CORPIX_LEFT', view);
self.selectedLeftPane = view;
}
}))
.actions(self => ({
deleteActiveSchema() {
self.selectedSchema.parent.detach(self.selectedSchema);
self.setSchema(undefined, undefined);
},
deleteActiveElement() {
self.selectedElement.parent.detach(self.selectedElement);
self.selectedElement = undefined;
}
}));
const projectStore = mobx_state_tree_1.types
.model({
form: elementStore,
schema: schemaStore,
state: stateStore,
history: mobx_state_tree_1.types.optional(mst_middlewares_1.UndoManager, {})
})
.actions(self => ({
renameSchema: (name, rootSchema) => {
let selected = self.state.selectedSchema;
let owner = selected.reference ? selected.reference : selected;
let parent = owner.parent;
let sourcePath = context.selectedSourcePath;
let titleOnly = !sourcePath || (parent.definitions.has(sourcePath) && rootSchema === parent);
let current = self.state.selectedSchema;
if (titleOnly) {
current.setValue('title', name);
return;
}
if (parent.properties.has(name)) {
current.setError('title', 'Element with this name already exists!');
return;
}
let newSourcePathParts = sourcePath.split('.');
newSourcePathParts.pop();
let newSourcePath = newSourcePathParts.concat(name).join('.');
context.selectedSourcePath = newSourcePath;
searchForm(self.form, item => {
for (let prop of propNames[item.control]) {
let p = item.props[prop];
if (p && p.source && p.source.indexOf(sourcePath) >= 0) {
p.setValue('source', p.source.replace(sourcePath, newSourcePath));
}
}
});
const data = helpers_1.schemaDatasetToJS(current);
parent.properties.set(name, data);
let newValue = parent.properties.get(name);
newValue.setValue('title', name);
self.state.setSchema(newValue, name);
parent.detach(current);
context.recomputeDataBounce();
}
}));
return function buildFormEditorDataset(form, schema) {
assignArrayIds(schema, context.types);
if (schema) {
schema = mergeSchema(schema, schema.definitions, context.types);
}
else {
schema = {};
}
let s = projectStore.create({ form, schema, state: {} });
if (form) {
const currentForm = localStorage.getItem('CORPIX_SELECTED_FORM');
if (currentForm && s.form.pages.some(p => p.uid === currentForm)) {
s.state.setForm(s.form.pages.find(p => p.uid === currentForm));
}
else {
s.state.setForm(s.form);
}
}
context.form = s.form;
context.schema = s.schema;
context.project = s;
context.state = s.state;
if (!undoSet) {
dynamic_form_1.setUndoManager(s);
global.__state = s;
undoSet = true;
}
return s;
};
}
exports.prepareStores = prepareStores;
//# sourceMappingURL=form_store.js.map