mirror of
https://github.com/Karaka-Management/jsOMS.git
synced 2026-01-11 17:58:41 +00:00
Create strong ui feature improvements
This commit is contained in:
parent
d9996c1d5a
commit
a525f6c881
|
|
@ -36,7 +36,7 @@
|
|||
|
||||
this.result[0] = function()
|
||||
{
|
||||
jsOMS.Log.Logger.instance.error('Invalid response code.');
|
||||
jsOMS.Log.Logger.instance.info('Unhandled response');
|
||||
};
|
||||
|
||||
/** global: XMLHttpRequest */
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
* @since 1.0.0
|
||||
*/
|
||||
const timerActionDelay = {};
|
||||
const timerAction = function (action, callback)
|
||||
const timerAction = function (action, callback, data)
|
||||
{
|
||||
"use strict";
|
||||
|
||||
|
|
@ -18,6 +18,6 @@ const timerAction = function (action, callback)
|
|||
|
||||
timerActionDelay[action.id] = setTimeout(function() {
|
||||
delete timerActionDelay[action.id];
|
||||
callback();
|
||||
callback(data);
|
||||
}, action.delay);
|
||||
};
|
||||
|
|
|
|||
235
UI/Component/AdvancedInput.js
Normal file
235
UI/Component/AdvancedInput.js
Normal file
|
|
@ -0,0 +1,235 @@
|
|||
/**
|
||||
* Advanced input class.
|
||||
*
|
||||
* @copyright Dennis Eichhorn
|
||||
* @license OMS License 1.0
|
||||
* @version 1.0.0
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @todo: this class is probably the most stupid thing I've done in a long time. Seriously fix this!
|
||||
* @todo: Passing self to every MEMBER function is just dumb.
|
||||
*/
|
||||
(function (jsOMS)
|
||||
{
|
||||
"use strict";
|
||||
|
||||
/** @namespace jsOMS.UI */
|
||||
jsOMS.Autoloader.defineNamespace('jsOMS.UI.Component');
|
||||
|
||||
jsOMS.UI.Component.AdvancedInput = class {
|
||||
/**
|
||||
* @constructor
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
constructor (e)
|
||||
{
|
||||
this.id = e.id;
|
||||
this.inputComponent = e;
|
||||
this.inputField = this.inputComponent.getElementsByClassName('input')[0];
|
||||
this.dropdownElement = document.getElementById(this.id + '-dropdown');
|
||||
this.tagElement = document.getElementById(this.id + '-tags');
|
||||
this.dataList = this.dropdownElement.getElementsByTagName('table')[0];
|
||||
this.dataListBody = this.dataList.getElementsByTagName('tbody')[0];
|
||||
this.dataTpl = document.getElementById(this.id + '-rowElement');
|
||||
this.tagTpl = this.tagElement.getElementsByTagName('template')[0];
|
||||
this.src = this.inputField.getAttribute('data-src');
|
||||
|
||||
const self = this;
|
||||
this.inputField.addEventListener('keydown', function(e) {
|
||||
if (e.keyCode === 13 || e.keyCode === 40) {
|
||||
jsOMS.preventAll(e);
|
||||
}
|
||||
|
||||
if (e.keyCode === 40) {
|
||||
self.selectOption(self.dataListBody.firstElementChild);
|
||||
} else {
|
||||
// handle change delay
|
||||
self.inputTimeDelay({id: self.id, delay: 300}, self.changeCallback, self, e);
|
||||
}
|
||||
});
|
||||
|
||||
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: dropdown should show/hide or depending on setting be always visible maybe with :focus+table or similar
|
||||
|
||||
if (e.keyCode === 27 || e.keyCode === 46 || e.keyCode === 8) {
|
||||
// handle esc, del to go back to input field
|
||||
self.inputField.focus();
|
||||
self.clearDataListSelection(self);
|
||||
} else if (e.keyCode === 38) {
|
||||
// handle up-click
|
||||
if (document.activeElement.previousElementSibling !== null) {
|
||||
self.clearDataListSelection(self);
|
||||
self.selectOption(document.activeElement.previousElementSibling);
|
||||
}
|
||||
} else if (e.keyCode === 40) {
|
||||
// handle down-click
|
||||
if (document.activeElement.nextElementSibling !== null) {
|
||||
self.clearDataListSelection(self);
|
||||
self.selectOption(document.activeElement.nextElementSibling);
|
||||
}
|
||||
} else if (e.keyCode === 13 || e.keyCode === 9) {
|
||||
self.clearDataListSelection(self);
|
||||
self.addToResultList(self);
|
||||
}
|
||||
});
|
||||
|
||||
this.dropdownElement.addEventListener('focusout', function(e){
|
||||
self.clearDataListSelection(self);
|
||||
});
|
||||
|
||||
this.dropdownElement.addEventListener('click', function(e) {
|
||||
if (document.activeElement.tagName.toLowerCase() !== 'tr') {
|
||||
return;
|
||||
}
|
||||
|
||||
self.clearDataListSelection(self);
|
||||
self.addToResultList(self);
|
||||
});
|
||||
};
|
||||
|
||||
remoteCallback(self, data)
|
||||
{
|
||||
data = JSON.parse(data.response);
|
||||
const dataLength = data.length;
|
||||
|
||||
console.table(data);
|
||||
|
||||
// if dropdown == true
|
||||
if (self.dropdownElement.getAttribute('data-active') === 'true') {
|
||||
while (self.dataListBody.firstChild) {
|
||||
self.dataListBody.removeChild(self.dataListBody.firstChild);
|
||||
}
|
||||
|
||||
for(let i = 0; i < dataLength; ++i) {
|
||||
// set readable value
|
||||
const newRow = self.dataTpl.content.cloneNode(true);
|
||||
let fields = newRow.querySelectorAll('[data-tpl-text]');
|
||||
let fieldLength = fields.length;
|
||||
|
||||
for (let j = 0; j < fieldLength; ++j) {
|
||||
fields[j].appendChild(
|
||||
document.createTextNode(
|
||||
jsOMS.getArray(fields[j].getAttribute('data-tpl-text'), data[i])
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// set internal value
|
||||
fields = newRow.querySelectorAll('[data-tpl-value]');
|
||||
fieldLength = fields.length;
|
||||
|
||||
for (let j = 0; j < fieldLength; ++j) {
|
||||
fields[j].setAttribute(
|
||||
'data-value',
|
||||
jsOMS.getArray(fields[j].getAttribute('data-tpl-value'), data[i])
|
||||
);
|
||||
}
|
||||
|
||||
self.dataListBody.appendChild(newRow);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
changeCallback(self, key)
|
||||
{
|
||||
// if remote data
|
||||
if (typeof self.src !== 'undefined' && self.src !== '') {
|
||||
const request = new jsOMS.Message.Request.Request(self.src);
|
||||
request.setSuccess(function (data) { self.remoteCallback(self, data); });
|
||||
request.send();
|
||||
}
|
||||
};
|
||||
|
||||
selectOption(e)
|
||||
{
|
||||
e.focus();
|
||||
// todo: change to set style .active
|
||||
e.setAttribute('style', 'background: #f00');
|
||||
jsOMS.addClass(e, 'active');
|
||||
};
|
||||
|
||||
clearDataListSelection(self)
|
||||
{
|
||||
const list = self.dataListBody.getElementsByTagName('tr'),
|
||||
length = list.length;
|
||||
|
||||
for (let i = 0; i < length; ++i) {
|
||||
// todo: remove the active class
|
||||
list[i].setAttribute('style', '');
|
||||
jsOMS.removeClass(list[i], 'active');
|
||||
}
|
||||
};
|
||||
|
||||
addToResultList(self) {
|
||||
if (self.inputField.getAttribute('data-autocomplete') === 'true') {
|
||||
self.inputField.value = document.activeElement.querySelectorAll('[data-tpl-value="' + self.inputField.getAttribute('data-value') + '"]')[0].getAttribute('data-value');
|
||||
}
|
||||
|
||||
if (self.tagElement.getAttribute('data-active') === 'true') {
|
||||
// todo: make badges removable
|
||||
const newTag = self.tagTpl.content.cloneNode(true);
|
||||
|
||||
// set internal value
|
||||
let fields = newTag.querySelectorAll('[data-tpl-value]');
|
||||
let fieldLength = fields.length;
|
||||
let uuid = '';
|
||||
let value = '';
|
||||
|
||||
for (let j = 0; j < fieldLength; ++j) {
|
||||
value = document.activeElement.querySelectorAll('[data-tpl-value="' + newTag.firstElementChild.getAttribute('data-tpl-value') + '"]')[0].getAttribute('data-value');
|
||||
fields[j].setAttribute('data-value', value);
|
||||
|
||||
uuid += value;
|
||||
}
|
||||
|
||||
// don't allow duplicate
|
||||
if (self.tagElement.querySelectorAll('[data-tpl-uuid="' + uuid + '"').length !== 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
newTag.firstElementChild.setAttribute('data-tpl-uuid', uuid);
|
||||
|
||||
// set readable text
|
||||
fields = newTag.querySelectorAll('[data-tpl-text]');
|
||||
fieldLength = fields.length;
|
||||
|
||||
for (let j = 0; j < fieldLength; ++j) {
|
||||
fields[j].appendChild(
|
||||
document.createTextNode(
|
||||
document.activeElement.querySelectorAll('[data-tpl-text="' + fields[j].getAttribute('data-tpl-text') + '"]')[0].innerText
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// allow limit
|
||||
if (self.tagElement.childElementCount >= self.tagElement.getAttribute('data-limit')
|
||||
&& self.tagElement.getAttribute('data-limit') != 0
|
||||
) {
|
||||
self.tagElement.removeChild(self.tagElement.firstElementChild);
|
||||
}
|
||||
|
||||
self.tagElement.appendChild(newTag);
|
||||
}
|
||||
};
|
||||
|
||||
inputTimeDelay(action, callback, self, data)
|
||||
{
|
||||
if (jsOMS.UI.Component.AdvancedInput.timerDelay[action.id]) {
|
||||
clearTimeout(jsOMS.UI.Component.AdvancedInput.timerDelay[action.id]);
|
||||
delete jsOMS.UI.Component.AdvancedInput.timerDelay[action.id]
|
||||
}
|
||||
|
||||
jsOMS.UI.Component.AdvancedInput.timerDelay[action.id] = setTimeout(function() {
|
||||
delete jsOMS.UI.Component.AdvancedInput.timerDelay[action.id];
|
||||
callback(self, data);
|
||||
}, action.delay);
|
||||
};
|
||||
}
|
||||
|
||||
jsOMS.UI.Component.AdvancedInput.timerDelay = {};
|
||||
}(window.jsOMS = window.jsOMS || {}));
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
/**
|
||||
* Autocomplete class.
|
||||
*
|
||||
* @copyright Dennis Eichhorn
|
||||
* @license OMS License 1.0
|
||||
* @version 1.0.0
|
||||
* @since 1.0.0
|
||||
*/
|
||||
(function (jsOMS)
|
||||
{
|
||||
"use strict";
|
||||
|
||||
/** @namespace jsOMS.UI */
|
||||
jsOMS.Autoloader.defineNamespace('jsOMS.UI.Component');
|
||||
}(window.jsOMS = window.jsOMS || {}));
|
||||
|
|
@ -14,6 +14,16 @@
|
|||
jsOMS.Autoloader.defineNamespace('jsOMS.UI.Input');
|
||||
|
||||
jsOMS.UI.Input = class {
|
||||
/**
|
||||
* @constructor
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
constructor ()
|
||||
{
|
||||
this.visObs = null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Unbind input element
|
||||
*
|
||||
|
|
@ -49,6 +59,7 @@
|
|||
|
||||
input.addEventListener('change', function changeBind(event)
|
||||
{
|
||||
console.log('ttttttt');
|
||||
/* Handle remote datalist/autocomplete input element */
|
||||
let listId, list;
|
||||
if (typeof (listId = this.getAttribute('list')) !== 'undefined' && (list = document.getElementById(listId)).getAttribute('data-list-src') !== 'undefined') {
|
||||
|
|
|
|||
|
|
@ -18,8 +18,9 @@
|
|||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
constructor ()
|
||||
constructor (app)
|
||||
{
|
||||
this.app = app;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -41,7 +42,7 @@
|
|||
}
|
||||
} else {
|
||||
const tabs = document.querySelectorAll('.tabview'),
|
||||
length = !tabs ? 0 : tabs.length;
|
||||
length = !tabs ? 0 : tabs.length;
|
||||
|
||||
for (let i = 0; i < length; ++i) {
|
||||
this.bindElement(tabs[i]);
|
||||
|
|
@ -52,7 +53,7 @@
|
|||
/**
|
||||
* Bind & rebind UI element.
|
||||
*
|
||||
* @param {Object} e Element id
|
||||
* @param {Object} e Element
|
||||
*
|
||||
* @return {void}
|
||||
*
|
||||
|
|
@ -60,23 +61,55 @@
|
|||
*/
|
||||
bindElement (e)
|
||||
{
|
||||
const nodes = e.querySelectorAll('.tab-links a');
|
||||
this.activateTabUri(e);
|
||||
|
||||
nodes.addEventListener('click', function (evt)
|
||||
{
|
||||
/* Change Tab */
|
||||
const attr = this.getAttribute('href').substring(1),
|
||||
cont = this.parentNode.parentNode.parentNode.children[1];
|
||||
const nodes = e.querySelectorAll('.tab-links li'),
|
||||
length = nodes.length;
|
||||
|
||||
jsOMS.removeClass(jsOMS.getByClass(this.parentNode.parentNode, 'active'), 'active');
|
||||
jsOMS.addClass(this.parentNode, 'active');
|
||||
jsOMS.removeClass(jsOMS.getByClass(cont, 'active'), 'active');
|
||||
jsOMS.addClass(jsOMS.getByClass(cont, attr), 'active');
|
||||
for (let i = 0; i < length; ++i) {
|
||||
nodes[i].addEventListener('click', function (evt)
|
||||
{
|
||||
let fragmentString = window.location.href.includes('#') ? jsOMS.Uri.Http.parseUrl(window.location.href).fragment : '';
|
||||
|
||||
/* Modify url */
|
||||
/* Change Tab */
|
||||
/* Remove selected tab */
|
||||
fragmentString = jsOMS.ltrim(fragmentString.replace(this.parentNode.getElementsByClassName('active')[0].getElementsByTagName('label')[0].getAttribute('for'), ''), ',');
|
||||
jsOMS.removeClass(this.parentNode.getElementsByClassName('active')[0], 'active');
|
||||
jsOMS.addClass(this, 'active');
|
||||
|
||||
jsOMS.preventAll(evt);
|
||||
});
|
||||
/* Add selected tab */
|
||||
window.history.pushState(null,'',
|
||||
jsOMS.Uri.UriFactory.build(
|
||||
'{%}#' + (fragmentString === '' ? '' : fragmentString + ',') + this.getElementsByTagName('label')[0].getAttribute('for')
|
||||
)
|
||||
);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Activates the correct tab based on URI fragment.
|
||||
*
|
||||
* This allows to link a specific open tab to a user or make it a bookmark
|
||||
*
|
||||
* @param {Object} e Element
|
||||
*
|
||||
* @return {void}
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
activateTabUri(e)
|
||||
{
|
||||
const fragmentString = window.location.href.includes('#') ? jsOMS.Uri.Http.parseUrl(window.location.href).fragment : '';
|
||||
const fragments = fragmentString.split(','),
|
||||
fragLength = fragments.length;
|
||||
|
||||
for (let i = 0; i < fragLength; ++i) {
|
||||
let label = e.querySelectorAll('label[for="' + fragments[i] + '"]')[0];
|
||||
if (typeof label !== 'undefined') {
|
||||
label.click();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}(window.jsOMS = window.jsOMS || {}));
|
||||
|
|
|
|||
|
|
@ -1,15 +0,0 @@
|
|||
/**
|
||||
* Form manager class.
|
||||
*
|
||||
* @copyright Dennis Eichhorn
|
||||
* @license OMS License 1.0
|
||||
* @version 1.0.0
|
||||
* @since 1.0.0
|
||||
*/
|
||||
(function (jsOMS)
|
||||
{
|
||||
"use strict";
|
||||
|
||||
/** @namespace jsOMS.UI */
|
||||
jsOMS.Autoloader.defineNamespace('jsOMS.UI.Component');
|
||||
}(window.jsOMS = window.jsOMS || {}));
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
/**
|
||||
* Form manager class.
|
||||
*
|
||||
* @copyright Dennis Eichhorn
|
||||
* @license OMS License 1.0
|
||||
* @version 1.0.0
|
||||
* @since 1.0.0
|
||||
*/
|
||||
(function (jsOMS)
|
||||
{
|
||||
"use strict";
|
||||
|
||||
/** @namespace jsOMS.UI */
|
||||
jsOMS.Autoloader.defineNamespace('jsOMS.UI.Component');
|
||||
}(window.jsOMS = window.jsOMS || {}));
|
||||
|
|
@ -36,12 +36,13 @@
|
|||
bind (id)
|
||||
{
|
||||
let e = null;
|
||||
if (typeof id !== 'undefined') {
|
||||
if (typeof id !== 'undefined' && id !== null) {
|
||||
e = document.getElementById(id);
|
||||
}
|
||||
|
||||
this.bindHref(e);
|
||||
this.bindLazyLoad(e);
|
||||
this.bindInput(e);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -102,5 +103,24 @@
|
|||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Bind & rebind UI element.
|
||||
*
|
||||
* @param {Object} [e] Element id
|
||||
*
|
||||
* @return {void}
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
bindInput (e)
|
||||
{
|
||||
e = e !== null ? [e] : document.getElementsByClassName('advancedInput');
|
||||
const length = e.length;
|
||||
|
||||
for (let i = 0; i < length; ++i) {
|
||||
new jsOMS.UI.Component.AdvancedInput(e[i]);
|
||||
}
|
||||
};
|
||||
}
|
||||
}(window.jsOMS = window.jsOMS || {}));
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@
|
|||
{
|
||||
this.app = app;
|
||||
this.formManager = new jsOMS.UI.Component.Form(this.app);
|
||||
this.tabManager = new jsOMS.UI.Component.Tab();
|
||||
this.tabManager = new jsOMS.UI.Component.Tab(this.app);
|
||||
this.tableManager = new jsOMS.UI.Component.Table(this.app);
|
||||
this.actionManager = new jsOMS.UI.ActionManager(this.app);
|
||||
this.dragNDrop = new jsOMS.UI.DragNDrop(this.app);
|
||||
|
|
|
|||
|
|
@ -123,6 +123,7 @@
|
|||
*/
|
||||
static unique (url)
|
||||
{
|
||||
// unique queries
|
||||
const parts = url.replace(/\?/g, '&').split('&'),
|
||||
full = parts[0];
|
||||
|
||||
|
|
@ -148,6 +149,28 @@
|
|||
url = full + '?' + pars.join('&');
|
||||
}
|
||||
|
||||
// unique fragments
|
||||
const fragments = url.match(/\#[a-zA-Z0-9\-,]+/g),
|
||||
fragLength = fragments !== null ? fragments.length : 0;
|
||||
|
||||
for (let i = 0; i < fragLength; ++i) {
|
||||
url = url.replace(fragments[i], '');
|
||||
}
|
||||
|
||||
if (fragLength > 0) {
|
||||
const fragList = fragments[fragLength - 1].split(','),
|
||||
fragListLength = fragList.length;
|
||||
let fragListNew = [];
|
||||
|
||||
for (let i = 0; i < fragListLength; ++i) {
|
||||
if (!fragListNew.includes(fragList[i]) && fragList[i] !== '') {
|
||||
fragListNew.push(fragList[i]);
|
||||
}
|
||||
}
|
||||
|
||||
url += fragListNew.join(',');
|
||||
}
|
||||
|
||||
return url;
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user