UNPKG

pragma-views2

Version:

580 lines (461 loc) 17.9 kB
import {TemplateParser} from "../../lib/template-parser.js"; import {findParentWithClass} from "./../../lib/dom-helper.js"; import {performViewElementValidation} from "./../../lib/view-helper.js"; import {ActionDialogManager} from "./../../lib/action-dialog-manager.js"; import {DatasetFactory} from "./../../lib/dataset-factory.js"; import {SchemaHelper} from "./../../lib/schema-helper.js"; import {createBehavioursFromString, releaseElements} from "./../../../../baremetal/lib/binding/binding-helpers.js"; import {addExpressionTriggers, observe, addTriggers} from "./../../../../baremetal/lib/binding/observers.js"; import {ViewBinding} from "./../../../../baremetal/lib/binding/view-binding.js" import {addEventsFeatures, removeEventsFeatures} from "./../../../../baremetal/lib/mixin-events.js"; import {executeFunctionOnPath, setValueOnPath, deleteValueOnPath} from "./../../../../baremetal/lib/objectpath-helper.js"; import {isMobile} from "./../../lib/device-helper.js"; class PragmaForm extends HTMLElement { get isMobile() { return isMobile(); } get context() { return this._context; } set context(newValue) { this._context = newValue; } get model() { return this._model; } set model(newValue) { this._model = newValue; } get remote() { return this._remote; } set remote(newValue) { this._remote = newValue; } get schema() { return this._schema; }; set schema(newValue) { this._schema = newValue; if (newValue != null && newValue._isVisible != true) { this.refreshFromSchema(); } } get selectedId() { return this._selectedId; } set selectedId(newValue) { this._selectedId = newValue; } get templateId() { return this._templateId; } set templateId(newValue) { this._templateId = newValue; } get templates() { return this._templates; } set templates(newValue) { this._templates = newValue; } get type() { return this._type; } set type(newValue) { this._type = newValue; } clear() { this.detailsElement.innerHTML = ""; } connectedCallback() { addEventsFeatures(this); this.initTemplate(); this.binding = new ViewBinding(this); this.templates = new Map(); this.templateParser = new TemplateParser(); this.detailsElement = this.querySelector(".form-container"); if (this.remote != undefined) { window.eventEmitter.emit("fetch-schema", { remote: this.remote, type: this.type || "view", callback: (schema) => this.schema = schema }); } if (this.schema != undefined) { this.refreshFromSchema(); } if (this.remote != undefined && this.type != undefined) { this.remoteChanged(this.remote); } this.registerEvent(this, "focusin", this.focus.bind(this)); this.registerEvent(this, "focusout", this.focusOut.bind(this)); this.validateElementHandler = this.validateElement.bind(this); window.eventEmitter.on("validate-element", this.validateElementHandler); this.schemaHelper = new SchemaHelper(this.schema, this.model); } disconnectedCallback() { removeEventsFeatures(this); window.eventEmitter.emit("clear-assistant"); window.eventEmitter.remove("validate-element", this.validateElementHandler); this.disposeFileInput(); this.disposeProcessManager(); this.disposeVariables(this.schema); } disposeFileInput() { if (this.fileInput) { this.fileInput.removeEventListener("change", this.changeHandler); this.fileInput = null; this.changeHandler = null; } } disposeProcessManager() { if (this.processManager == undefined) { return; } this.processManager.dispose(); this.processManager = null; } disposeVariables(schema) { if (schema == undefined) { return; } if (schema.variables != undefined && schema.variables.models != undefined) { const keys = Object.keys(schema.variables.models); for (let key of keys) { if (Number.isInteger(schema.variables.models[key]) == false) { schema.variables.models[key].dispose(); schema.variables.models[key] = null; } } } schema.variables = null; } fetchSchema(remote, type) { if (this.remote != undefined && this.type != undefined) { window.eventEmitter.emit("fetch-schema", { remote: remote, type: this.type || "view", callback: (schema) => this.schema = schema }); } } focus(event) { const card = findParentWithClass(event.target, "card"); if (card != null) { card.setAttribute("aria-selected", true); event.target.card = card; } } focusFirstInput() { const input = this.querySelector("input"); if (input) input.focus(); } focusOut(event) { if (event.target.card != undefined) { event.target.card.setAttribute("aria-selected", false); event.target.card = null; } } /** * Models are created externally and does not have context information, but we still want to give them context awareness without over exposing them. * To allow you to define property defaults on the model, we inflate the values as soon as it becomes part of the form because the form understands context. * @param model */ inflateModelDefaults(model) { if (model == undefined || model.__definition == undefined) { return; } for (let field of model.__definition.fields) { if (field.default != undefined) { const defaultValue = this.schemaHelper.getAssociatedValue(field.default); field.initialValue = defaultValue; model.__defaults.set(field.name, defaultValue); model[field.name] = defaultValue; } } } inflateParameters(parameters) { const keys = Object.keys(parameters); for (let key of keys) { let result = this.schemaHelper.getAssociatedValue(parameters[key]); if (key == "model") { result = this.inflateParameters(result); } parameters[key] = result; } return parameters; } initTemplate() { const instance = document.importNode(window.templates.get("pragma-form"), true); this.appendChild(instance); } loadContentFromFile(event) { const file = event.target.files[0]; const fr = new FileReader(); fr.onload = _ => { this.schema = JSON.parse(fr.result); this.disposeFileInput(); }; fr.readAsText(file); } async loadDatasetVariable(name) { if (this.schema.variables == undefined || this.schema.variables.models == undefined) { return; } const dsValue = this.schema.variables.models[name]; if (Number.isInteger(dsValue)) { const factory = new DatasetFactory({schema: this.schema}); const ds = factory.createDataSet(dsValue); ds.setInitialValues({}); this.schema.variables.models[name] = ds; factory.dispose(); this.inflateModelDefaults(ds); } else { dsValue.resetToDefault(); } } loadHtml(html) { const container = this.querySelector(".form-container"); container.innerHTML = html; this.binding.parse(this, this.children); window.eventEmitter.emit("form-updated", this); } loadTemplates() { this.templates.clear(); if (this.schema.templates != undefined) { this.templateParser.initializeResources(this.schema); for (let template of this.schema.templates) { const html = this.templateParser.parseElements(template.elements); this.templates.set(template.id, html); } } } modelChanged(newValue) { if (this.schemaHelper != undefined) { this.schemaHelper.model = newValue; } } nextProcessStep() { this.processManager.next(); } /** * NOTES: * Is there a current process running? * If there is and the action is UI related then show it in the process UI. * If not, and it is UI related then you need to show a dialog with the UI. * @param id */ async performAction(id) { if (Array.isArray(id)) { for (let i of id) { await this.performAction(i); } return; } if (id != undefined) { const action = this.schema.actions.find(item => item.id == id); let result; if (action.remote != undefined) { result = await this.performRemoteAction(action); } else if (this[action.action] != undefined) { if (action.parameters != undefined) { action.parameters = this.inflateParameters(action.parameters); } result = await this[action.action].call(this, action.parameters); } else if (action.action.indexOf(".") != -1) { result = await executeFunctionOnPath(this, action.action, action.parameters); } if (action.variable != undefined) { if (typeof result == "object") { for (let key of Object.keys(result)) { setValueOnPath(this.schema, `schema.variables.${action.variable}.${key}`, result[key]); } } else { setValueOnPath(this.schema, `schema.variables.${action.variable}`, result); } } } } async performContextAction(action) { const a = Object.create(action); if (a.parameters != undefined) { a.parameters = this.inflateParameters(a.parameters); } return await this.context.performAction(a); } async performProcess(id) { const process = this.schema.processes.find(item => item.id == id); this.showProcess(process.actions); } async performRemoteAction(action) { if (this.context.performAction != undefined) { if (action.template == undefined) { return await this.performContextAction(action) } else { if (action.model != undefined) { this.loadDatasetVariable(action.model); } const html = this.templateParser.parseTemplate({template: action.template}); const div = document.createElement("div"); // JHR: todo: replace //this.viewSource = this.dynamicViewLoader.load(html, div, this); const dialog = new ActionDialogManager(div, async (successfull) => { if (successfull == true) { return await this.performContextAction(action); } // JHR: todo: replace //this.dynamicViewLoader.unload(div); dialog.dispose(); }); } } } perspective(id) { if (this.schema.perspectives == undefined) { return undefined; } return this.schema.perspectives.find(item => item.id == id); } async postMessage(action) { window.eventEmitter.postMessage(action.parameters.query, action.parameters); } async releaseElements() { const elements = this.querySelectorAll("[behaviours]"); return releaseElements(elements); } remoteChanged(newValue) { this.fetchSchema(newValue, this.type); } removeVariable(action) { const varName = this.schemaHelper.getAssociatedValue(action.parameters.name); deleteValueOnPath(this.schema, `schema.variables.${varName}`); } async refreshFromSchema() { this.releaseElements(); if (this.schema == null) return; this.schema._isVisible = true; if (this.schemaHelper != undefined) { this.schemaHelper.schema = this.schema; } if (this.templateParser) { this.loadTemplates(); const html = this.templateId == undefined ? await this.templateParser.parse(this.schema) : this.templateParser.parseTemplate({template: this.templateId}); this.loadHtml(html); this.setupBehaviours(); this.focusFirstInput(); this.inflateModelDefaults(this.model); this.setupCustomActionEvents(); this.setupCustomActionTriggers(); } } setValue(parameters) { const keys = Object.keys(parameters); for (let key of keys) { setValueOnPath(this, this.updateVariablePath(key), parameters[key]); } } setVariable(action) { const varName = this.schemaHelper.getAssociatedValue(action.parameters.name); const varValue = this.schemaHelper.getAssociatedValue(action.parameters.value); setValueOnPath(this.schema, `variables.${varName}`, varValue); } setupBehaviours() { const elements = this.querySelectorAll("[behaviours]"); const collection = Array.from(elements); for(let element of collection) { createBehavioursFromString(element.getAttribute("behaviours"), element); }; } updateVariablePath(path) { if (path.indexOf("@") == -1) { return path; } return path.split("@").join("schema.variables."); } setupCustomActionTriggers() { if (this.schema.customActionTriggers == undefined) return; if (Array.isArray(this.schema.customActionTriggers) == false) return; for (let customTrigger of this.schema.customActionTriggers) { this.setupCustomActionTrigger(customTrigger); } } setupCustomActionTrigger(customTrigger) { let expression = customTrigger.trigger; if (expression.indexOf("@") != -1) { expression = this.updateVariablePath(expression); } addTriggers(this, expression, () => this.performTriggeredActions(customTrigger)); } setupCustomActionEvents() { if (this.schema.customActionEvents == undefined) return; if (Array.isArray(this.schema.customActionEvents) == false) return; for (let customEvent of this.schema.customActionEvents) { this.setupCustomActionEvent(customEvent); } } setupCustomActionEvent(customEvent) { let expression = customEvent.event; if (expression.indexOf("@") != -1) { expression = this.updateVariablePath(expression); } addExpressionTriggers(this, expression, () => this.performTriggeredActions(customEvent)); } performTriggeredActions(customAction) { for (let action of customAction.actions) { if (action.condition != undefined) { const cnd = window.compiler.add(action.condition); const result = cnd(this); if (result != true) { continue; } } const parameters = this.inflateParameters(action.parameters); if (action.action == "setValue") { this.setValue(parameters); } else if (action.action = "setValidation") { this.setValidation(parameters); } } } async showDialog(action) { const dialog = new ActionDialogManager(action, this, () => { console.log("perform action requested"); dialog.dispose(); }); } async showProcess(actions) { for (let actionId of actions) { await this.performAction(actionId); } } showSchemaTemplate(templateId) { if (this.templates.has(templateId)) { const html = this.templates.get(templateId); this.clear(); this.loadHtml(html); } } template(id) { if (this.schema.templates == undefined) { return undefined; } return this.schema.templates.find(item => item.id == id); } typeChanged(newValue) { this.fetchSchema(this.remote, newValue); } validateElement(element) { performViewElementValidation(this.viewSource.view, element); } } customElements.define('pragma-form', PragmaForm);