From 06c686213c3d743c8c5393613f7441f748017cb9 Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Sun, 12 Jan 2020 17:57:29 +0100 Subject: [PATCH] fix todo comments --- Model/Action/Dom/GetValue.js | 1 - Model/Action/Dom/Remove.js | 6 +- Model/Action/Message/Log.js | 7 +- Model/Action/Utils/DataCollector.js | 3 +- UI/ActionManager.js | 26 ++- UI/Component/AdvancedInput.js | 25 ++- UI/Component/AdvancedSelect.js | 42 +++-- UI/Component/Form.js | 253 +++++++++++++++++++++------ UI/Input/Keyboard/KeyboardManager.js | 30 ++-- UI/Input/Touch/TouchManager.js | 6 +- UI/Input/Voice/VoiceManager.js | 1 - Utils/Parser/Markdown.js | 1 - Utils/UiUtils.js | 22 +++ Utils/oLib.js | 23 ++- 14 files changed, 342 insertions(+), 104 deletions(-) diff --git a/Model/Action/Dom/GetValue.js b/Model/Action/Dom/GetValue.js index 017f14d..ff9e4a4 100644 --- a/Model/Action/Dom/GetValue.js +++ b/Model/Action/Dom/GetValue.js @@ -25,7 +25,6 @@ export function domGetValue (action, callback, id) if (e[i].tagName === 'INPUT' || e[i].tagName === 'SELECTS' || e[i].tagName === 'BUTTON') { value[eId] = e[i].getAttribute('value'); } else if (e[i].tagName === 'FORM') { - // todo: this is messy. if form should be handled somewhere else not in loop since it overwrites all other values... will there very be other values in case of a form selector? if yes than this will cause a bug! value = window.omsApp.uiManager.getFormManager().get(eId).getData(); break; } else { diff --git a/Model/Action/Dom/Remove.js b/Model/Action/Dom/Remove.js index 67c556b..8d59112 100644 --- a/Model/Action/Dom/Remove.js +++ b/Model/Action/Dom/Remove.js @@ -24,7 +24,11 @@ export function removeButtonAction (action, callback, id) e[i].classList.add(action.aniOut); } - // todo: here is a problem with removing elements. after removing the first element in a list the second one cannot be deleted. maybe this is because the action event gets removed for sister elements after one is deleted? + /** + * @todo Orange-Management/jsOMS#68 + * Adding a remove action to a list of elements will stop working after removing the first element. + * This could be because after removing the first sibling the action or the listener is removed for the siblings? + */ setTimeout(function () { if (e[i].parentElement === null) { diff --git a/Model/Action/Message/Log.js b/Model/Action/Message/Log.js index 23c2ed3..d4d26ed 100644 --- a/Model/Action/Message/Log.js +++ b/Model/Action/Message/Log.js @@ -1,3 +1,6 @@ +import { NotificationMessage } from '../../../Message/Notification/NotificationMessage.js'; +import { NotificationType } from '../../../Message/Notification/NotificationType.js'; + /** * Log. * @@ -12,11 +15,11 @@ export function logAction (action, callback, id) "use strict"; window.omsApp.notifyManager.send( - new jsOMS.Message.Notification.NotificationMessage( + new NotificationMessage( action.data.status, action.data.title, action.data.message - ), jsOMS.Message.Notification.NotificationType.APP_NOTIFICATION + ), NotificationType.APP_NOTIFICATION ); callback(); diff --git a/Model/Action/Utils/DataCollector.js b/Model/Action/Utils/DataCollector.js index b9fe5c2..209c9b8 100644 --- a/Model/Action/Utils/DataCollector.js +++ b/Model/Action/Utils/DataCollector.js @@ -24,8 +24,7 @@ export function dataCollectionAction (action, callback) continue; } - // todo: different types of elements have differnt forms of storing values (input, textarea etc.) - data[selector].push(e.value); + data[selector].push(jsOMS.getValue(e)); } } diff --git a/UI/ActionManager.js b/UI/ActionManager.js index 988ca83..10a946d 100644 --- a/UI/ActionManager.js +++ b/UI/ActionManager.js @@ -87,6 +87,7 @@ export class ActionManager for (let i = 0; i < listenerLength; ++i) { let c = [e], hasSelector = false; + // the selector must be a child of e!!! if (listeners[i].hasOwnProperty('selector')) { c = document.querySelectorAll(listeners[i].selector); hasSelector = true; @@ -97,11 +98,13 @@ export class ActionManager this.bindListener(c[j].id, listeners[i]); } - // if it has selector then a listener for child events must be implemented since these can potentially changed without any knowledge - // todo: what if the selector parent is different from "e"? then this doesn't make sense! Maybe this isn't allowed to happen! - // todo: careful this could cause bugs if there is another component relying on a listener for this dom element. Maybe create actionManager domlistener? - // Maybe just use this listener for ALL action listeners and check if delete, then remove otherwise do current stuff. - // Problem is, the listener doesn't work for the node itself only for children and listening to ALL document nodes might be a bad idea?!?!?! + /** + * @todo Orange-Management/jsOMS#69 + * If a element has a selector defined this means the action is defined for all child elements of this selector. + * This usually is done in order to avoid defining the same behavior multiple times for similar elements (e.g. elements in a list). + * However, in this case it's not unusual that the child elements get changed dynamically (added, changed, removed). + * In this case the child element listeners need to be updated on change/addition/removal. + */ const observeConfig = { childList: false, attributes: true, subtree: false }; if (hasSelector) { @@ -109,8 +112,11 @@ export class ActionManager const length = data.addedNodes.length; for (let j = 0; j < length; ++j) { - self.bindListener(data.addedNodes[j].id, listeners[i], true); - // todo only make removable if action itself is defined as auto removable + self.bindListener( + data.addedNodes[j].id, + listeners[i], + typeof listeners[i].autoremove !== 'undefined' ? listeners[i].autoremove : false + ); } }); @@ -144,13 +150,15 @@ export class ActionManager return; } + if (this.app.eventManager.isAttached(id + '-' + listener.key + '-' + listener.action[j - 1].key)) { + return; + } + this.app.eventManager.attach(id + '-' + listener.key + '-' + listener.action[j - 1].key, function (data) { self.runAction(id, listener, listener.action[j], data); }, removable, true); } - // todo: the true here is a memory leak since it should be removed at some point?! - // todo: handle onload action right after registering everything. this will be used for onload api calls in order to get content such as lists or models. Maybe in the main application after registering a invoke('onload') should be called if the application wants to execute the onload elements // Register event for first action document.getElementById(id).addEventListener(listener.listener, function (event) diff --git a/UI/Component/AdvancedInput.js b/UI/Component/AdvancedInput.js index 61312b6..97b520f 100644 --- a/UI/Component/AdvancedInput.js +++ b/UI/Component/AdvancedInput.js @@ -215,7 +215,11 @@ export class AdvancedInput selectOption(e) { e.focus(); - // todo: change to set style .active + + /** + * @todo Orange-Management/jsOMS#70 + * Implement external styles for selections instead of inline css + */ e.setAttribute('style', 'background: #f00'); jsOMS.addClass(e, 'active'); }; @@ -235,7 +239,11 @@ export class AdvancedInput length = list.length; for (let i = 0; i < length; ++i) { - // todo: remove the active class + + /** + * @todo Orange-Management/jsOMS#70 + * Implement external styles for selections instead of inline css + */ list[i].setAttribute('style', ''); jsOMS.removeClass(list[i], 'active'); } @@ -258,7 +266,11 @@ export class AdvancedInput } if (self.tagElement !== null && self.tagElement.getAttribute('data-active') === 'true') { - // todo: make badges removable + + /** + * @todo Orange-Management/jsOMS#71 + * Make badges removable + */ const newTag = self.tagTpl.content.cloneNode(true); // set internal value @@ -274,8 +286,11 @@ export class AdvancedInput uuid += value; } - // don't allow duplicate - // todo: create a data-duplicat=true attribute to allow duplication and then have a count as part of the uuid (maybe row id) + /** + * @todo Orange-Management/jsOMS#72 + * Allow duplication + * Create a `data-duplicat=true` attribute to allow duplication and then have a count as part of the uuid (maybe row id). + */ if (self.tagElement.querySelectorAll('[data-tpl-uuid="' + uuid + '"').length !== 0) { return; } diff --git a/UI/Component/AdvancedSelect.js b/UI/Component/AdvancedSelect.js index 6a357da..6c6d0f7 100644 --- a/UI/Component/AdvancedSelect.js +++ b/UI/Component/AdvancedSelect.js @@ -38,10 +38,12 @@ export class AdvancedSelect const self = this; this.selectField.addEventListener('focusout', function (e) { - // todo: this also means that clicking on any other part of the result list that it disappears befor - // the click is registered in the result list since focusout has highest priority (e.g. sort button in table). - // so far i don't know a way to check if *any* element in the result div is clicked, if I could check this - // first then I could simply say, don't make the result div inactive! + /** + * @todo Orange-Management/Modules#63 + * If you click anything outside of the input element the dropdown list closes. + * This is also true if you click something inside of the dropdown list e.g. sort/filter etc. + * This might be fixable by changing the focus from the input element to the dropdown element and keep the dropdown element visible if it has focus. + */ if (e.relatedTarget === null || e.relatedTarget.parentElement === null || e.relatedTarget.parentElement.parentElement === null || @@ -73,9 +75,13 @@ export class AdvancedSelect this.dropdownElement.addEventListener('keydown', function (e) { jsOMS.preventAll(e); - // todo: consider if it makes sense to have a none element always for phone users only to jump out? - // todo: if not remote then the suggestion dropdown should filter itself based on best match - + /** + * @todo Orange-Management/jsOMS#73 + * Consider to add a none element which allows phone users to undo a selection (if this is allowed). + * + * @todo Orange-Management/jsOMS#74 + * Implement auto filtering on client side (for remote data and client side data). + */ if (e.keyCode === 27 || e.keyCode === 46 || e.keyCode === 8) { // handle esc, del to go back to input field self.inputField.focus(); @@ -211,7 +217,10 @@ export class AdvancedSelect */ selectOption(e) { e.focus(); - // todo: change to set style .active + /** + * @todo Orange-Management/jsOMS#70 + * Implement external styles for selections instead of inline css + */ e.setAttribute('style', 'background: #f00'); jsOMS.addClass(e, 'active'); }; @@ -230,7 +239,10 @@ export class AdvancedSelect length = list.length; for (let i = 0; i < length; ++i) { - // todo: remove the active class + /** + * @todo Orange-Management/jsOMS#70 + * Implement external styles for selections instead of inline css + */ list[i].setAttribute('style', ''); jsOMS.removeClass(list[i], 'active'); } @@ -253,7 +265,10 @@ export class AdvancedSelect } if (self.tagElement.getAttribute('data-active') === 'true') { - // todo: make badges removable + /** + * @todo Orange-Management/jsOMS#71 + * Make badges removable + */ const newTag = self.tagTpl.content.cloneNode(true); // set internal value @@ -269,8 +284,11 @@ export class AdvancedSelect uuid += value; } - // don't allow duplicate - // todo: create a data-duplicat=true attribute to allow duplication and then have a count as part of the uuid (maybe row id) + /** + * @todo Orange-Management/jsOMS#72 + * Allow duplication + * Create a `data-duplicat=true` attribute to allow duplication and then have a count as part of the uuid (maybe row id). + */ if (self.tagElement.querySelectorAll('[data-tpl-uuid="' + uuid + '"').length !== 0) { return; } diff --git a/UI/Component/Form.js b/UI/Component/Form.js index 071e59d..aa5ea3c 100644 --- a/UI/Component/Form.js +++ b/UI/Component/Form.js @@ -349,9 +349,6 @@ export class Form if ((successInject = form.getSuccess()) !== null) { successInject(response); } else if (typeof response.get('type') !== 'undefined') { - // todo: am i using this now and should all cases be handled with the successInjection? - // maybe there could be global response actions where injecting them to every form would not make any sense - // however not many if any use cases come to mind right now where this would be necessary self.app.responseManager.run(response.get('type'), response.get(), request); } else if (typeof o.status !== 'undefined' && o.status !== NotificationLevel.HIDDEN) { self.app.notifyManager.send( @@ -412,15 +409,25 @@ export class Form bindAddExternal(id) { const createForm = document.getElementById(id).getAttribute('data-ui-form'); - // todo: maybe allow multiple add buttons!!!! In order to do that do createForm.getAttribute('data-ui-form') and add this attribute to the add button instead of the pseudo form + /** + * @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')); - // todo: [0/1] is no longer working because of arbitrary templates for inline editing + /** + * @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); // set internal value @@ -430,12 +437,16 @@ export class Form let value = ''; 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'); - // todo: 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].setAttribute('data-value', value); uuid += value; @@ -453,6 +464,12 @@ export class Form 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( @@ -460,17 +477,28 @@ export class Form )[0].value ) ); - - // todo: 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=] } subMain.appendChild(newEle); - // todo: consider to do ui action as success inject to the backend request... maybe optional because sometimes there will be no backend call? - // todo: sometimes the response data needs to be put into the frontend (e.g. image upload, only after upload the backend endpoint will be known and not in advance) - // todo: if a column has a form in the template the id of the form needs to be set unique somehow (e.g. remove button in form) - // todo: bind removable - // todo: bind edit + /** + * @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` + */ return true; }); @@ -496,10 +524,20 @@ export class Form ? document.querySelector(formElement.getAttribute('data-ui-content')) : formElement.querySelector(formElement.getAttribute('data-ui-content')); - // todo: [0/1] is no longer working because of arbitrary templates for inline editing + /** + * @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')[1].content.cloneNode(true); - const eleId = 'f' + Math.random().toString(36).substring(7); - // todo: check if random id doesn't already exist + let eleId = ''; + + do { + eleId = 'f' + Math.random().toString(36).substring(7); + } while (document.getElementById(eleId) !== null); newEle.firstElementChild.id = eleId; newEle.firstElementChild.getElementsByTagName('form')[0].id = eleId + '-form'; @@ -513,20 +551,40 @@ export class Form subMain.appendChild(newEle.firstElementChild); - // todo: this is no longer working... it's not tbody!!! + /** + * @todo Orange-Management/jsOMS#82 + * The container element for inline adding isn't always tbody + * + * @todo Orange-Management/jsOMS#83 + * Removing a dynamically added form from the dom should also be removed and unbound from the FormManager + */ self.app.uiManager.getFormManager().get(eleId + '-form').injectSubmit(function () { document.getElementById(id).getElementsByTagName('tbody')[0].removeChild( document.getElementById(eleId) ); }); - // todo: bind removable - // todo: bind edit + /** + * @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: this is polluting the form manager because it should be emptied afterwards (form is deleted but not from form manager) - // todo: consider to do ui action as success inject to the backend request... maybe optional because sometimes there will be no backend call? - // todo: if a column has a form in the template the id of the form needs to be set unique somehow (e.g. remove button in form) + /** + * @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#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` + */ }; /** @@ -578,7 +636,6 @@ export class Form for (let i = 0; i < selectorLength; ++i) { // this handles selectors such as 'ancestor > child/or/sibling' and many more - // todo: maybe move this to the library as an advanced ancestor function? const selector = selectors[i].trim(' ').split(' '); const closest = selector[0].trim(); @@ -604,8 +661,11 @@ export class Form newEle.push(subMain.getElementsByTagName('template')[selectorLength + i].content.cloneNode(true)); if (newEle[i].firstElementChild.id === null) { - // todo: don't use random id use actual row id for data which needs to be updated - const eleId = 'f' + Math.random().toString(36).substring(7); + 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; @@ -632,25 +692,25 @@ export class Form const matchLength = matches.length; for (let c = 0; c < matchLength; ++c) { - // todo: handle multiple matches - // todo: urls remote src shouldn't start with http (it can but also the base path should be allowed or the current uri as basis... maybe define a data-tpl-value-srctype??? however this sounds stupid and might be too verbose or use http as identifier and use the fact that the request object uses internally the uri factory!!! sounds much smarter :)) - // todo: implement this for other cases as well or potentially pull it out because it is very similar!!! if (values[i].getAttribute('data-tpl-value').startsWith('http') || values[i].getAttribute('data-tpl-value').startsWith('{') ) { const request = new Request(values[i].getAttribute('data-tpl-value')); 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. + */ self.setValueOfElement(matches[c], xhr.response); - // todo: the problem with this is that the response must only return the markdown or whatever is requested. It would be much nicer if it would also possible to define a path for the response in case a json object is returned which is very likely }); request.send(); } else { self.setValueOfElement(matches[c], self.getValueFromDataSource(values[i])); } - // todo handle remote data (e.g. value ist coming from backend. do special check for http) } - // todo: handle different input types } } @@ -662,9 +722,24 @@ export class Form const matchLength = matches.length; for (let c = 0; c < matchLength; ++c) { - // todo: handle multiple matches - self.setTextOfElement(matches[c], self.getTextFromDataSource(text[i])); - // todo handle remote data (e.g. value ist coming from backend. do special check for http) + if (text[i].getAttribute('data-tpl-text').startsWith('http') + || text[i].getAttribute('data-tpl-text').startsWith('{') + ) { + const request = new Request(text[i].getAttribute('data-tpl-text')); + 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. + */ + self.setTextOfElement(matches[c], xhr.response); + }); + + request.send(); + } else { + self.setTextOfElement(matches[c], self.getTextFromDataSource(text[i])); + } } } } @@ -684,7 +759,10 @@ export class Form ); });*/ - // todo: replace add button with save button and add cancel button + /** + * @todo Orange-Management/jsOMS#86 + * On edit replace add button with save and cancel + */ jsOMS.addClass(this, 'hidden'); const saveButtons = self.forms[id].getSave(); @@ -702,7 +780,10 @@ export class Form // todo: on save button click insert data into hidden row and show hidden row again, delete form row }); - // todo: bind bad form response (e.g. api responds with anything but 201) + /** + * @todo Orange-Management/jsOMS#85 + * Invalid backend/api responses (!201) should undo/stop UI changes + */ }; /** @@ -751,7 +832,6 @@ export class Form for (let i = 0; i < selectorLength; ++i) { // todo: similar logic is in updatable Inline and probably in External... pull out? // this handles selectors such as 'ancestor > child/or/sibling' and many more - // todo: maybe move this to the library as an advanced ancestor function? let selector = selectors[i].trim(' ').split(' '); let closest = selector[0].trim(); @@ -797,14 +877,27 @@ export class Form for (let j = 0; j < selectorLength; ++j) { const matches = parentsContent[j].querySelectorAll('[data-tpl-value="' + values[i].getAttribute('data-tpl-value') + '"'); - const matchLength = matches.length; for (let c = 0; c < matchLength; ++c) { - // todo: handle multiple matches - matches[c].value = self.getValueFromDataSource(values[i]); - // todo handle remote data (e.g. value ist coming from backend. do special check for http) + if (values[i].getAttribute('data-tpl-value').startsWith('http') + || values[i].getAttribute('data-tpl-value').startsWith('{') + ) { + const request = new Request(values[i].getAttribute('data-tpl-value')); + 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. + */ + self.setValueOfElement(matches[c], xhr.response); + }); + + request.send(); + } else { + self.setValueOfElement(matches[c], self.getValueFromDataSource(values[i])); + } } - // todo: handle different input types } } @@ -816,9 +909,24 @@ export class Form const matchLength = matches.length; for (let c = 0; c < matchLength; ++c) { - // todo: handle multiple matches - self.setTextOfElement(matches[c], self.getTextFromDataSource(text[i])); - // todo handle remote data (e.g. value ist coming from backend. do special check for http) + if (text[i].getAttribute('data-tpl-text').startsWith('http') + || text[i].getAttribute('data-tpl-text').startsWith('{') + ) { + const request = new Request(text[i].getAttribute('data-tpl-text')); + 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. + */ + self.setTextOfElement(matches[c], xhr.response); + }); + + request.send(); + } else { + self.setTextOfElement(matches[c], self.getTextFromDataSource(text[i])); + } } } } @@ -916,31 +1024,68 @@ export class Form // insert row values data into form length = values.length; for (let i = 0; i < length; ++i) { - // todo: handle multiple matches const matches = document.getElementById(formId).querySelectorAll('[data-tpl-value="' + values[i].getAttribute('data-tpl-value') + '"'); const matchLength = matches.length; for (let c = 0; c < matchLength; ++c) { - self.setValueOfElement(matches[c], self.getValueFromDataSource(values[i])); + if (values[i].getAttribute('data-tpl-value').startsWith('http') + || values[i].getAttribute('data-tpl-value').startsWith('{') + ) { + const request = new Request(values[i].getAttribute('data-tpl-value')); + 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. + */ + self.setValueOfElement(matches[c], xhr.response); + }); + + request.send(); + } else { + self.setValueOfElement(matches[c], self.getValueFromDataSource(values[i])); + } } - // todo handle remote data (e.g. value ist coming from backend. do special check for http) } // insert row text data into form length = text.length; for (let i = 0; i < length; ++i) { - // todo: handle multiple matches const matches = document.getElementById(formId).querySelectorAll('[data-tpl-text="' + text[i].getAttribute('data-tpl-text') + '"'); - // consider pulling this out because it exists like 3x2 = 6 times in a similar way or at least 3 times very similarly + // todo: consider pulling this out because it exists like 3x2 = 6 times in a similar way or at least 3 times very similarly const matchLength = matches.length; for (let c = 0; c < matchLength; ++c) { - self.setTextOfElement(matches[c], self.getTextFromDataSource(text[i])); + if (text[i].getAttribute('data-tpl-text').startsWith('http') + || text[i].getAttribute('data-tpl-text').startsWith('{') + ) { + const request = new Request(text[i].getAttribute('data-tpl-text')); + 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. + */ + self.setTextOfElement(matches[c], xhr.response); + }); + + request.send(); + } else { + self.setTextOfElement(matches[c], self.getTextFromDataSource(text[i])); + } } - // todo handle remote data (e.g. value ist coming from backend. do special check for http) } - // todo: replace add button with save button and add cancel button + /** + * @todo Orange-Management/jsOMS#86 + * On edit replace add button with save and cancel + * + * @todo Orange-Management/jsOMS#85 + * Invalid backend/api responses (!201) should undo/stop UI changes + */ + // todo: on save button click insert data into hidden row and show hidden row again, delete form row // todo: consider to highlight column during edit }); diff --git a/UI/Input/Keyboard/KeyboardManager.js b/UI/Input/Keyboard/KeyboardManager.js index d0f34d7..868e287 100644 --- a/UI/Input/Keyboard/KeyboardManager.js +++ b/UI/Input/Keyboard/KeyboardManager.js @@ -52,21 +52,25 @@ export class KeyboardManager */ bind (element) { - const self = this; + const elements = document.querySelectorAll(element); + const self = this, + length = elements.length; - // todo: implement keyboard for selected elements right now only global hotkeys possible - document.addEventListener('keydown', function keyBind(event) - { - self.down.push(event.keyCode); - }); - document.addEventListener('keyup', function keyBind(event) - { - if (self.down.length > 0) { - self.run(element, event); - self.down = []; - } - }); + for (let i = 0; i < length; ++i) { + elements[i].addEventListener('keydown', function keyBind(event) + { + self.down.push(event.keyCode); + }); + + elements[i].addEventListener('keyup', function keyBind(event) + { + if (self.down.length > 0) { + self.run(element, event); + self.down = []; + } + }); + } }; /** diff --git a/UI/Input/Touch/TouchManager.js b/UI/Input/Touch/TouchManager.js index 0adbf9d..0fa75f1 100644 --- a/UI/Input/Touch/TouchManager.js +++ b/UI/Input/Touch/TouchManager.js @@ -78,10 +78,10 @@ export class TouchManager elapsedTime = new Date().getTime() - self.activeSwipe.time; self.resetSwipe(); - // todo: only prevent all if success - jsOMS.preventAll(event); if (elapsedTime > 300 && distY < 3 && distX < 3) { + jsOMS.preventAll(event); + let rightClick = MouseEvent('click', { bubbles: true, @@ -102,6 +102,8 @@ export class TouchManager document.dispatchEvent(rightClick); } else if (elapsedTime < 500) { + jsOMS.preventAll(event); + /** global: Event */ const e = new Event('keyup'); diff --git a/UI/Input/Voice/VoiceManager.js b/UI/Input/Voice/VoiceManager.js index b971647..a219e68 100644 --- a/UI/Input/Voice/VoiceManager.js +++ b/UI/Input/Voice/VoiceManager.js @@ -106,7 +106,6 @@ export class VoiceManager */ setLanguage(lang) { - // todo: eventually restart this.recognition.lang = lang; }; diff --git a/Utils/Parser/Markdown.js b/Utils/Parser/Markdown.js index 396d284..4b5f849 100644 --- a/Utils/Parser/Markdown.js +++ b/Utils/Parser/Markdown.js @@ -2558,7 +2558,6 @@ clean(doc); // some stuff, like accidental reference links must now be escaped - // todo // doc.innerHTML = doc.innerHTML.replace(/\[[\S\t ]]/); var nodes = doc.childNodes, diff --git a/Utils/UiUtils.js b/Utils/UiUtils.js index dd2b624..fe76d37 100644 --- a/Utils/UiUtils.js +++ b/Utils/UiUtils.js @@ -98,6 +98,28 @@ } }; + /** + * Get element value + * + * @param ele DOM Element + * + * @return {string} + * + * @since 1.0.0 + */ + jsOMS.getValue = function (ele) + { + switch (ele.tagName.toLowerCase()) { + case 'div': + case 'pre': + case 'article': + case 'section': + return ele.innerHTML; + default: + return ele.value; + } + }; + /** * Action prevent * diff --git a/Utils/oLib.js b/Utils/oLib.js index ba72966..d7b2e0d 100644 --- a/Utils/oLib.js +++ b/Utils/oLib.js @@ -276,7 +276,6 @@ */ jsOMS.ready = function (func) { - // todo: IE problems? + Maybe interactive + loaded can cause problems since elements might not be loaded yet?!!?!!?! if (document.readyState === 'complete' || document.readyState === 'loaded' || document.readyState === 'interactive') { func(); } else { @@ -287,6 +286,28 @@ } }; + /** + * Get element value + * + * @param ele DOM Element + * + * @return {string} + * + * @since 1.0.0 + */ + jsOMS.getValue = function (ele) + { + switch (ele.tagName.toLowerCase()) { + case 'div': + case 'pre': + case 'article': + case 'section': + return ele.innerHTML; + default: + return ele.value; + } + }; + /** * Empty element *