diff --git a/Log/Logger.js b/Log/Logger.js index 4c0a3c9..5300147 100755 --- a/Log/Logger.js +++ b/Log/Logger.js @@ -1,5 +1,6 @@ import { LogLevel } from './LogLevel.js'; import { Request } from '../Message/Request/Request.js'; +import { SystemUtils } from '../System/SystemUtils.js'; /** * Logger class. @@ -63,7 +64,7 @@ export class Logger * * @since 1.0.0 */ - interpolate (message, context, level) + interpolate (message, context) { message = typeof message === 'undefined' ? Logger.MSG_FULL : message; @@ -89,13 +90,15 @@ export class Logger */ createContext (message, context, level) { - context.datetime = (new Date()).toISOString(); - context.version = '1.0.0'; - context.os = Request.getOS(); - context.browser = Request.getBrowser(); - context.path = window.location.href; - context.level = level; - context.message = message; + context.backtrace = console.trace(); + context.datetime = (new Date()).toISOString(); + context.version = '1.0.0'; + context.os = SystemUtils.getOS(); + context.browser = SystemUtils.getBrowser(); + context.path = window.location.href; + context.datetime = (new Date()).toString(); + context.level = level; + context.message = message; return context; }; @@ -120,11 +123,11 @@ export class Logger } if (this.ui) { - this.writeUi(message, context, level); + this.writeUi(message, context); } if (this.remote) { - this.writeRemote(message, context, level); + this.writeRemote(context); } }; @@ -133,20 +136,19 @@ export class Logger * * @param {string} message Message to display * @param {Object} [context] Context to put into message - * @param {string} level Log level * * @return {void} * * @since 1.0.0 */ - writeUi (message, context, level) + writeUi (message, context) { /** global: Notification */ if (Notification.permission !== 'granted' && Notification.permission !== 'denied') { Notification.requestPermission().then(function (permission) { }); } - const notification = new Notification('Logger', { body: this.interpolate(message, context, level) }); + const notification = new Notification('Logger', { body: this.interpolate(message, context) }); setTimeout(notification.close.bind(notification), 4000); }; @@ -192,15 +194,13 @@ export class Logger /** * Create remote log message * - * @param {string} message Message to display * @param {Object} [context] Context to put into message - * @param {string} level Log level * * @return {void} * * @since 1.0.0 */ - writeRemote (message, context, level) + writeRemote (context) { const request = new Request(); request.setData(context); diff --git a/Message/Request/Request.js b/Message/Request/Request.js index b945c36..3631c9c 100755 --- a/Message/Request/Request.js +++ b/Message/Request/Request.js @@ -1,7 +1,5 @@ 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'; @@ -85,61 +83,6 @@ export class Request } }; - /** - * Get browser. - * - * @return {string} - * - * @since 1.0.0 - */ - static getBrowser () - { - /** global: InstallTrigger */ - /** global: navigator */ - /** global: window */ - if ((!!window.opr && !!opr.addons) || !!window.opera || navigator.userAgent.indexOf(' OPR/') >= 0) { - return BrowserType.OPERA; - } else if (typeof InstallTrigger !== 'undefined') { - return BrowserType.FIREFOX; - } else if (Object.toString.call(window.HTMLElement).indexOf('Constructor') > 0) { - return BrowserType.SAFARI; - } else if (/* @cc_on!@ */false || !!document.documentMode) { - return BrowserType.IE; - } else if (!!window.StyleMedia) { - return BrowserType.EDGE; - } else if (!!window.chrome && !!window.chrome.webstore) { - return BrowserType.CHROME; - } else if (((typeof isChrome !== 'undefined' && isChrome) - || (typeof isOpera !== 'undefined' && isOpera)) - && !!window.CSS - ) { - return BrowserType.BLINK; - } - - return BrowserType.UNKNOWN; - }; - - /** - * Get os. - * - * @return {string} - * - * @since 1.0.0 - */ - static getOS () - { - for (const os in OSType) { - if (Object.prototype.hasOwnProperty.call(OSType, os)) { - /** global: navigator */ - if (navigator.appVersion.toLowerCase().indexOf(OSType[os]) !== -1) { - return OSType[os]; - } - } - } - - return OSType.UNKNOWN; - }; - /** * Set request method. * @@ -378,13 +321,20 @@ export class Request if (this.xhr.readyState !== 1) { if (this.type === RequestType.FORM_DATA) { - let url = this.uri; - for (let pair of this.data.entries()) { - url += '&' + pair[0] + '=' + pair[1]; - } + // GET request doesn't allow body/payload. Therefor we have to put the data into the uri + if (this.method === RequestMethod.GET) { + let url = this.uri; + for (let pair of this.data.entries()) { + url += '&' + pair[0] + '=' + pair[1]; + } - this.xhr.open(this.method, UriFactory.build(url)); + this.xhr.open(this.method, UriFactory.build(url)); + } else { + this.xhr.open(this.method, UriFactory.build(this.uri)); + } } else { + console.log(UriFactory.build(this.uri)); + this.xhr.open(this.method, UriFactory.build(this.uri)); } @@ -421,11 +371,7 @@ export class Request } else if (this.type === RequestType.URL_ENCODE) { this.xhr.send(this.queryfy(this.data)); } else if (this.type === RequestType.FORM_DATA) { - if (this.method === RequestMethod.GET) { - this.xhr.send(); - } else { - this.xhr.send(this.data); - } + this.xhr.send(this.data); } }; }; diff --git a/README.md b/README.md index 6105ff3..cb93ece 100755 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ General updates can be found in our info section at https://karaka.app/info and ## Tech stack * Language: php, js, c++, html, css, markdown, shell script -* Database: Maria/MySQL, PostgreSQL, MSSQL, SQLite +* Database: Maria/MySQL, PostgreSQL, MSSQL/SQLSrv, SQLite * Webserver: apache2, nginx * Cache: Redis, Memcached diff --git a/Message/Request/BrowserType.js b/System/BrowserType.js similarity index 100% rename from Message/Request/BrowserType.js rename to System/BrowserType.js diff --git a/Message/Request/OSType.js b/System/OSType.js similarity index 100% rename from Message/Request/OSType.js rename to System/OSType.js diff --git a/System/SystemUtils.js b/System/SystemUtils.js new file mode 100644 index 0000000..8da571b --- /dev/null +++ b/System/SystemUtils.js @@ -0,0 +1,68 @@ +import { BrowserType } from './BrowserType.js'; +import { OSType } from './OSType.js'; + +/** + * System utils class. + * + * @copyright Dennis Eichhorn + * @license OMS License 1.0 + * @version 1.0.0 + * @since 1.0.0 + */ +export class SystemUtils +{ + /** + * Get browser. + * + * @return {string} + * + * @since 1.0.0 + */ + static getBrowser () + { + /** global: InstallTrigger */ + /** global: navigator */ + /** global: window */ + if ((!!window.opr && !!opr.addons) || !!window.opera || navigator.userAgent.indexOf(' OPR/') >= 0) { + return BrowserType.OPERA; + } else if (typeof InstallTrigger !== 'undefined') { + return BrowserType.FIREFOX; + } else if (Object.toString.call(window.HTMLElement).indexOf('Constructor') > 0) { + return BrowserType.SAFARI; + } else if (/* @cc_on!@ */false || !!document.documentMode) { + return BrowserType.IE; + } else if (!!window.StyleMedia) { + return BrowserType.EDGE; + } else if (!!window.chrome && !!window.chrome.webstore) { + return BrowserType.CHROME; + } else if (((typeof isChrome !== 'undefined' && isChrome) + || (typeof isOpera !== 'undefined' && isOpera)) + && !!window.CSS + ) { + return BrowserType.BLINK; + } + + return BrowserType.UNKNOWN; + }; + + /** + * Get os. + * + * @return {string} + * + * @since 1.0.0 + */ + static getOS () + { + for (const os in OSType) { + if (Object.prototype.hasOwnProperty.call(OSType, os)) { + /** global: navigator */ + if (navigator.appVersion.toLowerCase().indexOf(OSType[os]) !== -1) { + return OSType[os]; + } + } + } + + return OSType.UNKNOWN; + }; +}; diff --git a/UI/Component/Form.js b/UI/Component/Form.js index 2ccab5f..4032541 100755 --- a/UI/Component/Form.js +++ b/UI/Component/Form.js @@ -118,9 +118,11 @@ export class Form } // don't overwrite existing bind + /* + @todo: removed because sometimes it is already bound but bound in a wrong way (e.g. no success is defined) if (Object.prototype.hasOwnProperty.call(this.forms, id)) { return; - } + }*/ this.forms[id] = new FormView(id); const self = this; @@ -817,6 +819,12 @@ export class Form ) { jsOMS.preventAll(event); self.submit(self.forms[id], self.forms[id].getSubmit()[elementIndex]); + } else if ((elementIndex = '')) { + // @todo: if table head input field in popups changes -> check if input empty -> deactivate -> checkbox : else activate checkbox + // careful: the same checkbox is used for showing the filter popup. maybe create a separate checkbox, which only handles the highlighting if filter is defined. + // this means popup active highlights filter icon AND different content checkbox also highlights filter + // -> two hiddin checkboxes are necessary (one is already implemented) + // Consider: It might make sense to do this in the Table.js??? Kinda depends on additional functionality together with the form probably. } // remote actions (maybe solvable with callbacks?): @@ -905,7 +913,10 @@ export class Form // select first input element (this allows fast consecutive data input) const firstFormInputElement = form.getFirstInputElement(); - firstFormInputElement.focus(); + + if (firstFormInputElement !== null) { + firstFormInputElement.focus(); + } }; /** @@ -950,14 +961,14 @@ export class Form const self = this; request.setData(data); - request.setType(RequestType.FORM_DATA); + request.setType(RequestType.FORM_DATA); // @todo: consider to allow different request type request.setUri(action ? action : form.getAction()); request.setMethod(form.getMethod()); request.setSuccess(function (xhr) { window.omsApp.logger.log(xhr.response); - if (xhr.getResponseHeader('content-type') === 'application/octet-stream') { + if (xhr.getResponseHeader('content-type').includes('application/octet-stream')) { const blob = new Blob([xhr.response], { type: 'application/octet-stream' }); const doc = document.createElement('a'); doc.style = 'display: none'; @@ -981,6 +992,17 @@ export class Form doc.click(); window.URL.revokeObjectURL(url); document.body.removeChild(doc); + } else if (xhr.getResponseHeader('content-type').includes('text/html')) { + // window.location = UriFactory.build(uri); + + document.documentElement.innerHTML = xhr.response; + /* This is not working as it reloads the page ?! + document.open(); + document.write(html); + document.close(); + */ + + window.omsApp.reInit(); // @todo: fix memory leak which most likely exists because of continous binding without removing binds } else { try { const o = JSON.parse(xhr.response)[0]; diff --git a/UI/Component/Tab.js b/UI/Component/Tab.js index 59e17e6..d0e519a 100755 --- a/UI/Component/Tab.js +++ b/UI/Component/Tab.js @@ -134,15 +134,15 @@ export class Tab if (fragLength > 0 && fragmentString !== '') { for (let i = 0; i < fragLength; ++i) { - const label = e.querySelectorAll('label[for="' + fragments[i] + '"]')[0]; - if (typeof label !== 'undefined') { + const label = e.querySelector('label[for="' + fragments[i] + '"]'); + if (typeof label !== 'undefined' && label !== null) { label.click(); } } } - if (e.getElementsByClassName('active').length < 1) { - e.querySelector('label').click(); + if (e.querySelector('.tab-links').querySelector('.active') === null) { + e.querySelector('.tab-links').querySelector('label').click(); } }; }; diff --git a/UI/GeneralUI.js b/UI/GeneralUI.js index 2cd9d94..3e392ab 100755 --- a/UI/GeneralUI.js +++ b/UI/GeneralUI.js @@ -67,6 +67,17 @@ export class GeneralUI const length = e.length; for (let i = 0; i < length; ++i) { + /* + @todo: bad solution, probably needs to be more navigation specific + const link = UriFactory.buildAbsolute( + e[i].getAttribute('href') !== null ? e[i].getAttribute('href') : e[i].getAttribute('data-href') + ); + + if (jsOMS.rtrim(link, '/') !== window.location.origin && window.location.href.startsWith(link)) { + jsOMS.addClass(e[i], 'active'); + } + */ + if (e[i].getAttribute('data-action') !== null) { continue; } @@ -86,10 +97,10 @@ export class GeneralUI } jsOMS.preventAll(event); - history.pushState(null, null, window.location); let uri = this.getAttribute('data-href'); uri = uri === null ? this.getAttribute('href') : uri; + history.pushState({}, null, UriFactory.build(uri)); if (this.getAttribute('target') === '_blank' || this.getAttribute(['data-target']) === '_blank' @@ -97,7 +108,23 @@ export class GeneralUI ) { window.open(UriFactory.build(uri), '_blank'); } else { - window.location = UriFactory.build(uri); + // window.location = UriFactory.build(uri); + + fetch(UriFactory.build(uri)) + .then((response) => response.text()) + .then((html) => { + document.documentElement.innerHTML = html; + /* This is not working as it reloads the page ?! + document.open(); + document.write(html); + document.close(); + */ + + window.omsApp.reInit(); // @todo: fix memory leak which most likely exists because of continous binding without removing binds + }) + .catch((error) => { + console.warn(error); + }); } }); } diff --git a/Uri/UriFactory.js b/Uri/UriFactory.js index 9eef658..388cb04 100755 --- a/Uri/UriFactory.js +++ b/Uri/UriFactory.js @@ -174,6 +174,17 @@ export class UriFactory return url; }; + static buildAbsolute (uri, toMatch = null) + { + if (uri.startsWith('/')) { + return UriFactory.build(window.location.origin + uri, toMatch); + } else if (uri.indexOf('://') === -1) { + return UriFactory.build(window.location.origin + '/' + uri, toMatch); + } + + return uri; + }; + /** * Build uri * diff --git a/Utils/Parser/Markdown.js b/Utils/Parser/Markdown.js index 688599c..4bd04c9 100755 --- a/Utils/Parser/Markdown.js +++ b/Utils/Parser/Markdown.js @@ -644,7 +644,7 @@ throw new Error('callback param is required'); } - if (!showdown.helper.isfunction (callback)) { + if (!showdown.helper.isFunction (callback)) { throw new Error('callback param must be a function/closure'); } @@ -826,7 +826,7 @@ showdown.helper.replaceRecursiveRegExp = function (str, replacement, left, right, flags) { 'use strict'; - if (!showdown.helper.isfunction (replacement)) { + if (!showdown.helper.isFunction (replacement)) { var repStr = replacement; replacement = function () { return repStr; diff --git a/Utils/UiUtils.js b/Utils/UiUtils.js index be964ae..c090eee 100755 --- a/Utils/UiUtils.js +++ b/Utils/UiUtils.js @@ -135,6 +135,7 @@ { event.preventDefault(); event.stopImmediatePropagation(); + event.stopPropagation(); event.cancelBubble = true; }; diff --git a/Utils/oLib.js b/Utils/oLib.js index 07b8089..b0cb22c 100755 --- a/Utils/oLib.js +++ b/Utils/oLib.js @@ -331,6 +331,7 @@ { event.preventDefault(); event.stopImmediatePropagation(); + event.stopPropagation(); event.cancelBubble = true; return false;