|
@@ -0,0 +1,670 @@
|
|
|
|
|
+class TableHeader {
|
|
|
|
|
+ constructor(columns) {
|
|
|
|
|
+ this.columns = columns;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ render() {
|
|
|
|
|
+ const tr = document.createElement('tr');
|
|
|
|
|
+ const colgroup = document.createElement('colgroup');
|
|
|
|
|
+ this.columns.forEach((column) => {
|
|
|
|
|
+ const th = document.createElement('th');
|
|
|
|
|
+ const col = document.createElement('col');
|
|
|
|
|
+ th.setAttribute('data-column', column.column);
|
|
|
|
|
+ col.setAttribute('data-column', column.column);
|
|
|
|
|
+ th.innerHTML = column.label;
|
|
|
|
|
+ tr.appendChild(th);
|
|
|
|
|
+ colgroup.appendChild(col);
|
|
|
|
|
+ });
|
|
|
|
|
+ const thead = document.createElement('thead');
|
|
|
|
|
+ thead.appendChild(tr);
|
|
|
|
|
+
|
|
|
|
|
+ return {colgroup : colgroup, thead : thead };
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+class ActionSet {
|
|
|
|
|
+
|
|
|
|
|
+ arrowDown = '<i class="fa fa-arrow-down" aria-hidden="true"></i>';
|
|
|
|
|
+
|
|
|
|
|
+ constructor(actions, element = 'button', value = null) {
|
|
|
|
|
+ this.actions = actions;
|
|
|
|
|
+ this.element = element;
|
|
|
|
|
+ this.value = value;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ render() {
|
|
|
|
|
+ if (this.element == 'button') {
|
|
|
|
|
+ return this.renderButton();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (this.element == 'span') {
|
|
|
|
|
+ return this.renderSpan();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ renderButton() {
|
|
|
|
|
+ this.actionButton = document.createElement('a');
|
|
|
|
|
+ this.actionButton.classList.add('btn', 'btn-outline-secondary');
|
|
|
|
|
+ this.actionButton.innerHTML = `<i class="fa fa-${this.actions[0].icon}" aria-hidden="true"></i> ${this.actions[0].label}`;
|
|
|
|
|
+ this.actionButton.href = this.actions[0].route.replace('{{id}}', this.value);
|
|
|
|
|
+
|
|
|
|
|
+ if (this.actions.length == 1) {
|
|
|
|
|
+ return { 'button': this.actionButton, 'toggle': null, 'list': null };
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ this.actionToggle = document.createElement('button');
|
|
|
|
|
+ this.actionToggle.classList.add('btn', 'btn-outline-secondary', 'dropdown-toggle-split');
|
|
|
|
|
+ this.actionToggle.innerHTML = this.arrowDown;
|
|
|
|
|
+ this.actionToggle.setAttribute('data-bs-toggle', 'dropdown');
|
|
|
|
|
+
|
|
|
|
|
+ this.actionList = document.createElement('ul');
|
|
|
|
|
+ this.actionList.classList.add('dropdown-menu');
|
|
|
|
|
+
|
|
|
|
|
+ this.actions.forEach((action) => {
|
|
|
|
|
+ const actionHolder = document.createElement('li');
|
|
|
|
|
+ const actionLink = document.createElement('a');
|
|
|
|
|
+ actionLink.classList.add('dropdown-item');
|
|
|
|
|
+ actionLink.href = action.route.replace('{{id}}', this.value);
|
|
|
|
|
+ actionLink.innerHTML = `<i class="fa fa-${action.icon}" aria-hidden="true"></i> ${action.label}`;
|
|
|
|
|
+
|
|
|
|
|
+ actionHolder.appendChild(actionLink);
|
|
|
|
|
+ this.actionList.appendChild(actionHolder);
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ return {
|
|
|
|
|
+ 'button': this.actionButton,
|
|
|
|
|
+ 'toggle': this.actionToggle,
|
|
|
|
|
+ 'list': this.actionList
|
|
|
|
|
+ };
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ renderSpan() {
|
|
|
|
|
+ this.actionButton = document.createElement('div');
|
|
|
|
|
+
|
|
|
|
|
+ this.actionToggle = document.createElement('span');
|
|
|
|
|
+ this.actionToggle.setAttribute('data-bs-toggle', 'dropdown');
|
|
|
|
|
+ this.actionToggle.innerHTML = `#${this.value} ${this.arrowDown}`;
|
|
|
|
|
+
|
|
|
|
|
+ this.actionList = document.createElement('ul');
|
|
|
|
|
+ this.actionList.classList.add('dropdown-menu');
|
|
|
|
|
+
|
|
|
|
|
+ this.actions.forEach((action) => {
|
|
|
|
|
+ const actionHolder = document.createElement('li');
|
|
|
|
|
+ if(action.type == 'divider'){
|
|
|
|
|
+ const actionDivider = document.createElement('hr');
|
|
|
|
|
+ actionDivider.classList.add('dropdown-divider');
|
|
|
|
|
+ this.actionList.appendChild(actionDivider);
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ const actionLink = document.createElement('a');
|
|
|
|
|
+ actionLink.classList.add('dropdown-item');
|
|
|
|
|
+ actionLink.href = action.route.replace('{{id}}', this.value);
|
|
|
|
|
+ actionLink.innerHTML = `<i class="fa fa-${action.icon}" aria-hidden="true"></i> ${action.label}`;
|
|
|
|
|
+
|
|
|
|
|
+ actionHolder.appendChild(actionLink);
|
|
|
|
|
+ this.actionList.appendChild(actionHolder);
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ this.actionButton.appendChild(this.actionToggle);
|
|
|
|
|
+ this.actionButton.appendChild(this.actionList);
|
|
|
|
|
+
|
|
|
|
|
+ return this.actionButton;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ renderLabel(label, icon){
|
|
|
|
|
+ if(icon){
|
|
|
|
|
+ return `<i class="fa fa-${icon}" aria-hidden="true"></i> ${label}`
|
|
|
|
|
+ }
|
|
|
|
|
+ return label
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+class TableBody {
|
|
|
|
|
+ constructor(rows, columns, rowActions, options) {
|
|
|
|
|
+ this.rows = rows;
|
|
|
|
|
+ this.columns = columns;
|
|
|
|
|
+ this.rowActions = rowActions;
|
|
|
|
|
+ this.options = options;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ render() {
|
|
|
|
|
+ if(this.options.selectable){
|
|
|
|
|
+ return this.renderSelectable();
|
|
|
|
|
+ }
|
|
|
|
|
+ return this.renderDefaultTable();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ renderDefaultTable(){
|
|
|
|
|
+ const tbody = document.createElement('tbody');
|
|
|
|
|
+
|
|
|
|
|
+ this.rows.forEach((row) => {
|
|
|
|
|
+ const tr = document.createElement('tr');
|
|
|
|
|
+
|
|
|
|
|
+ this.columns.forEach((column) => {
|
|
|
|
|
+ const td = document.createElement('td');
|
|
|
|
|
+ td.setAttribute('data-name', column.column);
|
|
|
|
|
+ td.setAttribute('data-value', row[column.column]);
|
|
|
|
|
+
|
|
|
|
|
+ if (column.column == 'id') {
|
|
|
|
|
+ tr.setAttribute('data-value', row[column.column]);
|
|
|
|
|
+ const idColumn = new ActionSet(this.rowActions, 'span', row[column.column]);
|
|
|
|
|
+ td.appendChild(idColumn.render());
|
|
|
|
|
+ } else {
|
|
|
|
|
+ td.innerHTML = row[column.column];
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ tr.appendChild(td);
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ tbody.appendChild(tr);
|
|
|
|
|
+
|
|
|
|
|
+ });
|
|
|
|
|
+ return tbody;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ renderSelectable(){
|
|
|
|
|
+ const tbody = document.createElement('tbody');
|
|
|
|
|
+
|
|
|
|
|
+ this.rows.forEach((row) => {
|
|
|
|
|
+ const tr = document.createElement('tr');
|
|
|
|
|
+
|
|
|
|
|
+ this.columns.forEach((column) => {
|
|
|
|
|
+ const td = document.createElement('td');
|
|
|
|
|
+ td.setAttribute('data-name', column.column);
|
|
|
|
|
+ td.setAttribute('data-value', row[column.column]);
|
|
|
|
|
+
|
|
|
|
|
+ if (column.column == 'id') {
|
|
|
|
|
+ tr.setAttribute('data-value', row[column.column]);
|
|
|
|
|
+ const idColumn = document.createElement('button');
|
|
|
|
|
+
|
|
|
|
|
+ let payload = {'element': row, ...this.options.selectable.callbackParameters};
|
|
|
|
|
+
|
|
|
|
|
+ idColumn.addEventListener('click', this.options.selectable.select.bind(null, payload));
|
|
|
|
|
+ idColumn.classList.add('btn', 'btn-danger', 'btn-block');
|
|
|
|
|
+ idColumn.style = "padding: 0.1rem 0.5em;";
|
|
|
|
|
+ idColumn.innerHTML = 'Selecionar';
|
|
|
|
|
+ td.appendChild(idColumn);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ td.innerHTML = row[column.column];
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ tr.appendChild(td);
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ tbody.appendChild(tr);
|
|
|
|
|
+
|
|
|
|
|
+ });
|
|
|
|
|
+ return tbody;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+class Buttons {
|
|
|
|
|
+ constructor(currentPage, totalPages, maxButtons, onPageChange, replicateChanges) {
|
|
|
|
|
+ this.currentPage = currentPage;
|
|
|
|
|
+ this.totalPages = totalPages;
|
|
|
|
|
+ this.maxButtons = maxButtons;
|
|
|
|
|
+ this.onPageChange = onPageChange;
|
|
|
|
|
+ this.replicateChanges = replicateChanges;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ render() {
|
|
|
|
|
+ console.log('adssaddas');
|
|
|
|
|
+ this.buttonHolder = document.createElement('div');
|
|
|
|
|
+ this.buttonHolder.classList.add('col-12', 'col-md-9');
|
|
|
|
|
+
|
|
|
|
|
+ this.paginationButtons = document.createElement('ul');
|
|
|
|
|
+ this.paginationButtons.classList.add('pagination', 'pagination-sm');
|
|
|
|
|
+
|
|
|
|
|
+ this.prevButton = document.createElement('li');
|
|
|
|
|
+ this.prevButton.classList.add('page-link');
|
|
|
|
|
+ this.prevButton.textContent = 'Previous';
|
|
|
|
|
+ this.prevButton.disabled = true;
|
|
|
|
|
+ this.prevButton.addEventListener('click', () => {
|
|
|
|
|
+ if (this.currentPage > 1) {
|
|
|
|
|
+ this.onPageChange(this.currentPage - 1);
|
|
|
|
|
+ this.updateButtons(this.currentPage - 1);
|
|
|
|
|
+ this.replicateChanges(this.currentPage);
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ this.paginationButtons.appendChild(this.prevButton);
|
|
|
|
|
+ this.pageButtons = Array();
|
|
|
|
|
+
|
|
|
|
|
+ for (let i = 1; i <= this.totalPages; i++) {
|
|
|
|
|
+ const pageButton = document.createElement('li');
|
|
|
|
|
+ pageButton.classList.add('page-item');
|
|
|
|
|
+ const pageButtonLink = document.createElement('a');
|
|
|
|
|
+ pageButtonLink.classList.add('page-link');
|
|
|
|
|
+ pageButtonLink.textContent = i;
|
|
|
|
|
+ if (!(this.currentPage === i ||
|
|
|
|
|
+ i > (this.currentPage + this.maxButtons / 2) ||
|
|
|
|
|
+ i < (this.currentPage - this.maxButtons / 2))) {
|
|
|
|
|
+ pageButton.classList.add('hidden');
|
|
|
|
|
+ }
|
|
|
|
|
+ if(this.currentPage === i){
|
|
|
|
|
+ pageButton.classList.add('active');
|
|
|
|
|
+ }
|
|
|
|
|
+ pageButtonLink.addEventListener('click', () => {
|
|
|
|
|
+ this.onPageChange(i);
|
|
|
|
|
+ this.updateButtons(i);
|
|
|
|
|
+ this.replicateChanges(this.currentPage);
|
|
|
|
|
+ });
|
|
|
|
|
+ pageButton.appendChild(pageButtonLink);
|
|
|
|
|
+ this.pageButtons.push(pageButton);
|
|
|
|
|
+ this.paginationButtons.appendChild(pageButton);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ this.nextButton = document.createElement('li');
|
|
|
|
|
+ this.nextButton.classList.add('page-link');
|
|
|
|
|
+ this.nextButton.textContent = 'Next';
|
|
|
|
|
+ this.nextButton.disabled = this.totalPages === 0 || this.currentPage === this.totalPages;
|
|
|
|
|
+ this.nextButton.addEventListener('click', () => {
|
|
|
|
|
+ if (this.currentPage < this.totalPages) {
|
|
|
|
|
+ this.onPageChange(this.currentPage + 1);
|
|
|
|
|
+ this.updateButtons(this.currentPage + 1);
|
|
|
|
|
+ this.replicateChanges(this.currentPage);
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ this.paginationButtons.appendChild(this.nextButton);
|
|
|
|
|
+ this.buttonHolder.appendChild(this.paginationButtons);
|
|
|
|
|
+
|
|
|
|
|
+ return this.buttonHolder;
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ updateButtons(page, perPage) {
|
|
|
|
|
+
|
|
|
|
|
+ if (page) {
|
|
|
|
|
+ this.currentPage = parseInt(page);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (this.prevButton) {
|
|
|
|
|
+ this.prevButton.disabled = this.currentPage === 1;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (this.nextButton) {
|
|
|
|
|
+ this.nextButton.disabled = this.totalPages === 0 || this.currentPage === this.totalPages;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (this.pageButtons) {
|
|
|
|
|
+ this.pageButtons.forEach((button, index) => {
|
|
|
|
|
+ button.classList.remove('active');
|
|
|
|
|
+ if (this.currentPage === index + 1 ||
|
|
|
|
|
+ index > (this.currentPage + this.maxButtons / 2) ||
|
|
|
|
|
+ index < (this.currentPage - this.maxButtons / 2)) {
|
|
|
|
|
+ button.classList.add('hidden');
|
|
|
|
|
+ }else {
|
|
|
|
|
+ button.classList.remove('hidden');
|
|
|
|
|
+ }
|
|
|
|
|
+ if (index + 1 == this.currentPage) {
|
|
|
|
|
+ button.classList.add('active');
|
|
|
|
|
+ button.classList.remove('hidden');
|
|
|
|
|
+ } else {
|
|
|
|
|
+ button.removeAttribute('value');
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+class Label {
|
|
|
|
|
+ constructor(actualPage, totalPages, recordsCount, totalRecords) {
|
|
|
|
|
+ this.actualPage = actualPage;
|
|
|
|
|
+ this.totalPages = totalPages;
|
|
|
|
|
+ this.recordsCount = recordsCount;
|
|
|
|
|
+ this.totalRecords = totalRecords;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ render(){
|
|
|
|
|
+ this.paginationLabel = document.createElement('div');
|
|
|
|
|
+ this.paginationLabel.classList.add('col-12');
|
|
|
|
|
+
|
|
|
|
|
+ this.pageLabel = document.createElement('span');
|
|
|
|
|
+ this.pageLabel.innerText = `Page: ${this.actualPage} of ${this.totalPages} | `;
|
|
|
|
|
+
|
|
|
|
|
+ this.recordLabel = document.createElement('span');
|
|
|
|
|
+ this.recordLabel.innerText = `${this.recordsCount} of ${this.totalRecords} records shown`;
|
|
|
|
|
+
|
|
|
|
|
+ this.paginationLabel.appendChild(this.pageLabel);
|
|
|
|
|
+ this.paginationLabel.appendChild(this.recordLabel);
|
|
|
|
|
+
|
|
|
|
|
+ return this.paginationLabel;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ rerender() {
|
|
|
|
|
+ this.pageLabel.innerText = `Page: ${this.actualPage} of ${this.totalPages} | `;
|
|
|
|
|
+ this.recordLabel.innerText = `${this.recordsCount} of ${this.totalRecords} records shown`;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ updateLabel(page, perPage, totalPages){
|
|
|
|
|
+ this.actualPage = page;
|
|
|
|
|
+ this.perPage = perPage;
|
|
|
|
|
+ this.rerender();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+class Search {
|
|
|
|
|
+
|
|
|
|
|
+ constructor(currentPage, totalPages, onPageChange, replicateChanges){
|
|
|
|
|
+ this.currentPage = currentPage;
|
|
|
|
|
+ this.totalPages = totalPages;
|
|
|
|
|
+ this.onPageChange = onPageChange;
|
|
|
|
|
+ this.replicateChanges = replicateChanges;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ render(){
|
|
|
|
|
+
|
|
|
|
|
+ const paginationHolder = document.createElement('div');
|
|
|
|
|
+ paginationHolder.classList.add('col-12', 'col-md-3');
|
|
|
|
|
+
|
|
|
|
|
+ this.paginationSearch = document.createElement('div');
|
|
|
|
|
+ this.paginationSearch.classList.add('search', 'input-group','col-md-3', 'col-sm-12');
|
|
|
|
|
+
|
|
|
|
|
+ this.textualNumber = document.createElement('input');
|
|
|
|
|
+ this.textualNumber.classList.add('form-control', 'form-control-sm');
|
|
|
|
|
+ this.textualNumber.setAttribute('type', 'number');
|
|
|
|
|
+ this.textualNumber.setAttribute('min', 1);
|
|
|
|
|
+ this.textualNumber.setAttribute('max', this.totalPages);
|
|
|
|
|
+ this.textualNumber.value = this.currentPage;
|
|
|
|
|
+
|
|
|
|
|
+ this.textualNumber.addEventListener('blur', (event) => {
|
|
|
|
|
+ let page = event.target.value;
|
|
|
|
|
+ if(page > this.totalPages){
|
|
|
|
|
+ page = this.totalPages;
|
|
|
|
|
+ this.textualNumber.value = this.totalPages;
|
|
|
|
|
+ }
|
|
|
|
|
+ if(page < 1){
|
|
|
|
|
+ page = 1;
|
|
|
|
|
+ this.textualNumber.value = page;
|
|
|
|
|
+ }
|
|
|
|
|
+ this.replicateChanges(page);
|
|
|
|
|
+ this.onPageChange(page);
|
|
|
|
|
+ });
|
|
|
|
|
+ this.textualNumber.addEventListener('keydown', (event) => {
|
|
|
|
|
+ if (event.key === 'Enter') {
|
|
|
|
|
+ console.log('reberberbrte');
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ //this.paginationSearch.appendChild(this.textualNumber);
|
|
|
|
|
+ this.append(this.textualNumber);
|
|
|
|
|
+
|
|
|
|
|
+ this.selectNumber = document.createElement('select');
|
|
|
|
|
+ this.selectNumber.classList.add('form-select', 'form-select-sm');
|
|
|
|
|
+ for(let i = 1; i < this.totalPages; i++){
|
|
|
|
|
+ const selectOption = document.createElement('option');
|
|
|
|
|
+ selectOption.innerText = i;
|
|
|
|
|
+ selectOption.setAttribute('value', i);
|
|
|
|
|
+ this.selectNumber.appendChild(selectOption);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ this.selectNumber.addEventListener('change', (event) => {
|
|
|
|
|
+ this.replicateChanges(event.target.value);
|
|
|
|
|
+ this.onPageChange(event.target.value);
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ //this.paginationSearch.appendChild(this.selectNumber);
|
|
|
|
|
+ this.append(this.selectNumber);
|
|
|
|
|
+
|
|
|
|
|
+ const recordsPerPage = document.createElement('select');
|
|
|
|
|
+ recordsPerPage.classList.add('form-select', 'form-select-sm');
|
|
|
|
|
+ for(let i = 1; i < 10; i++){
|
|
|
|
|
+ const selectOption = document.createElement('option');
|
|
|
|
|
+ selectOption.innerText = i * 25;
|
|
|
|
|
+ selectOption.setAttribute('value', i * 25);
|
|
|
|
|
+ recordsPerPage.appendChild(selectOption);
|
|
|
|
|
+ }
|
|
|
|
|
+ recordsPerPage.addEventListener('change', (event) => {
|
|
|
|
|
+ //console.log(event.target.value)
|
|
|
|
|
+ //this.replicateChanges(event.target.value);
|
|
|
|
|
+ });
|
|
|
|
|
+ //this.paginationSearch.appendChild(recordsPerPage);
|
|
|
|
|
+ this.append(recordsPerPage);
|
|
|
|
|
+
|
|
|
|
|
+ paginationHolder.appendChild(this.paginationSearch);
|
|
|
|
|
+
|
|
|
|
|
+ return paginationHolder;
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ updateSearch(pageNumber, perPage) {
|
|
|
|
|
+ this.selectNumber.value = pageNumber;
|
|
|
|
|
+ this.textualNumber.value = pageNumber;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ searchChange(){
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ append(element){
|
|
|
|
|
+ let container = document.createElement('div');
|
|
|
|
|
+ container.classList.add('col-4');
|
|
|
|
|
+ container.appendChild(element);
|
|
|
|
|
+ this.paginationSearch.appendChild(container);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+class Pagination {
|
|
|
|
|
+ constructor(onPageChange, rowCount, perPage) {
|
|
|
|
|
+ this.currentPage = 1;
|
|
|
|
|
+ this.maxButtons = 10;
|
|
|
|
|
+ this.onPageChange = onPageChange;
|
|
|
|
|
+ this.rowCount = rowCount;
|
|
|
|
|
+ this.perPage = perPage;
|
|
|
|
|
+ this.totalPages = Math.ceil(rowCount / perPage);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ render() {
|
|
|
|
|
+ this.paginationContainer = document.createElement('div');
|
|
|
|
|
+ this.paginationContainer.classList.add('pagination', 'row');
|
|
|
|
|
+
|
|
|
|
|
+ if(this.totalPages <= 1){
|
|
|
|
|
+ return this.paginationContainer;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ this.labels = new Label(this.currentPage, this.totalPages, 10, 1000);
|
|
|
|
|
+
|
|
|
|
|
+ this.buttons = new Buttons(this.currentPage, this.totalPages, 10, this.onPageChange, (page) => {
|
|
|
|
|
+ this.labels.updateLabel(page, this.perPage);
|
|
|
|
|
+ this.search.updateSearch(page, this.perPage);
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ this.search = new Search(this.currentPage, this.totalPages, this.onPageChange, (page, size) => {
|
|
|
|
|
+ this.labels.updateLabel(page, this.perPage);
|
|
|
|
|
+ this.buttons.updateButtons(page, this.perPage);
|
|
|
|
|
+ this.search.updateSearch(page, this.perPage);
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ this.paginationContainer.appendChild(this.labels.render());
|
|
|
|
|
+ this.paginationContainer.appendChild(this.buttons.render());
|
|
|
|
|
+ this.paginationContainer.appendChild(this.search.render());
|
|
|
|
|
+
|
|
|
|
|
+ return this.paginationContainer;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ changePageSize(onPageChange, rowCount, perPage) {
|
|
|
|
|
+ this.currentPage = 1;
|
|
|
|
|
+ this.maxButtons = 10;
|
|
|
|
|
+ this.onPageChange = onPageChange;
|
|
|
|
|
+ this.rowCount = rowCount;
|
|
|
|
|
+ this.perPage = perPage;
|
|
|
|
|
+ this.totalPages = Math.ceil(rowCount / perPage);
|
|
|
|
|
+
|
|
|
|
|
+ return this.paginationContainer;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+class ListButton{
|
|
|
|
|
+ constructor(icon, actions){
|
|
|
|
|
+ this.icon = icon;
|
|
|
|
|
+ this.actions = actions;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ render() {
|
|
|
|
|
+ this.actionButton = document.createElement('button');
|
|
|
|
|
+ this.actionButton.classList.add('btn', 'btn-outline-secondary');
|
|
|
|
|
+ this.actionButton.innerHTML = `<i class="fa fa-${this.icon}" aria-hidden="true"></i>`;
|
|
|
|
|
+
|
|
|
|
|
+ return this.actionButton;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+class SearchBar {
|
|
|
|
|
+ constructor(onSearch) {
|
|
|
|
|
+ this.onSearch = onSearch;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ render() {
|
|
|
|
|
+ this.searchBarContainer = document.createElement('div');
|
|
|
|
|
+ this.searchBarContainer.classList.add('search-bar');
|
|
|
|
|
+
|
|
|
|
|
+ this.inputElement = document.createElement('input');
|
|
|
|
|
+ this.inputElement.classList.add('form-control');
|
|
|
|
|
+ this.inputElement.setAttribute('type', 'text');
|
|
|
|
|
+ this.inputElement.addEventListener('keydown', (event) => {
|
|
|
|
|
+ if (event.key === 'Enter') {
|
|
|
|
|
+ this.searchText = this.inputElement.value;
|
|
|
|
|
+ this.onSearch(this.searchText);
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ this.searchBarContainer.appendChild(this.inputElement);
|
|
|
|
|
+
|
|
|
|
|
+ return this.searchBarContainer;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ getSearch(){
|
|
|
|
|
+ return this.inputElement.value;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+class ToolBar {
|
|
|
|
|
+ constructor(onSearch, actions, options) {
|
|
|
|
|
+ this.onSearch = onSearch;
|
|
|
|
|
+ this.actions = actions;
|
|
|
|
|
+ this.options = options;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ render() {
|
|
|
|
|
+ this.toolbar = document.createElement('div');
|
|
|
|
|
+ this.toolbar.classList.add('input-group', 'mb-3');
|
|
|
|
|
+
|
|
|
|
|
+ if (typeof this.actions !== 'undefined' && typeof this.options.selectable === 'undefined' && this.actions.length > 0) {
|
|
|
|
|
+
|
|
|
|
|
+ this.actionSet = new ActionSet(this.actions, 'button');
|
|
|
|
|
+ let { button, toggle, list } = this.actionSet.render();
|
|
|
|
|
+
|
|
|
|
|
+ if (button) {
|
|
|
|
|
+ this.toolbar.appendChild(button);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (toggle) {
|
|
|
|
|
+ this.toolbar.appendChild(toggle);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (list) {
|
|
|
|
|
+ this.toolbar.append(list);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ this.searchBar = new SearchBar(this.onSearch);
|
|
|
|
|
+ this.toolbar.appendChild(this.searchBar.render());
|
|
|
|
|
+ this.toolbar.appendChild(new ListButton('th', '').render());
|
|
|
|
|
+ return this.toolbar;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ getSearch() {
|
|
|
|
|
+ return this.searchBar.getSearch();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+class DataTable {
|
|
|
|
|
+
|
|
|
|
|
+ constructor(tableElement, options = {}) {
|
|
|
|
|
+ if (typeof tableElement === 'string') {
|
|
|
|
|
+ this.tableElement = document.getElementById(tableElement);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ this.tableElement = tableElement;
|
|
|
|
|
+ }
|
|
|
|
|
+ this.page = 1;
|
|
|
|
|
+ this.options = options;
|
|
|
|
|
+ this.perPage = 25;
|
|
|
|
|
+ this.getData();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ render(data) {
|
|
|
|
|
+ const { actions, rowActions, columns, rows, total } = data;
|
|
|
|
|
+ this.table = document.createElement('table');
|
|
|
|
|
+ this.table.classList.add('table', 'table-responsive');
|
|
|
|
|
+
|
|
|
|
|
+ this.searchBar = new ToolBar((searchText) => {
|
|
|
|
|
+ this.getData(searchText);
|
|
|
|
|
+ }, actions, this.options);
|
|
|
|
|
+
|
|
|
|
|
+ this.pagination = new Pagination((page, perPage) => {
|
|
|
|
|
+ this.page = page--;
|
|
|
|
|
+ //this.perPage = perPage;
|
|
|
|
|
+ this.getData();
|
|
|
|
|
+ }, total, this.perPage);
|
|
|
|
|
+
|
|
|
|
|
+ this.headerElement = new TableHeader(columns);
|
|
|
|
|
+ const tableHeader = this.headerElement.render();
|
|
|
|
|
+ this.table.appendChild(tableHeader.colgroup);
|
|
|
|
|
+ this.table.appendChild(tableHeader.thead);
|
|
|
|
|
+
|
|
|
|
|
+ this.bodyElement = new TableBody(rows, columns, rowActions, this.options);
|
|
|
|
|
+ this.table.appendChild(this.bodyElement.render());
|
|
|
|
|
+
|
|
|
|
|
+ // #ToDo Convert table to div
|
|
|
|
|
+ if (this.tableElement.tagName === 'TABLE') {
|
|
|
|
|
+ const divContainer = document.createElement('div');
|
|
|
|
|
+ while (this.tableElement.firstChild) {
|
|
|
|
|
+ divContainer.appendChild(this.tableElement.firstChild);
|
|
|
|
|
+ }
|
|
|
|
|
+ this.tableElement.parentNode.replaceChild(divContainer, this.tableElement);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ this.tableElement.appendChild(this.searchBar.render());
|
|
|
|
|
+ this.tableElement.appendChild(this.pagination.render());
|
|
|
|
|
+ this.tableElement.appendChild(this.table);
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ rerender(data) {
|
|
|
|
|
+ const { columns, rows, rowActions, total } = data;
|
|
|
|
|
+
|
|
|
|
|
+ if (!this.table) {
|
|
|
|
|
+ this.render(data);
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const content = new TableBody(rows, columns, rowActions, this.options).render();
|
|
|
|
|
+ this.table.querySelector('tbody').innerHTML = content.innerHTML;
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ async getData() {
|
|
|
|
|
+
|
|
|
|
|
+ let requestBody = {
|
|
|
|
|
+ 'page': this.page - 1,
|
|
|
|
|
+ 'pageSize': this.perPage
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ if(this.searchBar){
|
|
|
|
|
+ requestBody.search = this.searchBar.getSearch();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const params = new URLSearchParams(requestBody).toString();
|
|
|
|
|
+ const response = await fetch(this.options.url + '?' + params);
|
|
|
|
|
+ const data = await response.json();
|
|
|
|
|
+ this.rerender(data);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+export { DataTable as default };
|