first commit
This commit is contained in:
@@ -0,0 +1,652 @@
|
||||
import './table.css';
|
||||
|
||||
import { Ut } from '../../utils/Ut';
|
||||
import { $, El, fillData } from '../../utils/dom';
|
||||
import { FormValidator } from '../../utils/form-validator/FormValidator';
|
||||
import { Rc } from '../../core/Rc';
|
||||
import { Render } from '../../core/Render';
|
||||
|
||||
export class Table {
|
||||
|
||||
static CLEAN = 0;
|
||||
static APPEND = 1;
|
||||
static PREPEND = 2;
|
||||
static UPDATE = 3;
|
||||
|
||||
/**
|
||||
* Table, Constructor
|
||||
*/
|
||||
constructor(target, caller, opts) {
|
||||
|
||||
this.target = target;
|
||||
this.caller = caller;
|
||||
|
||||
this.vars = new FormData();
|
||||
|
||||
this.reqOpts = {};
|
||||
|
||||
this.vars.set('pg', 1);
|
||||
|
||||
this.opts = { ... {
|
||||
layout : 'auto',
|
||||
filter : false,
|
||||
header : {},
|
||||
label : '%rows results',
|
||||
sortable : 0
|
||||
}, ... opts, ... opts.children };
|
||||
|
||||
this.rows = 0;
|
||||
this.setHeader = true;
|
||||
this.data = {};
|
||||
|
||||
if (!this.opts.header.cell || this.opts.display == 'none') {
|
||||
this.setHeader = false;
|
||||
}
|
||||
|
||||
this.makeUiTable();
|
||||
|
||||
if (this.opts.filter) { // create filter form
|
||||
this.makeFilterForm();
|
||||
}
|
||||
|
||||
if (Ut.isSet(this.opts.toolbar_header)) { // create toolbar header
|
||||
this.makeToolbarHeader();
|
||||
}
|
||||
|
||||
if (this.opts.label) { // create info label
|
||||
this.makeInfoLabel();
|
||||
}
|
||||
|
||||
this.makeNewTable();
|
||||
|
||||
this.makePagination();
|
||||
|
||||
if (Ut.isSet(this.opts.toolbar_footer)) { // create toolbar footer
|
||||
this.makeToolbarFooter();
|
||||
}
|
||||
|
||||
this.setMode(Table.CLEAN);
|
||||
|
||||
if ( Ut.isFn(caller) ) { // Data Mode
|
||||
this.makeRequest();
|
||||
}
|
||||
else {
|
||||
this.setTableData(caller);
|
||||
}
|
||||
|
||||
if (this.opts.sortable) {
|
||||
this.setSortable();
|
||||
}
|
||||
|
||||
Ut.trigger(this.opts.onInit, this);
|
||||
}
|
||||
|
||||
setMode(mode) {
|
||||
|
||||
this.mode = mode;
|
||||
|
||||
if (mode == Table.CLEAN) {
|
||||
this.id = 0;
|
||||
}
|
||||
}
|
||||
|
||||
setTableData(data) {
|
||||
|
||||
this.data = data;
|
||||
this.rows = parseInt(this.data.count);
|
||||
|
||||
this.updateInfoRows();
|
||||
|
||||
if (this.mode == Table.CLEAN) {
|
||||
|
||||
this.table.dxHtml('');
|
||||
|
||||
if (this.rows) {
|
||||
this.makeTableHead();
|
||||
}
|
||||
}
|
||||
|
||||
this.makeTableRows();
|
||||
|
||||
this.updatePagination();
|
||||
|
||||
Ut.trigger(this.opts.onUpdate, this);
|
||||
}
|
||||
|
||||
makeInfoLabel() {
|
||||
this.info = El('div', { class: 'sp-table-info' });
|
||||
this.ui.append(this.info);
|
||||
}
|
||||
|
||||
// Make UI container
|
||||
|
||||
makeUiTable() {
|
||||
this.ui = El('div', { class: 'sp-table-ui' });
|
||||
this.target.append(this.ui);
|
||||
}
|
||||
|
||||
// Make filter form
|
||||
|
||||
makeFilterForm() {
|
||||
|
||||
let that = this;
|
||||
|
||||
this.filterForm = El('form', { novalidate: true, class: 'sp-form filter-main' });
|
||||
|
||||
Render.makeUiElements(Ut.objVal(this.opts.filter).children, this.filterForm);
|
||||
|
||||
this.ui.append(this.filterForm);
|
||||
|
||||
this.filterForm.dxOn('changed clear', 'input[type="text"]', () => that.filterForm.dxTrigger('submit.form'));
|
||||
this.filterForm.dxOn('change', 'select, input[type="radio"], input[type="checkbox"]', () => that.filterForm.dxTrigger('submit.form'));
|
||||
|
||||
new FormValidator(this.filterForm, {
|
||||
|
||||
onInit: el => that.filterFormEl = el,
|
||||
onSubmit: function(vars) {
|
||||
|
||||
that.vars = vars;
|
||||
|
||||
that.vars.set('pg', 1);
|
||||
|
||||
that.setMode(Table.CLEAN);
|
||||
|
||||
that.makeRequest();
|
||||
}
|
||||
});
|
||||
|
||||
fillData(that.filterFormEl, this.vars);
|
||||
}
|
||||
|
||||
// Make header toolbar
|
||||
|
||||
makeToolbarHeader() {
|
||||
|
||||
this.toolbarHeader = El('div', { class: 'sp-toolbar toolbar-header' + (this.opts.toolbar_header.cls ? ' ' + this.opts.toolbar_header.cls : '') });
|
||||
|
||||
Render.makeUiElements(Ut.objVal(this.opts.toolbar_header).children, this.toolbarHeader);
|
||||
|
||||
this.ui.append( this.toolbarHeader );
|
||||
|
||||
Ut.trigger(this.opts.toolbarHeader, this);
|
||||
}
|
||||
|
||||
// Make Pagination Area
|
||||
|
||||
makePagination() {
|
||||
|
||||
this.paginationEl = this.ui.appendChild(El('div', { class: 'sp-pagination' }));
|
||||
|
||||
this.paginationEl.dxOn('click', 'a', (e, t) => {
|
||||
|
||||
this.vars.set('pg', t.dataset.id);
|
||||
|
||||
this.setMode(Table.CLEAN);
|
||||
|
||||
this.makeRequest();
|
||||
});
|
||||
|
||||
this.paginationEl.dxOn('click', 'a.btn-before', (_, t) => {
|
||||
|
||||
this.vars.set('before', this.data.before);
|
||||
this.vars.set('after', '');
|
||||
|
||||
this.setMode(Table.CLEAN);
|
||||
|
||||
this.makeRequest();
|
||||
});
|
||||
|
||||
this.paginationEl.dxOn('click', 'a.btn-after', function() {
|
||||
|
||||
this.vars.set('before', '');
|
||||
this.vars.set('after', this.data.after);
|
||||
|
||||
this.setMode(Table.CLEAN);
|
||||
|
||||
this.makeRequest();
|
||||
});
|
||||
}
|
||||
|
||||
// Make footer toolbar
|
||||
|
||||
makeToolbarFooter() {
|
||||
|
||||
this.toolbarFooter = El('div', { class: 'sp-toolbar toolbar-footer' + (this.opts.toolbar_footer.cls ? ' ' + this.opts.toolbar_footer.cls : '') });
|
||||
|
||||
Render.makeUiElements(Ut.objVal(this.opts.toolbar_footer).children, this.toolbarFooter);
|
||||
|
||||
this.ui.append(this.toolbarFooter);
|
||||
|
||||
Ut.trigger(this.opts.toolbarFooter, this);
|
||||
}
|
||||
|
||||
// Make new ui table
|
||||
|
||||
makeNewTable() {
|
||||
this.table = El('div', { class: 'sp-table layout-' + this.opts.layout + (!this.setHeader ? ' no-header' : '') + (this.opts.cls ? ' ' + this.opts.cls : '')});
|
||||
this.ui.append(this.table);
|
||||
}
|
||||
|
||||
// Make table head
|
||||
|
||||
makeTableHead() {
|
||||
|
||||
if (!this.setHeader) {
|
||||
return;
|
||||
}
|
||||
|
||||
let header = this.opts.header;
|
||||
|
||||
let thead = El('div', { class: 'thead' + (header.cls ? ' ' + header.cls : '') });
|
||||
|
||||
let n = 1;
|
||||
|
||||
for (; n < this.data.items[0].length; n++) {
|
||||
let cell = header.cell ? (header.cell[ n - 1 ] || {}) : {};
|
||||
thead.append( El('div', { class: 'th' + (cell.cls ? ' ' + cell.cls : '') }, (cell.text || '') ) );
|
||||
}
|
||||
|
||||
this.table.prepend(thead);
|
||||
}
|
||||
|
||||
// Make table rows
|
||||
|
||||
makeTableRows() {
|
||||
|
||||
let that = this;
|
||||
|
||||
if (this.mode == Table.UPDATE) {
|
||||
|
||||
let row = this.getRow(this.id);
|
||||
|
||||
if (row) {
|
||||
|
||||
row.dxHtml('');
|
||||
|
||||
let data = this.data.items[0];
|
||||
|
||||
let n = 1;
|
||||
|
||||
for (; n < data.length; n++) {
|
||||
|
||||
let cell = that.opts.header.cell ? (that.opts.header.cell[ n - 1 ] || {}) : {};
|
||||
|
||||
let column = El('div', { class: 't-col' });
|
||||
|
||||
row.append( El('div', { class: 'td' + (cell.cls ? ' ' + cell.cls : ''), 'data-label': cell.text },
|
||||
column
|
||||
));
|
||||
|
||||
if (data[n]) {
|
||||
column.dxHtml(data[n]);
|
||||
}
|
||||
|
||||
if (n == 1 && that.opts.sortable) {
|
||||
column.classList.add('flex', 'v-center');
|
||||
column.prepend( El('i', { class: 'handle' }) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
this.data.items.forEach((data, i) => {
|
||||
|
||||
let tbody = El('div', {
|
||||
class: 'tbody' + (that.opts.body && that.opts.body.cls ? ' ' + that.opts.body.cls : ''),
|
||||
'data-id': data[0],
|
||||
'data-pos': i
|
||||
});
|
||||
|
||||
let n = 1;
|
||||
|
||||
for (; n < data.length; n++) {
|
||||
|
||||
let cell = that.opts.header.cell ? (that.opts.header.cell[ n - 1 ] || {}) : {};
|
||||
|
||||
let column = El('div', { class: 't-col' });
|
||||
|
||||
tbody.append( El('div', { class: 'td' + (cell.cls ? ' ' + cell.cls : ''), 'data-label': cell.text },
|
||||
column
|
||||
));
|
||||
|
||||
if (data[n]) {
|
||||
column.dxHtml(data[n]);
|
||||
}
|
||||
|
||||
if (n == 1 && that.opts.sortable) {
|
||||
column.classList.add('flex', 'v-center');
|
||||
column.prepend( El('i', { class: 'handle' }) );
|
||||
}
|
||||
|
||||
if (that.mode == Table.PREPEND) {
|
||||
that.table.prepend(tbody);
|
||||
}
|
||||
else {
|
||||
that.table.append(tbody);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Set info rows
|
||||
|
||||
updateInfoRows() {
|
||||
this.setInfo(this.opts.label.replace(/%rows/g, this.rows));
|
||||
}
|
||||
|
||||
// XHR Request
|
||||
|
||||
makeRequest() {
|
||||
|
||||
let that = this;
|
||||
|
||||
let vars = {};
|
||||
|
||||
if (this.mode == Table.UPDATE) {
|
||||
vars.id = this.id;
|
||||
}
|
||||
else {
|
||||
vars = this.vars;
|
||||
vars.set('id', 0);
|
||||
}
|
||||
|
||||
this.reqOpts.vars = vars;
|
||||
|
||||
this.caller(this.reqOpts).then(jr => {
|
||||
|
||||
if (jr.code != Rc.DONE) {
|
||||
that.setInfo('No Data');
|
||||
return;
|
||||
}
|
||||
|
||||
that.setTableData(jr.data);
|
||||
|
||||
}).catch(error => console.error(error));
|
||||
}
|
||||
|
||||
// Set ui sortable
|
||||
|
||||
setSortable() {
|
||||
|
||||
let that = this,
|
||||
isHandle = false,
|
||||
toDrag;
|
||||
|
||||
let isBefore = function(a, b) {
|
||||
if (a.parentNode == b.parentNode) {
|
||||
for (let cur = a; cur; cur = cur.previousSibling) {
|
||||
if (cur === b) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
this.table.dxOn('mousedown mouseup', 'i.handle', function(e) {
|
||||
|
||||
let parent = this.dxParents('.tbody');
|
||||
|
||||
if (e.type == 'mousedown') {
|
||||
isHandle = true;
|
||||
parent.setAttribute('draggable', true);
|
||||
}
|
||||
else {
|
||||
isHandle = false;
|
||||
parent.removeAttribute('draggable');
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
this.table.dxOn('dragenter', '.tbody', function(e) {
|
||||
|
||||
if (!isHandle) {
|
||||
return;
|
||||
}
|
||||
|
||||
let target = this.matches('.tbody') ? this : this.dxParents('.tbody');
|
||||
|
||||
if (isBefore( toDrag, target )) {
|
||||
target.before(toDrag);
|
||||
}
|
||||
else {
|
||||
|
||||
if (target.nextElementSibling === null) {
|
||||
$('.sp-table').append( toDrag );
|
||||
}
|
||||
else {
|
||||
target.nextElementSibling.before(toDrag);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
this.table.dxOn('dragstart', '.tbody', function(e) {
|
||||
|
||||
if (!isHandle) {
|
||||
return;
|
||||
}
|
||||
|
||||
toDrag = this;
|
||||
|
||||
e.dataTransfer.setData('text/plain', null);
|
||||
e.dataTransfer.effectAllowed = 'move';
|
||||
|
||||
toDrag.style.opacity = 0.4;
|
||||
});
|
||||
|
||||
this.table.dxOn('dragend', '.tbody', function(e) {
|
||||
|
||||
if (!isHandle) {
|
||||
return;
|
||||
}
|
||||
|
||||
isHandle = false;
|
||||
|
||||
let onSort = false;
|
||||
|
||||
toDrag.style.opacity = '';
|
||||
toDrag.removeAttribute('draggable');
|
||||
|
||||
let data = {};
|
||||
|
||||
that.table.dxFind('.tbody', (el, i) => {
|
||||
|
||||
if (el.dataset.pos != i && !onSort) {
|
||||
onSort = true;
|
||||
}
|
||||
|
||||
if (el.dataset.pos != i) {
|
||||
|
||||
data[ el.dataset.id ] = i;
|
||||
|
||||
el.dataset.pos = i;
|
||||
}
|
||||
});
|
||||
|
||||
if (onSort) {
|
||||
Ut.trigger(that.opts.onSort, that, data);
|
||||
onSort = false;
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
// Update pagination area
|
||||
|
||||
updatePagination() {
|
||||
|
||||
this.paginationEl.dxHtml('');
|
||||
|
||||
if (this.data.pagination && this.data.pagination.count > 1) {
|
||||
|
||||
let pg_btns = [],
|
||||
pg_btn,
|
||||
j = 0;
|
||||
|
||||
if (this.data.pagination.start > 1) {
|
||||
|
||||
pg_btns[j] = [
|
||||
1, '<<', false
|
||||
];
|
||||
|
||||
j = 1;
|
||||
}
|
||||
|
||||
for (let i = this.data.pagination.start; i <= this.data.pagination.end; i++) {
|
||||
|
||||
pg_btns[j] = [
|
||||
i, i, (this.vars.get('pg') == i)
|
||||
]
|
||||
|
||||
j++;
|
||||
}
|
||||
|
||||
if (this.data.pagination.start > 1 && this.data.pagination.page != this.data.pagination.end) {
|
||||
pg_btns[j] = [
|
||||
this.data.pagination.count, '>>', false
|
||||
];
|
||||
}
|
||||
|
||||
pg_btns.forEach((dat) => {
|
||||
|
||||
pg_btn = El('a', {
|
||||
'data-id': dat[0],
|
||||
class: (dat[2] ? 'disabled' : '')}, dat[1]
|
||||
);
|
||||
|
||||
this.paginationEl.append(pg_btn);
|
||||
});
|
||||
}
|
||||
else if (this.data.before || this.data.after) { // update UI
|
||||
|
||||
if (this.data.before) {
|
||||
this.paginationEl.append( El('a', { 'data-id': this.data.before, class: 'btn-before' }, '<') );
|
||||
}
|
||||
|
||||
if (this.data.after) {
|
||||
this.paginationEl.append( El('a', { 'data-id': this.data.after, class: 'btn-after' }, '>') );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get All Rows
|
||||
|
||||
getRows(id) {
|
||||
return this.table.dxFind('.tbody');
|
||||
}
|
||||
|
||||
// Get Row By ID
|
||||
|
||||
getRow(id) {
|
||||
return this.table.dxFind('.tbody[data-id="'+ id +'"]');
|
||||
}
|
||||
|
||||
// Update Row Data
|
||||
|
||||
updateRow(id, data) {
|
||||
|
||||
this.setMode(Table.UPDATE);
|
||||
this.id = id;
|
||||
|
||||
if (data) {
|
||||
this.setTableData(data);
|
||||
}
|
||||
else {
|
||||
this.makeRequest();
|
||||
}
|
||||
}
|
||||
|
||||
// Update All Rows
|
||||
|
||||
update(data) {
|
||||
|
||||
this.setMode(Table.CLEAN);
|
||||
|
||||
if (data) {
|
||||
this.setTableData(data);
|
||||
}
|
||||
else {
|
||||
this.makeRequest();
|
||||
}
|
||||
}
|
||||
|
||||
// Delete Row
|
||||
|
||||
deleteRow(id) {
|
||||
|
||||
let row = this.getRow(id);
|
||||
|
||||
if (row) {
|
||||
|
||||
this.rows--;
|
||||
this.updateInfoRows();
|
||||
|
||||
row.remove();
|
||||
|
||||
if (!this.rows) {
|
||||
|
||||
let pg = this.vars.get('pg');
|
||||
|
||||
if (pg > 1) {
|
||||
this.vars.set('pg', --pg);
|
||||
}
|
||||
|
||||
this.update();
|
||||
}
|
||||
|
||||
Ut.trigger(this.opts.onUpdate, this);
|
||||
}
|
||||
}
|
||||
|
||||
// Add Row At The End of the table
|
||||
|
||||
appendRow(data) {
|
||||
|
||||
this.setMode(this.table.children.length ? Table.APPEND : Table.CLEAN);
|
||||
|
||||
if (data) {
|
||||
this.setTableData(data);
|
||||
}
|
||||
else {
|
||||
this.makeRequest();
|
||||
}
|
||||
}
|
||||
|
||||
// Add Row At Begining of the table
|
||||
|
||||
prependRow(data) {
|
||||
|
||||
this.setMode(this.table.children.length ? Table.APPEND : Table.CLEAN);
|
||||
|
||||
if (data) {
|
||||
this.setTableData(data);
|
||||
}
|
||||
else {
|
||||
this.makeRequest();
|
||||
}
|
||||
}
|
||||
|
||||
// Set Info Table
|
||||
|
||||
setInfo(text) {
|
||||
this.info.textContent = text;
|
||||
};
|
||||
|
||||
// Set Toolbar Header
|
||||
|
||||
setHeaderToolbar(content) {
|
||||
this.toolbarHeader.dxHtml(content);
|
||||
}
|
||||
|
||||
// Set Toolbar Footer
|
||||
|
||||
setFooterToolbar(content) {
|
||||
this.toolbarFooter.dxHtml(content);
|
||||
}
|
||||
}
|
||||
|
||||
//Ut.extendNodeUx(Table);
|
||||
Reference in New Issue
Block a user