async table js utility now with explicit selector
This commit is contained in:
parent
c654f3d6ab
commit
8b1fae2856
@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,3 +1,3 @@
|
|||||||
$newline never
|
$newline never
|
||||||
<div ##{wIdent "table-wrapper"}>
|
<div ##{wIdent "table-wrapper"} uw-async-table>
|
||||||
^{table}
|
^{table}
|
||||||
|
|||||||
Reference in New Issue
Block a user