diff --git a/Log/Logger.js b/Log/Logger.js index dfa6720..a349bfb 100644 --- a/Log/Logger.js +++ b/Log/Logger.js @@ -115,11 +115,7 @@ export class Logger } if (this.ui) { - /** - * @todo Orange-Management/jsOMS#67 - * Implement UI logging - * Create a dom element with inline css for UI logging. - */ + this.writeUi(message, context, level); } if (this.remote) { @@ -127,6 +123,17 @@ export class Logger } }; + writeUi (message, context, level) + { + if (Notification.permission !== 'granted' && Notification.permission !== 'denied') { + Notification.requestPermission().then(function(permission) { }); + } + + /** global: Notification */ + const notification = new Notification('Logger', {body: this.interpolate(message, context, level)}); + setTimeout(notification.close.bind(notification), 4000); + }; + /** * Create local log message * diff --git a/Message/Notification/App/AppNotification.js b/Message/Notification/App/AppNotification.js index 29cc54d..611ef03 100644 --- a/Message/Notification/App/AppNotification.js +++ b/Message/Notification/App/AppNotification.js @@ -64,7 +64,7 @@ export class AppNotification tpl.parentNode.appendChild(output); - const logs = document.getElementsByClassName('log-msg'); + const logs = document.getElementsByClassName('log-msg'); const lastElementAdded = logs[logs.length - 1]; window.navigator.vibrate(msg.vibrate ? 200 : 0); diff --git a/Message/Notification/Browser/BrowserNotification.js b/Message/Notification/Browser/BrowserNotification.js index f68080b..44f9972 100644 --- a/Message/Notification/Browser/BrowserNotification.js +++ b/Message/Notification/Browser/BrowserNotification.js @@ -60,9 +60,9 @@ export class BrowserNotification { /** global: Notification */ if (Notification.permission === "granted") { - let notification = new Notification(msg.title, { body: msg.message, vibrate: [msg.vibrate ? 200 : 0] }); + const notification = new Notification(msg.title, { body: msg.message, vibrate: [msg.vibrate ? 200 : 0] }); - setTimeout(notification.close.bind(notification), 4000); + setTimeout(notification.close.bind(notification), 5000); } }; }; \ No newline at end of file diff --git a/UI/ActionManager.js b/UI/ActionManager.js index 10a946d..92016eb 100644 --- a/UI/ActionManager.js +++ b/UI/ActionManager.js @@ -10,7 +10,7 @@ import { Logger } from '../Log/Logger.js'; * * @todo Orange-Management/jsOMS#26 * Sync/Async events - * Events so fare can be created sync and async depending on the implementation. + * Events so far can be created sync and async depending on the implementation. * It would be better to make it sync/async depending on a option flag. * * @todo Orange-Management/jsOMS#35 diff --git a/UI/Component/Form.js b/UI/Component/Form.js index 5a2f5b4..896e5f0 100644 --- a/UI/Component/Form.js +++ b/UI/Component/Form.js @@ -7,6 +7,7 @@ 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 { GeneralUI } from '../GeneralUI.js'; import { UriFactory } from '../../Uri/UriFactory.js'; /** @@ -28,11 +29,6 @@ import { UriFactory } from '../../Uri/UriFactory.js'; * * on Change (by using a timer) * * on Leave (all elements) * The listener should be defined in the form definition once and in js be applied to all form elements. - * - * @todo Orange-Management/Modules#177 - * Hotkey for saving forms for creation/edit - * Instead of using the mouse to click save the user should be able to use a hotkey to save/create/update the current form. - * The hotkey on PC should be alt+enter or alt+shift+enter or alt+s */ export class Form { @@ -152,38 +148,7 @@ export class Form const submitLength = submits.length; this.unbind(id); - - const removable = this.forms[id].getRemove(); - length = removable === null ? 0 : removable.length; - for (let i = 0; i < length; ++i) { - this.bindRemovable(removable[i], id); - } - - const addable = this.forms[id].getAdd(); - length = addable === null ? 0 : addable.length; - for (let i = 0; i < length; ++i) { - this.bindAdd(addable[i], id); - } - - const save = this.forms[id].getSave(); - length = save === null ? 0 : save.length; - for (let i = 0; i < length; ++i) { - this.bindSaveInline(save[i], id); - } - - // @todo implement bindSaveExternal ??? - - const cancel = this.forms[id].getCancel(); - length = cancel === null ? 0 : cancel.length; - for (let i = 0; i < length; ++i) { - this.bindCancelInline(cancel[i], id); - } - - const update = this.forms[id].getUpdate(); - length = update === null ? 0 : update.length; - for (let i = 0; i < length; ++i) { - this.bindUpdatable(update[i], id); - } + this.bindButtons(id); const imgPreviews = this.forms[id].getImagePreviews(); length = imgPreviews === null ? 0 : imgPreviews.length; @@ -195,11 +160,48 @@ export class Form submits[i].addEventListener('click', function (event) { jsOMS.preventAll(event); - self.submit(self.forms[id], submits[i].getAttribute('formaction')); + self.submit(self.forms[id], submits[i]); }); } }; + bindButtons (id, e = null) + { + let length = 0; + + const removable = this.forms[id].getRemove(e); + length = removable === null ? 0 : removable.length; + for (let i = 0; i < length; ++i) { + this.bindRemovable(removable[i], id); + } + + const addable = this.forms[id].getAdd(e); + length = addable === null ? 0 : addable.length; + for (let i = 0; i < length; ++i) { + this.bindAdd(addable[i], id); + } + + const save = this.forms[id].getSave(e); + length = save === null ? 0 : save.length; + for (let i = 0; i < length; ++i) { + this.bindSaveInline(save[i], id); + } + + // @todo implement bindSaveExternal ??? + + const cancel = this.forms[id].getCancel(e); + length = cancel === null ? 0 : cancel.length; + for (let i = 0; i < length; ++i) { + this.bindCancel(cancel[i], id); + } + + const update = this.forms[id].getUpdate(e); + length = update === null ? 0 : update.length; + for (let i = 0; i < length; ++i) { + this.bindUpdatable(update[i], id); + } + }; + /** * Create the new input * @@ -210,9 +212,7 @@ export class Form * * @since 1.0.0 */ - bindImagePreview(imageUpload, id) { - const self = this; - + bindImagePreview (imageUpload, id) { imageUpload.addEventListener('change', function () { const preview = document.querySelector('#preview-' + imageUpload.getAttribute('name')); @@ -221,7 +221,7 @@ export class Form window.URL.revokeObjectURL(this.src); } }); - } + }; /** * Unbind form @@ -250,21 +250,25 @@ export class Form * Calls injections first before executing the actual form submit * * @param {Object} form Form object - * @param {string} [action] Action different from the form action (e.g. formaction=*) + * @param {Element} button Action different from the form action (e.g. formaction=*) * * @return {void} * * @since 1.0.0 */ - submit (form, action = null) + submit (form, button) { - action = typeof action !== 'undefined' ? action : null; - /* Handle injects */ const self = this, injects = form.getSubmitInjects(); let counter = 0; + let action = null; + + if (button !== null) { + action = button.getAttribute('formaction'); + } + // Register normal form behavior if (!this.app.eventManager.isAttached(form.getId())) { this.app.eventManager.attach(form.getId(), function () @@ -291,6 +295,10 @@ export class Form if (counter < 1) { this.app.eventManager.trigger(form.getId()); } + + // select first input element (this allows fast consecutive data input) + const firstFormInputElement = form.getFirstInputElement(); + firstFormInputElement.focus(); }; /** @@ -307,8 +315,6 @@ export class Form */ submitForm (form, action = null) { - action = typeof action !== 'undefined' ? action : null; - const data = form.getData(); if (!form.isValid(data)) { @@ -413,6 +419,20 @@ export class Form } }; + static formClickEvent(event) + { + // submit button? + + // filter + // sort + // reorder + // remove + // add + // save + // update + // dragndrop + }; + /** * Count the bound forms * @@ -444,6 +464,10 @@ export class Form * Currently only one add button is allowed per form. Allow multiple/different add buttons in a form. */ create.addEventListener('click', function () { + if (!self.forms[id].isValid()) { + return; + } + const formElement = document.getElementById(id); const parents = []; const selectors = formElement.getAttribute('data-add-element').split(','), @@ -470,10 +494,15 @@ export class Form newEle.push(document.querySelector(addTpl[i]).content.cloneNode(true)); + const tplValue = newEle[i].querySelector('[data-tpl-value]').getAttribute('data-tpl-value'); parents.push( - selector.length === 0 - ? newEle[i].firstElementChild - : newEle[i].firstElementChild.querySelector(subSelector) + tplValue.startsWith('http') || tplValue.startsWith('{') + ? ( // data is only added from remote response after adding + selector.length === 0 + ? newEle[i].firstElementChild + : newEle[i].firstElementChild.querySelector(subSelector) + ) + : formElement // data comes from the form (even if the api returns something after adding). What if remote returns a DB id? how do we add it? is this a @todo ? probably yes, maybe first use local data and then if remote data available replace local data? ); values = values.concat( @@ -487,114 +516,27 @@ export class Form : 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