added ui state manager

This commit is contained in:
Dennis Eichhorn 2022-04-10 00:18:16 +02:00
parent 301f73fda5
commit 928bad0e41
10 changed files with 311 additions and 101 deletions

View File

@ -83,18 +83,20 @@ export class Form
{ {
if (id !== null && typeof this.ignore[id] === 'undefined') { if (id !== null && typeof this.ignore[id] === 'undefined') {
this.bindForm(id); this.bindForm(id);
} else {
const forms = document.querySelectorAll('form, [data-tag=form]');
const length = !forms ? 0 : forms.length;
for (let i = 0; i < length; ++i) { return;
const formId = forms[i].getAttribute('id'); }
if (typeof formId !== 'undefined' && formId !== null && typeof this.ignore[formId] === 'undefined') { const forms = document.querySelectorAll('form, [data-tag=form]');
this.bindForm(formId); const length = !forms ? 0 : forms.length;
} else {
Logger.instance.info('A form doesn\'t have an ID.'); for (let i = 0; i < length; ++i) {
} const formId = forms[i].getAttribute('id');
if (typeof formId !== 'undefined' && formId !== null && typeof this.ignore[formId] === 'undefined') {
this.bindForm(formId);
} else {
Logger.instance.info('A form doesn\'t have an ID.');
} }
} }
}; };
@ -188,11 +190,11 @@ export class Form
: formElement.querySelector(uiContainerName); : formElement.querySelector(uiContainerName);
/** @var {HTMLElement} newElement New element to add */ /** @var {HTMLElement} newElement New element to add */
const newElement = uiContainer.querySelector('.add-tpl').content.cloneNode(true); const newElement = uiContainer.querySelector('.oms-add-tpl').content.cloneNode(true);
// set random id for element // set random id for element
/** @var {string} eleId New element id */ /** @var {string} eleId New element id */
const eleId = Form.setRandomIdForTemplateElement(newElement); const eleId = Form.setRandomIdForElement(newElement.firstElementChild);
// If the new element has a form it should also receive a id // If the new element has a form it should also receive a id
if (newElement.firstElementChild.getElementsByTagName('form').length > 0) { if (newElement.firstElementChild.getElementsByTagName('form').length > 0) {
@ -266,7 +268,7 @@ export class Form
); );
// set random id for element // set random id for element
Form.setRandomIdForTemplateElement(newElements[i]); Form.setRandomIdForElement(newElements[i].firstElementChild);
} }
/** @var {object} remoteUrls Texts and values which come from remote sources */ /** @var {object} remoteUrls Texts and values which come from remote sources */
@ -492,7 +494,7 @@ export class Form
newElement.push(document.querySelector(updatableTpl[i]).content.cloneNode(true)); newElement.push(document.querySelector(updatableTpl[i]).content.cloneNode(true));
Form.setRandomIdForTemplateElement(newElement[i]); Form.setRandomIdForElement(newElement[i].firstElementChild);
} }
const fields = []; const fields = [];
@ -903,17 +905,17 @@ export class Form
}; };
/** /**
* Set random id of a template element * Set random data-id of a element
* *
* @param {HTMLElement} templateElement Element to set the id for * @param {HTMLElement} element Element to set the data-id for
* *
* @return {string} * @return {string}
* *
* @since 1.0.0 * @since 1.0.0
*/ */
static setRandomIdForTemplateElement (templateElement) static setRandomIdForElement (element)
{ {
if (templateElement.firstElementChild.getAttribute('data-id') !== null) { if (element.getAttribute('data-id') !== null && element.getAttribute('data-id') !== '') {
return; return;
} }
@ -923,7 +925,7 @@ export class Form
eleId = 'r-' + Math.random().toString(36).substring(7); eleId = 'r-' + Math.random().toString(36).substring(7);
} while (document.querySelector('[data-id="' + eleId + '"]') !== null); } while (document.querySelector('[data-id="' + eleId + '"]') !== null);
templateElement.firstElementChild.setAttribute('data-id', eleId); element.setAttribute('data-id', eleId);
return eleId; return eleId;
}; };
@ -934,7 +936,9 @@ export class Form
const length = data.length; const length = data.length;
const templateLength = elements.length; const templateLength = elements.length;
for (let i = 0; i < length; ++i) { for (let i = 0; i < length; ++i) {
const path = data[i].hasAttribute('data-tpl-' + type + '-path') ? data[i].getAttribute('data-tpl-' + type + '-path') : null; const path = data[i].hasAttribute('data-tpl-' + type + '-path')
? data[i].getAttribute('data-tpl-' + type + '-path')
: null;
for (let j = 0; j < templateLength; ++j) { for (let j = 0; j < templateLength; ++j) {
// sometimes elements contains templates, they need to get handled differently // sometimes elements contains templates, they need to get handled differently
@ -981,7 +985,9 @@ export class Form
const length = data.length; const length = data.length;
for (let i = 0; i < length; ++i) { for (let i = 0; i < length; ++i) {
const matches = self.forms[formId].getFormElement().querySelectorAll('[data-tpl-' + type + '="' + data[i].getAttribute('data-tpl-' + type) + '"'); const matches = self.forms[formId].getFormElement().querySelectorAll('[data-tpl-' + type + '="' + data[i].getAttribute('data-tpl-' + type) + '"');
const path = data[i].hasAttribute('data-tpl-' + type + '-path') ? data[i].getAttribute('data-tpl-' + type + '-path') : null; const path = data[i].hasAttribute('data-tpl-' + type + '-path')
? data[i].getAttribute('data-tpl-' + type + '-path')
: null;
const matchLength = matches.length; const matchLength = matches.length;
for (let c = 0; c < matchLength; ++c) { for (let c = 0; c < matchLength; ++c) {

View File

@ -40,13 +40,15 @@ export class Tab
if (e) { if (e) {
this.bindElement(e); this.bindElement(e);
} }
} else {
const tabs = document.getElementsByClassName('tabview');
const length = !tabs ? 0 : tabs.length;
for (let i = 0; i < length; ++i) { return;
this.bindElement(tabs[i]); }
}
const tabs = document.getElementsByClassName('tabview');
const length = !tabs ? 0 : tabs.length;
for (let i = 0; i < length; ++i) {
this.bindElement(tabs[i]);
} }
}; };

View File

@ -63,52 +63,39 @@ export class Table
{ {
if (id !== null && typeof this.ignore[id] === 'undefined') { if (id !== null && typeof this.ignore[id] === 'undefined') {
this.bindTable(id); this.bindTable(id);
} else {
const tables = document.getElementsByTagName('table');
const length = !tables ? 0 : tables.length;
for (let i = 0; i < length; ++i) { return;
const tableId = tables[i].getAttribute('id'); }
if (typeof tableId !== 'undefined' && tableId !== null && typeof this.ignore[tableId] === 'undefined') {
this.bindTable(tableId); const tables = document.getElementsByTagName('table');
} const length = !tables ? 0 : tables.length;
for (let i = 0; i < length; ++i) {
const tableId = tables[i].getAttribute('id');
if (typeof tableId !== 'undefined' && tableId !== null && typeof this.ignore[tableId] === 'undefined') {
this.bindTable(tableId);
} }
} }
}; };
/**
* Unbind table
*
* @param {string} id Table Id
*
* @return {void}
*
* @since 1.0.0
*/
unbind (id)
{
};
/** /**
* Bind & rebind UI element. * Bind & rebind UI element.
* *
* @param {Object} [id] Element id * @param {Object} id Element id
* *
* @return {void} * @return {void}
* *
* @since 1.0.0 * @since 1.0.0
*/ */
bindTable (id) bindTable (id = null)
{ {
if (typeof id === 'undefined' || !id) { if (id === null) {
jsOMS.Log.Logger.instance.info('A table doesn\'t have an ID.'); jsOMS.Log.Logger.instance.info('A table doesn\'t have an ID.');
return; return;
} }
this.tables[id] = new TableView(id); this.tables[id] = new TableView(id);
this.unbind(id);
this.bindExport(this.tables[id]); this.bindExport(this.tables[id]);
/** /**

View File

@ -36,7 +36,7 @@ export class DragNDrop
if (element !== null) { if (element !== null) {
this.bindElement(element); this.bindElement(element);
} else { } else {
const elements = document.querySelectorAll('.dragcontainer'); const elements = document.querySelectorAll('.oms-dragcontainer');
const length = !elements ? 0 : elements.length; const length = !elements ? 0 : elements.length;
for (let i = 0; i < length; ++i) { for (let i = 0; i < length; ++i) {
@ -71,12 +71,12 @@ export class DragNDrop
}, false); }, false);
element.addEventListener('dragenter', function (e) { element.addEventListener('dragenter', function (e) {
const thisElement = e.target.closest('.dragcontainer ' + this.children[this.children.length - 1].tagName); const thisElement = e.target.closest('.oms-dragcontainer ' + this.children[this.children.length - 1].tagName);
const rowIndex = Array.from(this.children).indexOf(thisElement); const rowIndex = Array.from(this.children).indexOf(thisElement);
const dragIndex = Array.from(self.dragging.children).indexOf(self.dragging); const dragIndex = Array.from(self.dragging.children).indexOf(self.dragging);
const oldPlaceholder = this.querySelector('.drag-placeholder'); const oldPlaceholder = this.querySelector('.oms-drag-placeholder');
if (oldPlaceholder !== null) { if (oldPlaceholder !== null) {
this.removeChild(oldPlaceholder); this.removeChild(oldPlaceholder);
} }
@ -91,7 +91,7 @@ export class DragNDrop
placeholder.setAttribute('draggable', 'true'); placeholder.setAttribute('draggable', 'true');
jsOMS.addClass(placeholder, 'drag-placeholder'); jsOMS.addClass(placeholder, 'oms-drag-placeholder');
if (dragIndex < rowIndex) { if (dragIndex < rowIndex) {
this.insertBefore(placeholder, thisElement.nextSibling); this.insertBefore(placeholder, thisElement.nextSibling);
@ -113,7 +113,7 @@ export class DragNDrop
element.addEventListener('dragend', function (e) { element.addEventListener('dragend', function (e) {
e.preventDefault(); e.preventDefault();
const oldPlaceholder = this.querySelector('.drag-placeholder'); const oldPlaceholder = this.querySelector('.oms-drag-placeholder');
if (oldPlaceholder === null) { if (oldPlaceholder === null) {
return; return;
} }

View File

@ -1 +0,0 @@
/* responsible for loading external ui elements (css,html,js) */

View File

@ -29,17 +29,19 @@ export class Order
* *
* @since 1.0.0 * @since 1.0.0
*/ */
bind (element) bind (element = null)
{ {
if (typeof element !== 'undefined') { if (element !== null) {
this.bindElement(element); this.bindElement(element);
} else {
const elements = document.querySelectorAll('.ordercontainer');
const length = !elements ? 0 : elements.length;
for (let i = 0; i < length; ++i) { return;
this.bindElement(elements[i]); }
}
const elements = document.querySelectorAll('.oms-ordercontainer');
const length = !elements ? 0 : elements.length;
for (let i = 0; i < length; ++i) {
this.bindElement(elements[i]);
} }
}; };
@ -68,7 +70,7 @@ export class Order
jsOMS.preventAll(event); jsOMS.preventAll(event);
const rowLength = element.children.length; const rowLength = element.children.length;
const thisElement = event.target.closest('.ordercontainer ' + this.children[rowLength - 1].tagName); const thisElement = event.target.closest('.oms-ordercontainer ' + this.children[rowLength - 1].tagName);
const rowId = Array.from(element.children).indexOf(thisElement); const rowId = Array.from(element.children).indexOf(thisElement);
const orderType = jsOMS.hasClass(event.target, 'order-up') ? 1 : -1; const orderType = jsOMS.hasClass(event.target, 'order-up') ? 1 : -1;

85
UI/RemoteData.js Normal file
View File

@ -0,0 +1,85 @@
/**
* Remote data class.
*
* @copyright Dennis Eichhorn
* @license OMS License 1.0
* @version 1.0.0
* @since 1.0.0
*/
export class RemoteData
{
/**
* @constructor
*
* @param {Object} app Application
*
* @since 1.0.0
*/
constructor (app)
{
this.app = app;
};
/**
* Bind element
*
* @param {Object} [element] DOM element
*
* @return {void}
*
* @since 1.0.0
*/
bind (element = null)
{
if (element !== null) {
this.bindElement(element);
return;
}
const elements = document.querySelectorAll('.oms-remotecontainer');
const length = !elements ? 0 : elements.length;
for (let i = 0; i < length; ++i) {
this.bindElement(elements[i]);
}
};
/**
* Bind DOM element
*
* @param {Element} element DOM element
*
* @return {void}
*
* @since 1.0.0
*/
bindElement (element)
{
if (!element) {
return;
}
element.addEventListener('click', function (event) {
if (!jsOMS.hasClass(event.target, 'order-up')
&& !jsOMS.hasClass(event.target, 'order-down')
) {
return;
}
jsOMS.preventAll(event);
const rowLength = element.children.length;
const thisElement = event.target.closest('.ordercontainer ' + this.children[rowLength - 1].tagName);
const rowId = Array.from(element.children).indexOf(thisElement);
const orderType = jsOMS.hasClass(event.target, 'order-up') ? 1 : -1;
if (orderType === 1 && rowId > 0) {
element.insertBefore(element.children[rowId], element.children[rowId - 1]);
} else if (orderType === -1 && rowId < rowLength) {
element.insertBefore(element.children[rowId], element.children[rowId + 2]);
}
}, false);
}
};

View File

@ -1,10 +1,12 @@
import { Form } from '../UI/Component/Form.js'; import { Form } from './Component/Form.js';
import { Tab } from '../UI/Component/Tab.js'; import { Tab } from './Component/Tab.js';
import { Table } from '../UI/Component/Table.js'; import { Table } from './Component/Table.js';
import { ActionManager } from '../UI/ActionManager.js'; import { ActionManager } from './ActionManager.js';
import { DragNDrop } from '../UI/DragNDrop.js'; import { DragNDrop } from './DragNDrop.js';
import { Order } from '../UI/Order.js'; import { Order } from './Order.js';
import { GeneralUI } from '../UI/GeneralUI.js'; import { RemoteData } from './RemoteData.js';
import { GeneralUI } from './GeneralUI.js';
import { UIStateManager } from './UIStateManager.js';
/** /**
* UI manager for handling basic ui elements. * UI manager for handling basic ui elements.
@ -25,14 +27,16 @@ export class UIManager
*/ */
constructor (app) constructor (app)
{ {
this.app = app; this.app = app;
this.formManager = new Form(this.app); this.formManager = new Form(this.app);
this.tabManager = new Tab(this.app); this.tabManager = new Tab(this.app);
this.tableManager = new Table(this.app); this.tableManager = new Table(this.app);
this.actionManager = new ActionManager(this.app); this.actionManager = new ActionManager(this.app);
this.dragNDrop = new DragNDrop(this.app); this.dragNDrop = new DragNDrop(this.app);
this.order = new Order(this.app); this.order = new Order(this.app);
this.generalUI = new GeneralUI(this.app); this.generalUI = new GeneralUI(this.app);
this.remoteData = new RemoteData(this.app);
this.uiStateManager = new UIStateManager(this.app);
const self = this; const self = this;
/** global: MutationObserver */ /** global: MutationObserver */
@ -54,9 +58,9 @@ export class UIManager
* *
* @since 1.0.0 * @since 1.0.0
*/ */
bind (id) bind (id = null)
{ {
if (typeof id === 'undefined') { if (id === null) {
this.formManager.bind(); this.formManager.bind();
this.tabManager.bind(); this.tabManager.bind();
this.tableManager.bind(); this.tableManager.bind();
@ -64,24 +68,28 @@ export class UIManager
this.dragNDrop.bind(); this.dragNDrop.bind();
this.order.bind(); this.order.bind();
this.generalUI.bind(); this.generalUI.bind();
} else { this.remoteData.bind();
const tag = document.getElementById(id); this.uiStateManager.bind();
this.generalUI.bind(tag);
if (!tag) { return;
return; }
}
switch (tag.tagName) { const tag = document.getElementById(id);
case 'form': this.generalUI.bind(tag);
this.formManager.bind(id);
break; if (!tag) {
case 'table': return;
this.tableManager.bind(id); }
break;
default: switch (tag.tagName) {
this.actionManager.bind(tag); case 'form':
} this.formManager.bind(id);
break;
case 'table':
this.tableManager.bind(id);
break;
default:
this.actionManager.bind(tag);
} }
}; };
@ -133,6 +141,30 @@ export class UIManager
return this.order; return this.order;
}; };
/**
* Get remote data manager.
*
* @return {Object}
*
* @since 1.0.0
*/
getRemoteData ()
{
return this.remoteData;
};
/**
* Get remote data manager.
*
* @return {Object}
*
* @since 1.0.0
*/
getUIStatemanager ()
{
return this.uiStateManager;
};
/** /**
* Get tab manager. * Get tab manager.
* *

97
UI/UIStateManager.js Normal file
View File

@ -0,0 +1,97 @@
/**
* UI state manager class.
*
* @copyright Dennis Eichhorn
* @license OMS License 1.0
* @version 1.0.0
* @since 1.0.0
*/
export class UIStateManager
{
/**
* @constructor
*
* @param {Object} app Application
*
* @since 1.0.0
*/
constructor (app)
{
this.app = app;
};
/**
* Bind element
*
* @param {Object} [element] DOM element
*
* @return {void}
*
* @since 1.0.0
*/
bind (element = null)
{
if (element !== null) {
this.bindElement(element);
return;
}
const elements = document.querySelectorAll('.oms-ui-state');
const length = !elements ? 0 : elements.length;
for (let i = 0; i < length; ++i) {
this.bindElement(elements[i]);
}
};
/**
* Bind DOM element
*
* @param {Element} element DOM element
*
* @return {void}
*
* @since 1.0.0
*/
bindElement (element)
{
if (!element) {
return;
}
let state = JSON.parse(window.localStorage.getItem('ui-state-' + element.id));
state = state !== null ? state : {};
switch (element.tagName.toLowerCase()) {
case 'input':
if (state === '1') {
element.click();
}
element.addEventListener('change', function (event) {
if (this.getAttribute('type') === 'checkbox'
|| this.getAttribute('type') === 'radio'
) {
window.localStorage.setItem('ui-state-' + this.id, JSON.stringify('1'));
} else {
window.localStorage.setItem('ui-state-' + this.id, JSON.stringify(this.value));
}
});
break;
case 'div':
// @todo: this is not working, WHY? state is correct, but element.scrollTop is just ignored?!
element.scrollLeft = state.x;
element.scrollTop = state.y;
element.addEventListener('scroll', function () {
window.localStorage.setItem('ui-state-' + this.id, JSON.stringify({x: this.scrollLeft, y: this.scrollTop}));
});
break;
default:
break;
}
};
};