async table js utility now with explicit selector

This commit is contained in:
Felix Hamann 2019-04-08 21:06:09 +02:00
parent c654f3d6ab
commit 8b1fae2856
2 changed files with 82 additions and 107 deletions

View File

@ -6,15 +6,14 @@
* Async Table Utility * Async Table Utility
* makes table filters, sorting and pagination behave asynchronously via AJAX calls * makes table filters, sorting and pagination behave asynchronously via AJAX calls
* *
* Attribute: [none] * Attribute: uw-async-table
* (will be set up automatically on tables)
* *
* Example usage: * Example usage:
* (regular table) * (regular table)
*/ */
var ASYNC_TABLE_UTIL_NAME = 'asyncTable'; var ASYNC_TABLE_UTIL_NAME = 'asyncTable';
var ASYNC_TABLE_UTIL_SELECTOR = 'table'; var ASYNC_TABLE_UTIL_SELECTOR = '[uw-async-table]';
var ASYNC_TABLE_LOCAL_STORAGE_KEY = 'ASYNC_TABLE'; var ASYNC_TABLE_LOCAL_STORAGE_KEY = 'ASYNC_TABLE';
@ -33,16 +32,12 @@
var asyncTableUtil = function(element) { var asyncTableUtil = function(element) {
var asyncTableHeader; var asyncTableHeader;
var asyncTableId; var asyncTableId;
var lastHorizontalPosition;
var currentTableUrl;
var ths = []; var ths = [];
var pageLinks = []; var pageLinks = [];
var pagesizeForm; var pagesizeForm;
var scrollTable; var scrollTable;
var utilInstances = [];
function init() { function init() {
if (!element) { if (!element) {
throw new Error('Async Table utility cannot be setup without an element!'); throw new Error('Async Table utility cannot be setup without an element!');
@ -53,11 +48,20 @@
asyncTableHeader = element.dataset.asyncTableDbHeader; asyncTableHeader = element.dataset.asyncTableDbHeader;
} }
asyncTableId = element.id; asyncTableId = element.querySelector('table').id;
console.log('asyncTable.init()', { asyncTableId }); // find scrolltable wrapper
scrollTable = element.querySelector('.scrolltable');
if (!scrollTable) {
throw new Error('Async Table cannot be set up without a .scrolltable element!');
}
setup(); setupSortableHeaders();
setupPagination();
setupPageSizeSelect();
setupTableFilter();
processLocalStorage();
// mark initialized // mark initialized
element.classList.add(ASYNC_TABLE_INITIALIZED_CLASS); element.classList.add(ASYNC_TABLE_INITIALIZED_CLASS);
@ -69,44 +73,67 @@
}; };
} }
function setup() { function setupSortableHeaders() {
scrollTable = element.closest('.scrolltable'); ths = Array.from(scrollTable.querySelectorAll('th.sortable')).map(function(th) {
if (!scrollTable) {
return false;
}
// sortable element headers
ths = Array.from(element.querySelectorAll('th.sortable')).map(function(th) {
return { element: th }; return { element: th };
}); });
// pagination links ths.forEach(function(th) {
th.clickHandler = function(event) {
var horizPos = (scrollTable || {}).scrollLeft;
setLocalStorageParameter('horizPos', horizPos);
clickHandler(event);
};
th.element.addEventListener('click', th.clickHandler);
});
}
function setupPagination() {
var pagination = element.querySelector('#' + asyncTableId + '-pagination'); var pagination = element.querySelector('#' + asyncTableId + '-pagination');
if (pagination) { if (pagination) {
pageLinks = Array.from(pagination.querySelectorAll('.page-link')).map(function(link) { pageLinks = Array.from(pagination.querySelectorAll('.page-link')).map(function(link) {
return { element: link }; return { element: link };
}); });
}
pageLinks.forEach(function(link) {
link.clickHandler = function(event) {
var tableBoundingRect = scrollTable.getBoundingClientRect();
if (tableBoundingRect.top < HEADER_HEIGHT) {
var scrollTo = {
top: (scrollTable.offsetTop || 0) - HEADER_HEIGHT,
left: scrollTable.offsetLeft || 0,
behavior: 'smooth',
};
setLocalStorageParameter('scrollTo', scrollTo);
}
clickHandler(event);
}
link.element.addEventListener('click', link.clickHandler);
});
}
}
function setupPageSizeSelect() {
// pagesize form // pagesize form
pagesizeForm = element.querySelector('#' + asyncTableId + '-pagesize-form'); pagesizeForm = element.querySelector('#' + asyncTableId + '-pagesize-form');
if (pagesizeForm) {
var pagesizeSelect = pagesizeForm.querySelector('[name=' + asyncTableId + '-pagesize]');
pagesizeSelect.addEventListener('change', changePagesizeHandler);
}
}
function setupTableFilter() {
// // filter // // filter
// var filterForm = element.querySelector('.' + TABLE_FILTER_FORM_CLASS); // var filterForm = element.querySelector('.' + TABLE_FILTER_FORM_CLASS);
// if (filterForm) { // if (filterForm) {
// options.updateTableFrom = updateTableFrom; // options.updateTableFrom = updateTableFrom;
// utilInstances.push(window.utils.setup('asyncTableFilter', filterForm, options)); // utilInstances.push(window.utils.setup('asyncTableFilter', filterForm, options));
// } // }
processLocalStorage();
setupListeners();
element.classList.add(ASYNC_TABLE_INITIALIZED_CLASS);
} }
function reset() { function reset() {
removeListeners(); removeListeners();
element.classList.remove(ASYNC_TABLE_INITIALIZED_CLASS); element.classList.remove(ASYNC_TABLE_INITIALIZED_CLASS);
} }
@ -114,48 +141,14 @@
var scrollTo = getLocalStorageParameter('scrollTo'); var scrollTo = getLocalStorageParameter('scrollTo');
if (scrollTo && scrollTable) { if (scrollTo && scrollTable) {
window.scrollTo(scrollTo); window.scrollTo(scrollTo);
scrollTo = null;
} }
setLocalStorageParameter('scrollTo', null);
var horizPos = getLocalStorageParameter('horizPos'); var horizPos = getLocalStorageParameter('horizPos');
if (horizPos && scrollTable) { if (horizPos && scrollTable) {
scrollTable.scrollLeft = lastHorizontalPosition; scrollTable.scrollLeft = horizPos;
lastHorizontalPosition = null;
}
}
function setupListeners() {
ths.forEach(function(th) {
th.clickHandler = function(event) {
var boundClickHandler = clickHandler.bind(this);
var horizPos = (scrollTable || {}).scrollLeft;
lastHorizontalPosition = (scrollTable || {}).scrollLeft;
boundClickHandler(event, { horizPos });
};
th.element.addEventListener('click', th.clickHandler);
});
pageLinks.forEach(function(link) {
link.clickHandler = function(event) {
var boundClickHandler = clickHandler.bind(this);
var tableBoundingRect = scrollTable.getBoundingClientRect();
if (tableBoundingRect.top < HEADER_HEIGHT) {
var scrollTo = {
top: (scrollTable.offsetTop || 0) - HEADER_HEIGHT,
left: scrollTable.offsetLeft || 0,
behavior: 'smooth',
};
setLocalStorageParameter('scrollTo', JSON.stringify(scrollTo));
}
boundClickHandler(event, tableOptions);
}
link.element.addEventListener('click', link.clickHandler);
});
if (pagesizeForm) {
var pagesizeSelect = pagesizeForm.querySelector('[name=' + asyncTableId + '-pagesize]');
pagesizeSelect.addEventListener('change', changePagesizeHandler);
} }
setLocalStorageParameter('horizPos', null);
} }
function removeListeners() { function removeListeners() {
@ -173,40 +166,41 @@
} }
} }
function clickHandler(event, tableOptions) { function clickHandler(event) {
event.preventDefault(); event.preventDefault();
var url = getClickDestination(this); var url = getClickDestination(event.target);
if (!url.match(/^http/)) { if (!url.match(/^http/)) {
url = new URL(window.location.origin + window.location.pathname + getClickDestination(this)); url = window.location.origin + window.location.pathname + url;
} }
updateTableFrom(url, tableOptions); updateTableFrom(url);
} }
function getClickDestination(el) { function getClickDestination(el) {
if (!el.querySelector('a')) { if (!el.matches('a') && !el.querySelector('a')) {
return ''; return '';
} }
return el.querySelector('a').getAttribute('href'); return el.getAttribute('href') || el.querySelector('a').getAttribute('href');
} }
function changePagesizeHandler(event) { function changePagesizeHandler(event) {
var pagesizeParamKey = asyncTableId + '-pagesize'; var pagesizeParamKey = asyncTableId + '-pagesize';
var pageParamKey = asyncTableId + '-page'; var pageParamKey = asyncTableId + '-page';
var url = new URL(currentTableUrl || window.location.href); var url = new URL(getLocalStorageParameter('currentTableUrl') || window.location.href);
url.searchParams.set(pagesizeParamKey, event.target.value); url.searchParams.set(pagesizeParamKey, event.target.value);
url.searchParams.set(pageParamKey, 0); url.searchParams.set(pageParamKey, 0);
updateTableFrom(url); updateTableFrom(url.href);
} }
// fetches new sorted element from url with params and replaces contents of current element // fetches new sorted element from url with params and replaces contents of current element
function updateTableFrom(url, tableOptions, callback) { function updateTableFrom(url) {
if (!HttpClient) { if (!HttpClient) {
throw new Error('HttpClient not found!'); throw new Error('HttpClient not found!');
} }
console.log('updating from ', { url });
element.classList.add(ASYNC_TABLE_LOADING_CLASS); element.classList.add(ASYNC_TABLE_LOADING_CLASS);
tableOptions = tableOptions || {};
var headers = { var headers = {
'Accept': 'text/html', 'Accept': 'text/html',
[asyncTableHeader]: asyncTableId [asyncTableHeader]: asyncTableId
@ -218,12 +212,11 @@
} }
return response.text(); return response.text();
}).then(function(data) { }).then(function(data) {
currentTableUrl = url.href; setLocalStorageParameter('currentTableUrl', url.href);
// reset table
reset(); reset();
updateWrapperContents(data, tableOptions); // update table with new
if (callback && typeof callback === 'function') { updateWrapperContents(data);
callback(element);
}
element.classList.remove(ASYNC_TABLE_LOADING_CLASS); element.classList.remove(ASYNC_TABLE_LOADING_CLASS);
}).catch(function(err) { }).catch(function(err) {
@ -231,33 +224,11 @@
}); });
} }
function updateWrapperContents(newHtml, tableOptions) { function updateWrapperContents(newHtml) {
tableOptions = tableOptions || {}; var newPage = document.createElement('div');
element.innerHTML = newHtml; newPage.innerHTML = newHtml;
var newWrapperContents = newPage.querySelector('#' + element.id);
element.innerHTML = newWrapperContents.innerHTML;
// merge global options and element specific options
// var resetOptions = {};
// Object.keys(options)
// .filter(function(key) {
// return !RESET_OPTIONS.includes(key);
// })
// .forEach(function(key) {
// resetOptions[key] = options[key];
// });
// var combinedOptions = {};
// combinedOptions = Object.keys(tableOptions)
// .filter(function(key) {
// return tableOptions.hasOwnProperty(key);
// })
// .map(function(key) {
// return { key, value: tableOptions[key] }
// })
// .reduce(function(cumulatedOpts, opt) {
// cumulatedOpts[opt.key] = opt.value;
// return cumulatedOpts;
// }, resetOptions);
if (UtilRegistry) { if (UtilRegistry) {
UtilRegistry.setupAll(); UtilRegistry.setupAll();
@ -269,7 +240,11 @@
function setLocalStorageParameter(key, value) { function setLocalStorageParameter(key, value) {
var currentLSState = JSON.parse(window.localStorage.getItem(ASYNC_TABLE_LOCAL_STORAGE_KEY)) || {}; var currentLSState = JSON.parse(window.localStorage.getItem(ASYNC_TABLE_LOCAL_STORAGE_KEY)) || {};
currentLSState[key] = value; if (value !== null) {
currentLSState[key] = value;
} else {
delete currentLSState[key];
}
window.localStorage.setItem(ASYNC_TABLE_LOCAL_STORAGE_KEY, JSON.stringify(currentLSState)); window.localStorage.setItem(ASYNC_TABLE_LOCAL_STORAGE_KEY, JSON.stringify(currentLSState));
} }

View File

@ -1,3 +1,3 @@
$newline never $newline never
<div ##{wIdent "table-wrapper"}> <div ##{wIdent "table-wrapper"} uw-async-table>
^{table} ^{table}