From e2da1506a7ec47fc177c71ffce22d0348a3242f0 Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Sun, 24 May 2020 19:18:13 +0200 Subject: [PATCH] improve update and add functionality --- Message/Notification/NotificationManager.js | 6 +- Message/Request/Request.js | 10 +- UI/Component/Form.js | 502 ++++++++++++-------- UI/Component/Tab.js | 2 +- UI/GeneralUI.js | 2 +- UI/Input/InputManager.js | 4 +- UI/UIManager.js | 10 +- Uri/UriFactory.js | 2 +- 8 files changed, 333 insertions(+), 205 deletions(-) diff --git a/Message/Notification/NotificationManager.js b/Message/Notification/NotificationManager.js index bf4a3fb..a071854 100644 --- a/Message/Notification/NotificationManager.js +++ b/Message/Notification/NotificationManager.js @@ -1,6 +1,6 @@ -import { AppNotification } from '../../../jsOMS/Message/Notification/App/AppNotification.js'; -import { BrowserNotification } from '../../../jsOMS/Message/Notification/Browser/BrowserNotification.js'; -import { NotificationType } from '../../../jsOMS/Message/Notification/NotificationType.js'; +import { AppNotification } from '../../Message/Notification/App/AppNotification.js'; +import { BrowserNotification } from '../../Message/Notification/Browser/BrowserNotification.js'; +import { NotificationType } from '../../Message/Notification/NotificationType.js'; /** * Notification manager. diff --git a/Message/Request/Request.js b/Message/Request/Request.js index e211d57..0247696 100644 --- a/Message/Request/Request.js +++ b/Message/Request/Request.js @@ -1,9 +1,9 @@ -import { Logger } from '../../Log/Logger.js'; -import { UriFactory } from '../../Uri/UriFactory.js'; -import { BrowserType } from './BrowserType.js'; -import { OSType } from './OSType.js'; +import { Logger } from '../../Log/Logger.js'; +import { UriFactory } from '../../Uri/UriFactory.js'; +import { BrowserType } from './BrowserType.js'; +import { OSType } from './OSType.js'; import { RequestMethod } from './RequestMethod.js'; -import { RequestType } from './RequestType.js'; +import { RequestType } from './RequestType.js'; /** * Request class. diff --git a/UI/Component/Form.js b/UI/Component/Form.js index aad6815..345ab7e 100644 --- a/UI/Component/Form.js +++ b/UI/Component/Form.js @@ -1,12 +1,13 @@ -import { Logger } from '../../Log/Logger.js'; -import { NotificationLevel } from '../../Message/Notification/NotificationLevel.js'; +import { Logger } from '../../Log/Logger.js'; +import { NotificationLevel } from '../../Message/Notification/NotificationLevel.js'; import { NotificationMessage } from '../../Message/Notification/NotificationMessage.js'; -import { NotificationType } from '../../Message/Notification/NotificationType.js'; -import { Request } from '../../Message/Request/Request.js'; -import { RequestMethod } from '../../Message/Request/RequestMethod.js'; -import { RequestType } from '../../Message/Request/RequestType.js'; -import { Response } from '../../Message/Response/Response.js'; -import { FormView } from '../../Views/FormView.js'; +import { NotificationType } from '../../Message/Notification/NotificationType.js'; +import { Request } from '../../Message/Request/Request.js'; +import { RequestMethod } from '../../Message/Request/RequestMethod.js'; +import { RequestType } from '../../Message/Request/RequestType.js'; +import { Response } from '../../Message/Response/Response.js'; +import { FormView } from '../../Views/FormView.js'; +import { UriFactory } from '../../Uri/UriFactory.js'; /** * Form manager class. @@ -160,7 +161,7 @@ export class Form const addable = this.forms[id].getAdd(); length = addable === null ? 0 : addable.length; for (let i = 0; i < length; ++i) { - this.bindAddInline(addable[i], id); + this.bindAdd(addable[i], id); } const save = this.forms[id].getSave(); @@ -171,10 +172,6 @@ export class Form // @todo implement bindSaveExternal ??? - if (document.getElementById(id).getAttribute('data-ui-form') !== null) { - this.bindAddExternal(id); - } - const cancel = this.forms[id].getCancel(); length = cancel === null ? 0 : cancel.length; for (let i = 0; i < length; ++i) { @@ -403,115 +400,231 @@ export class Form /** * Create the ui element * - * @param {string} createForm Create form - * @param {Object} id Form id + * @param {string} create Create form button + * @param {Object} id Id * * @return {void} * * @since 1.0.0 */ - bindAddExternal(id) + bindAddExternal(create, id) { - const createForm = document.getElementById(id).getAttribute('data-ui-form'); + const self = this; /** * @todo Orange-Management/jsOMS#75 * Currently only one add button is allowed per form. Allow multiple/different add buttons in a form. */ - this.app.uiManager.getFormManager().get(createForm).injectSubmit(function () { - const formElement = document.getElementById(id); - const subMain = formElement.getAttribute('data-ui-content').charAt(0) === '#' - ? document.querySelector(formElement.getAttribute('data-ui-content')) - : formElement.querySelector(formElement.getAttribute('data-ui-content')); + create.addEventListener('click', function () { + const formElement = document.getElementById(id); + const parents = []; + const selectors = formElement.getAttribute('data-add-element').split(','), + selectorLength = selectors.length; + const addTpl = formElement.getAttribute('data-add-tpl').split(','); - /** - * @todo Orange-Management/jsOMS#76 - * In the beginning there was a fixed amount of templates required (even if some were not used) for adding new dom elements to a lest, table etc. - * This no longer works especially for inline editing - * ```js - * const newEle = subMain.getElementsByTagName('template')[0].content.cloneNode(true); - * ``` - */ - const newEle = subMain.getElementsByTagName('template')[0].content.cloneNode(true); + const subMain = formElement.getAttribute('data-add-content').charAt(0) === '#' + ? document.querySelector(formElement.getAttribute('data-add-content')) + : formElement.querySelector(formElement.getAttribute('data-add-content')); - // set internal value - let fields = newEle.querySelectorAll('[data-tpl-value]'); - let fieldLength = fields.length; - let uuid = ''; - let value = ''; + let values = []; + let text = []; + const newEle = []; - for (let j = 0; j < fieldLength; ++j) { - /** - * @todo Orange-Management/jsOMS#77 - * We need to check what kind of tag the selector above returns in order to get the correct value. - * Currently this only makes sense for input elements but for selection, checkboxes etc. - * This doesn't make sense there we need .innerHTML or [data-text=] - */ - value = document.querySelectorAll( - '#' + createForm + ' [data-tpl-value="' + fields[j].getAttribute('data-tpl-value') + '"], [data-form="' + createForm + '"][data-tpl-value="' + fields[j].getAttribute('data-tpl-value') + '"]' - )[0].getAttribute('data-value'); + for (let i = 0; i < selectorLength; ++i) { + // this handles selectors such as 'ancestor > child/or/sibling' and many more + const selector = selectors[i].trim(' ').split(' '); + const closest = selector[0].trim(); - fields[j].setAttribute('data-value', value); + let subSelector = ''; + if (selector.length !== 0) { + selector.shift(); + subSelector = selector.join(' ').trim(); + } - uuid += value; - } + newEle.push(document.querySelector(addTpl[i]).content.cloneNode(true)); - // don't allow duplicate - if (subMain.querySelectorAll('[data-tpl-uuid="' + uuid + '"').length !== 0) { - return; - } - - newEle.firstElementChild.setAttribute('data-tpl-uuid', uuid); - - // set readable text - fields = newEle.querySelectorAll('[data-tpl-text]'); - fieldLength = fields.length; - - for (let j = 0; j < fieldLength; ++j) { - /** - * @todo Orange-Management/jsOMS#77 - * We need to check what kind of tag the selector above returns in order to get the correct value. - * Currently this only makes sense for input elements but for selection, checkboxes etc. - * This doesn't make sense there we need .innerHTML or [data-text=] - */ - fields[j].appendChild( - document.createTextNode( - document.querySelectorAll( - '#' + createForm + ' [data-tpl-text="' + fields[j].getAttribute('data-tpl-text') + '"], [data-form="' + createForm + '"][data-tpl-text="' + fields[j].getAttribute('data-tpl-text') + '"]' - )[0].value - ) + parents.push( + selector.length === 0 + ? newEle[i].firstElementChild + : newEle[i].firstElementChild.querySelector(subSelector) ); + + values = values.concat( + parents[i].hasAttribute('data-tpl-value') + ? parents[i] + : Array.prototype.slice.call(parents[i].querySelectorAll('[data-tpl-value]')) + ); + text = text.concat( + parents[i].hasAttribute('data-tpl-text') + ? parents[i] + : Array.prototype.slice.call(parents[i].querySelectorAll('[data-tpl-text]')) + ); + + if (newEle[i].firstElementChild.id === null) { + let eleId = ''; + + do { + eleId = 'f' + Math.random().toString(36).substring(7); + } while (document.getElementById(eleId) !== null); + + // root element is form even if it has a different tag than
also can be a form! + newEle[i].firstElementChild.id = eleId; + } } - subMain.appendChild(newEle); + const remoteUrls = {}; + const changedValueNodes = []; // prevent same node touching + length = values.length; + for (let i = 0; i < length; ++i) { + const path = values[i].hasAttribute('data-tpl-value-path') ? values[i].getAttribute('data-tpl-value-path') : null; - /** - * @todo Orange-Management/jsOMS#80 - * Consider to do UI action as success inject after a backend response. - * This will prevent bugs where the backand couldn't complete a action but the user sees it in the frontend. - * This should be probably optional optional because sometimes there will be no calls to the backend. - * - * @todo Orange-Management/jsOMS#78 - * After adding a new element some require a binding for removal - * - * @todo Orange-Management/jsOMS#79 - * After adding a new element some require a binding for editing - * - * @todo Orange-Management/jsOMS#81 - * A template can contain elements which must/should have an id (e.g. a form). - * If this element gets added to the DOM the id should be changed to a unique id because it could be added multiple times to the DOM. - * In order to bind these elements (e.g. forms) they must have a unique id. - * Maybe check all elements for ids and add a random part e.g. `-random_string` - */ + for (let j = 0; j < selectorLength; ++j) { + const matches = newEle[j].firstElementChild.hasAttribute('data-tpl-value') + && newEle[j].firstElementChild.getAttribute('data-tpl-value') === values[i].getAttribute('data-tpl-value') + ? [newEle[j].firstElementChild] + : newEle[j].firstElementChild.querySelectorAll( + '[data-tpl-value="' + values[i].getAttribute('data-tpl-value') + '"' + ); - return true; + const matchLength = matches.length; + for (let c = 0; c < matchLength; ++c) { + if (changedValueNodes.includes(matches[c]) + || (path !== null && path !== matches[c].getAttribute('data-tpl-value-path')) // ensure correct element. if this doesn't exist the matches from above contains alle elements with the same uri/path but eventually different tpl-paths @todo maybe fix it by improving the loop nesting or instead of storing the uri in the remoteUrls store the path? and then just check the path? + ) { + continue; + } + + changedValueNodes.push(matches[c]); + + if (values[i].getAttribute('data-tpl-value').startsWith('http') + || values[i].getAttribute('data-tpl-value').startsWith('{') + ) { + const uri = values[i].getAttribute('data-tpl-value').startsWith('/') + ? document.getElementsByTagName('base')[0].href + : ''; + + if (remoteUrls[uri + values[i].getAttribute('data-tpl-value')] === undefined) { + remoteUrls[uri + values[i].getAttribute('data-tpl-value')] = []; + } + + remoteUrls[uri + values[i].getAttribute('data-tpl-value')].push({ + path: path, + element: matches[c], + type: 'value' + }); + } else { + self.setValueOfElement(matches[c], self.getValueFromDataSource(values[i])); + } + } + } + } + + // insert row text data into form + const changedTextNodes = []; + length = text.length; + for (let i = 0; i < length; ++i) { + const path = text[i].hasAttribute('data-tpl-text-path') ? text[i].getAttribute('data-tpl-text-path') : null; + for (let j = 0; j < selectorLength; ++j) { + const matches = newEle[j].firstElementChild.hasAttribute('data-tpl-text') + && newEle[j].firstElementChild.getAttribute('data-tpl-text') === text[i].getAttribute('data-tpl-text') + ? [newEle[j].firstElementChild] + : newEle[j].firstElementChild.querySelectorAll( + '[data-tpl-text="' + text[i].getAttribute('data-tpl-text') + '"' + ); + + const matchLength = matches.length; + for (let c = 0; c < matchLength; ++c) { + if (changedTextNodes.includes(matches[c]) + || (path !== null && path !== matches[c].getAttribute('data-tpl-text-path')) // ensure correct element. if this doesn't exist the matches from above contains alle elements with the same uri/path but eventually different tpl-paths @todo maybe fix it by improving the loop nesting or instead of storing the uri in the remoteUrls store the path? and then just check the path? + ) { + continue; + } + + changedTextNodes.push(matches[c]); + + if (text[i].getAttribute('data-tpl-text').startsWith('http') + || text[i].getAttribute('data-tpl-text').startsWith('{') + ) { + const uri = text[i].getAttribute('data-tpl-text').startsWith('/') + ? document.getElementsByTagName('base')[0].href + : ''; + + if (remoteUrls[uri + text[i].getAttribute('data-tpl-text')] === undefined) { + remoteUrls[uri + text[i].getAttribute('data-tpl-text')] = []; + } + + remoteUrls[uri + text[i].getAttribute('data-tpl-text')].push({ + path: path, + element: matches[c], + type: 'text' + }); + } else { + self.setTextOfElement(matches[c], self.getTextFromDataSource(text[i])); + } + } + } + } + + console.log(remoteUrls); + + for (let i = 0; i < selectorLength; ++i) { + subMain.appendChild(newEle[i].firstElementChild); + } + + self.forms[id].setSuccess(function(response) { + if (response.get('status') !== 'undefined' && response.get('status') !== NotificationLevel.HIDDEN) { + self.app.notifyManager.send( + new NotificationMessage(response.get('status'), response.get('title'), response.get('message')), NotificationType.APP_NOTIFICATION + ); + } + + console.log(remoteUrls); + + UriFactory.setQuery('$id', response.get('response').id); + + // set values + for (const e in remoteUrls) { + const request = new Request(e); + request.setResultCallback(200, function(xhr) { + /** + * @todo Orange-Management/jsOMS#84 + * Remote data responses need to be parsed + * The data coming from the backend/api usually is not directly usable in the frontend. + * For that purpose some kind of value path should be defined to handle json responses in order to get only the data that is needed. + */ + const remoteUrlsLength = remoteUrls[e].length; + for (let k = 0; k < remoteUrlsLength; ++k) { + const path = remoteUrls[e][k].path; + + if (remoteUrls[e][k].type === 'value') { + self.setValueOfElement(remoteUrls[e][k].element, + path !== null ? jsOMS.getArray(path, JSON.parse(xhr.response)) : xhr.response + ); + } else { + self.setTextOfElement(remoteUrls[e][k].element, + path !== null ? jsOMS.getArray(path, JSON.parse(xhr.response)) : xhr.response + ); + } + } + }); + + request.send(); + } + }); + + // @todo bind update }); + + /** + * @todo Orange-Management/jsOMS#85 + * Invalid backend/api responses (!201) should undo/stop UI changes + */ }; /** * Create the new input * - * @param {string} createForm Create form + * @param {string} createForm Create form button * @param {Object} id Id * * @return {void} @@ -524,9 +637,9 @@ export class Form createForm.addEventListener('click', function () { const formElement = document.getElementById(id); - const subMain = formElement.getAttribute('data-ui-content').charAt(0) === '#' - ? document.querySelector(formElement.getAttribute('data-ui-content')) - : formElement.querySelector(formElement.getAttribute('data-ui-content')); + const subMain = formElement.getAttribute('data-add-content').charAt(0) === '#' + ? document.querySelector(formElement.getAttribute('data-add-content')) + : formElement.querySelector(formElement.getAttribute('data-add-content')); /** * @todo Orange-Management/jsOMS#76 @@ -591,6 +704,29 @@ export class Form */ }; + /** + * Bind edit button + * + * @param {string} add Add button + * @param {Object} id Id + * + * @return {void} + * + * @since 1.0.0 + */ + bindAdd(add, id) + { + /* The form is the UI element the user can edit. + * This will be added to the UI on click. + * Since the add is inline no form exists which the user can use, hence it must be created + */ + if (document.getElementById(id).getAttribute('data-add-form') !== null) { + this.bindAddInline(add, id); + } else { + this.bindAddExternal(add, id); + } + }; + /** * Bind edit button * @@ -603,7 +739,7 @@ export class Form */ bindUpdatable(update, id) { - if (document.getElementById(id).getAttribute('data-ui-form') === null) { + if (document.getElementById(id).getAttribute('data-update-form') === null) { this.bindUpdatableInline(update, id); } else { this.bindUpdatableExternal(update, id); @@ -627,12 +763,13 @@ export class Form update.addEventListener('click', function () { const formElement = document.getElementById(id); const parents = []; - const selectors = formElement.getAttribute('data-ui-element').split(','), + const selectors = formElement.getAttribute('data-update-element').split(','), selectorLength = selectors.length; + const updatableTpl = formElement.getAttribute('data-update-tpl').split(','); - const subMain = formElement.getAttribute('data-ui-content').charAt(0) === '#' - ? document.querySelector(formElement.getAttribute('data-ui-content')) - : formElement.querySelector(formElement.getAttribute('data-ui-content')); + const subMain = formElement.getAttribute('data-update-content').charAt(0) === '#' + ? document.querySelector(formElement.getAttribute('data-update-content')) + : formElement.querySelector(formElement.getAttribute('data-update-content')); let values = []; let text = []; @@ -650,7 +787,9 @@ export class Form } parents.push( - selector.length === 0 ? this.closest(closest) : this.closest(closest).querySelector(subSelector) + selector.length === 0 + ? this.closest(closest) + : this.closest(closest).querySelector(subSelector) ); values = values.concat( @@ -665,7 +804,8 @@ export class Form ); jsOMS.addClass(parents[i], 'hidden'); - newEle.push(subMain.getElementsByTagName('template')[selectorLength + i].content.cloneNode(true)); + + newEle.push(document.querySelector(updatableTpl[i]).content.cloneNode(true)); if (newEle[i].firstElementChild.id === null) { let eleId = ''; @@ -694,8 +834,8 @@ export class Form } // insert row values data into form - const remoteValueUrls = {}; - length = values.length; + const remoteUrls = {}; + length = values.length; for (let i = 0; i < length; ++i) { const path = values[i].hasAttribute('data-tpl-value-path') ? values[i].getAttribute('data-tpl-value-path') : null; for (let j = 0; j < selectorLength; ++j) { @@ -715,11 +855,15 @@ export class Form ? document.getElementsByTagName('base')[0].href : ''; - if (remoteValueUrls[uri + values[i].getAttribute('data-tpl-value')] === undefined) { - remoteValueUrls[uri + values[i].getAttribute('data-tpl-value')] = []; + if (remoteUrls[uri + values[i].getAttribute('data-tpl-value')] === undefined) { + remoteUrls[uri + values[i].getAttribute('data-tpl-value')] = []; } - remoteValueUrls[uri + values[i].getAttribute('data-tpl-value')].push({path: path, element: matches[c]}); + remoteUrls[uri + values[i].getAttribute('data-tpl-value')].push({ + path: path, + element: matches[c], + type: 'value' + }); } else { self.setValueOfElement(matches[c], self.getValueFromDataSource(values[i])); } @@ -727,30 +871,8 @@ export class Form } } - for (const e in remoteValueUrls) { - const request = new Request(e); - request.setResultCallback(200, function(xhr) { - /** - * @todo Orange-Management/jsOMS#84 - * Remote data responses need to be parsed - * The data coming from the backend/api usually is not directly usable in the frontend. - * For that purpose some kind of value path should be defined to handle json responses in order to get only the data that is needed. - */ - const remoteValueUrlsLength = remoteValueUrls[e].length; - for (let k = 0; k < remoteValueUrlsLength; ++k) { - const path = remoteValueUrls[e][k].path; - self.setValueOfElement(remoteValueUrls[e][k].element, - path !== null ? jsOMS.getArray(path, JSON.parse(xhr.response)) : xhr.response - ); - } - }); - - request.send(); - } - // insert row text data into form - const remoteTextUrls = {}; - length = text.length; + length = text.length; for (let i = 0; i < length; ++i) { const path = text[i].hasAttribute('data-tpl-text-path') ? text[i].getAttribute('data-tpl-text-path') : null; for (let j = 0; j < selectorLength; ++j) { @@ -766,15 +888,19 @@ export class Form if (text[i].getAttribute('data-tpl-text').startsWith('http') || text[i].getAttribute('data-tpl-text').startsWith('{') ) { - const uri = values[i].getAttribute('data-tpl-text').startsWith('/') + const uri = text[i].getAttribute('data-tpl-text').startsWith('/') ? document.getElementsByTagName('base')[0].href : ''; - if (remoteTextUrls[uri + text[i].getAttribute('data-tpl-value')] === undefined) { - remoteTextUrls[uri + text[i].getAttribute('data-tpl-value')] = []; + if (remoteUrls[uri + text[i].getAttribute('data-tpl-text')] === undefined) { + remoteUrls[uri + text[i].getAttribute('data-tpl-text')] = []; } - remoteTextUrls[uri + text[i].getAttribute('data-tpl-value')].push({path: path, element: matches[c]}); + remoteUrls[uri + text[i].getAttribute('data-tpl-text')].push({ + path: path, + element: matches[c], + type: 'text' + }); } else { self.setTextOfElement(matches[c], self.getTextFromDataSource(text[i])); } @@ -782,7 +908,7 @@ export class Form } } - for (const e in remoteTextUrls) { + for (const e in remoteUrls) { const request = new Request(e); request.setResultCallback(200, function(xhr) { /** @@ -791,12 +917,19 @@ export class Form * The data coming from the backend/api usually is not directly usable in the frontend. * For that purpose some kind of value path should be defined to handle json responses in order to get only the data that is needed. */ - const remoteTextUrlsLength = remoteTextUrls[e].length; - for (let k = 0; k < remoteTextUrlsLength; ++k) { - const path = remoteTextUrls[e][k].path; - self.setTextOfElement(remoteTextUrls[e][k].element, - path !== null ? jsOMS.getArray(path, JSON.parse(xhr.response)) : xhr.response - ); + const remoteUrlsLength = remoteUrls[e].length; + for (let k = 0; k < remoteUrlsLength; ++k) { + const path = remoteUrls[e][k].path; + + if (remoteUrls[e][k].type === 'value') { + self.setValueOfElement(remoteUrls[e][k].element, + path !== null ? jsOMS.getArray(path, JSON.parse(xhr.response)) : xhr.response + ); + } else { + self.setTextOfElement(remoteUrls[e][k].element, + path !== null ? jsOMS.getArray(path, JSON.parse(xhr.response)) : xhr.response + ); + } } }); @@ -878,7 +1011,7 @@ export class Form const formElement = document.getElementById(id); const parentsTpl = {}; const parentsContent = {}; - const selectors = formElement.getAttribute('data-ui-element').split(','), + const selectors = formElement.getAttribute('data-update-element').split(','), selectorLength = selectors.length; let values = []; @@ -944,7 +1077,7 @@ export class Form text = text.filter(function(value, index, self) { return self.indexOf(value) === index; }); // overwrite old values data in ui - const remoteValueUrls = {}; + const remoteUrls = {}; const changedValueNodes = []; // prevent same node touching length = values.length; for (let parent in parentsTpl) { // loop every selector which has elements to change @@ -967,11 +1100,15 @@ export class Form ? document.getElementsByTagName('base')[0].href : ''; - if (remoteValueUrls[uri + values[i].getAttribute('data-tpl-value')] === undefined) { - remoteValueUrls[uri + values[i].getAttribute('data-tpl-value')] = []; + if (remoteUrls[uri + values[i].getAttribute('data-tpl-value')] === undefined) { + remoteUrls[uri + values[i].getAttribute('data-tpl-value')] = []; } - remoteValueUrls[uri + values[i].getAttribute('data-tpl-value')].push({path: path, element: matches[c]}); + remoteUrls[uri + values[i].getAttribute('data-tpl-value')].push({ + path: path, + element: matches[c], + type: 'value' + }); } else { self.setValueOfElement(matches[c], self.getValueFromDataSource(values[i])); } @@ -980,7 +1117,6 @@ export class Form } // overwrite old text data in ui - const remoteTextUrls = {}; const changedTextNodes = []; length = text.length; for (let parent in parentsContent) { @@ -1003,11 +1139,15 @@ export class Form ? document.getElementsByTagName('base')[0].href : ''; - if (remoteTextUrls[uri + text[i].getAttribute('data-tpl-value')] === undefined) { - remoteTextUrls[uri + text[i].getAttribute('data-tpl-value')] = []; + if (remoteUrls[uri + text[i].getAttribute('data-tpl-text')] === undefined) { + remoteUrls[uri + text[i].getAttribute('data-tpl-text')] = []; } - remoteTextUrls[uri + text[i].getAttribute('data-tpl-value')].push({path: path, element: matches[c]}); + remoteUrls[uri + text[i].getAttribute('data-tpl-text')].push({ + path: path, + element: matches[c], + type: 'text' + }); } else { self.setTextOfElement(matches[c], self.getTextFromDataSource(text[i])); } @@ -1015,12 +1155,10 @@ export class Form } } - - // todo bind failure here, if failure do cancel, if success to remove edit template self.forms[id].setSuccess(function() { // overwrite old values from remote response - for (const e in remoteValueUrls) { + for (const e in remoteUrls) { const request = new Request(e); request.setResultCallback(200, function(xhr) { /** @@ -1029,41 +1167,27 @@ export class Form * The data coming from the backend/api usually is not directly usable in the frontend. * For that purpose some kind of value path should be defined to handle json responses in order to get only the data that is needed. */ - const remoteValueUrlsLength = remoteValueUrls[e].length; - for (let k = 0; k < remoteValueUrlsLength; ++k) { - const path = remoteValueUrls[e][k].path; - self.setValueOfElement(remoteValueUrls[e][k].element, - path !== null ? jsOMS.getArray(path, JSON.parse(xhr.response)) : xhr.response - ); - } - }); + const remoteUrlsLength = remoteUrls[e].length; + for (let k = 0; k < remoteUrlsLength; ++k) { + const path = remoteUrls[e][k].path; - request.send(); - } - - // overwrite old values from remote response - for (const e in remoteTextUrls) { - const request = new Request(e); - request.setResultCallback(200, function(xhr) { - /** - * @todo Orange-Management/jsOMS#84 - * Remote data responses need to be parsed - * The data coming from the backend/api usually is not directly usable in the frontend. - * For that purpose some kind of value path should be defined to handle json responses in order to get only the data that is needed. - */ - const remoteTextUrlsLength = remoteTextUrls[e].length; - for (let k = 0; k < remoteTextUrlsLength; ++k) { - const path = remoteTextUrls[e][k].path; - - self.setTextOfElement(remoteTextUrls[e][k].element, - path !== null ? jsOMS.getArray(path, JSON.parse(xhr.response)) : xhr.response - ); + if (remoteUrls[e][k].type === 'value') { + self.setValueOfElement(remoteUrls[e][k].element, + path !== null ? jsOMS.getArray(path, JSON.parse(xhr.response)) : xhr.response + ); + } else { + self.setTextOfElement(remoteUrls[e][k].element, + path !== null ? jsOMS.getArray(path, JSON.parse(xhr.response)) : xhr.response + ); + } } }); request.send(); } }); + + // @todo: does this submit and the previous submit in updatable mean I'm sending the data twice???? That would be bad! self.submit(self.forms[id]); self.removeEditTemplate(this, id); }); @@ -1082,7 +1206,7 @@ export class Form removeEditTemplate(ele, id) { const formElement = document.getElementById(id); - const selectors = formElement.getAttribute('data-ui-element').split(','), + const selectors = formElement.getAttribute('data-update-element').split(','), selectorLength = selectors.length; for (let i = 0; i < selectorLength; ++i) { @@ -1142,8 +1266,8 @@ export class Form update.addEventListener('click', function () { const formElement = document.getElementById(id); - const parent = this.closest(formElement.getAttribute('data-ui-element')); - const formId = formElement.getAttribute('data-ui-form'); + const parent = this.closest(formElement.getAttribute('data-update-element')); + const formId = formElement.getAttribute('data-update-form'); const values = parent.querySelectorAll('[data-tpl-value]'); const text = parent.querySelectorAll('[data-tpl-text]'); @@ -1204,7 +1328,7 @@ export class Form if (text[i].getAttribute('data-tpl-text').startsWith('http') || text[i].getAttribute('data-tpl-text').startsWith('{') ) { - const uri = values[i].getAttribute('data-tpl-text').startsWith('/') + const uri = text[i].getAttribute('data-tpl-text').startsWith('/') ? document.getElementsByTagName('base')[0].href : ''; @@ -1282,6 +1406,7 @@ export class Form { switch (src.tagName.toLowerCase()) { case 'div': + case 'span': case 'pre': case 'article': case 'section': @@ -1301,6 +1426,7 @@ export class Form { switch (src.tagName.toLowerCase()) { case 'div': + case 'span': case 'pre': case 'article': case 'section': @@ -1321,6 +1447,7 @@ export class Form { switch (src.tagName.toLowerCase()) { case 'div': + case 'span': case 'pre': case 'article': case 'section': @@ -1335,6 +1462,7 @@ export class Form { switch (src.tagName.toLowerCase()) { case 'div': + case 'span': case 'pre': case 'article': case 'section': diff --git a/UI/Component/Tab.js b/UI/Component/Tab.js index 980f2d6..dd6234e 100644 --- a/UI/Component/Tab.js +++ b/UI/Component/Tab.js @@ -1,4 +1,4 @@ -import { HttpUri } from '../../Uri/HttpUri.js'; +import { HttpUri } from '../../Uri/HttpUri.js'; import { UriFactory } from '../../Uri/UriFactory.js'; /** diff --git a/UI/GeneralUI.js b/UI/GeneralUI.js index fe53c75..95802b1 100644 --- a/UI/GeneralUI.js +++ b/UI/GeneralUI.js @@ -1,5 +1,5 @@ -import { UriFactory } from '../Uri/UriFactory.js'; +import { UriFactory } from '../Uri/UriFactory.js'; import { AdvancedInput } from './Component/AdvancedInput.js'; /** diff --git a/UI/Input/InputManager.js b/UI/Input/InputManager.js index 50a9cac..286cae3 100644 --- a/UI/Input/InputManager.js +++ b/UI/Input/InputManager.js @@ -1,6 +1,6 @@ import { KeyboardManager } from '../../../jsOMS/UI/Input/Keyboard/KeyboardManager.js'; -import { MouseManager } from '../../../jsOMS/UI/Input/Mouse/MouseManager.js'; -import { VoiceManager } from '../../../jsOMS/UI/Input/Voice/VoiceManager.js'; +import { MouseManager } from '../../../jsOMS/UI/Input/Mouse/MouseManager.js'; +import { VoiceManager } from '../../../jsOMS/UI/Input/Voice/VoiceManager.js'; /** * UI manager class. diff --git a/UI/UIManager.js b/UI/UIManager.js index f2cd0f7..9b7bef3 100644 --- a/UI/UIManager.js +++ b/UI/UIManager.js @@ -1,9 +1,9 @@ -import { Form } from '../UI/Component/Form.js'; -import { Tab } from '../UI/Component/Tab.js'; -import { Table } from '../UI/Component/Table.js'; +import { Form } from '../UI/Component/Form.js'; +import { Tab } from '../UI/Component/Tab.js'; +import { Table } from '../UI/Component/Table.js'; import { ActionManager } from '../UI/ActionManager.js'; -import { DragNDrop } from '../UI/DragNDrop.js'; -import { GeneralUI } from '../UI/GeneralUI.js'; +import { DragNDrop } from '../UI/DragNDrop.js'; +import { GeneralUI } from '../UI/GeneralUI.js'; /** * UI manager for handling basic ui elements. diff --git a/Uri/UriFactory.js b/Uri/UriFactory.js index 57c4f93..a17dce5 100644 --- a/Uri/UriFactory.js +++ b/Uri/UriFactory.js @@ -1,4 +1,4 @@ -import { HttpUri } from './HttpUri.js'; +import { HttpUri } from './HttpUri.js'; import { FormView } from './../Views//FormView.js'; /**