move js for asyncTable to static

This commit is contained in:
Felix Hamann 2019-02-16 19:57:33 +01:00
parent 228aa8320d
commit ebb9307629
5 changed files with 528 additions and 185 deletions

View File

@ -990,8 +990,8 @@ siteLayout' headingOverride widget = do
pc <- widgetToPageContent $ do
-- 3rd party
addScript $ StaticR js_vendor_zepto_js
addScript $ StaticR js_vendor_flatpickr_js
addScript $ StaticR js_vendor_zepto_js
addStylesheet $ StaticR css_vendor_flatpickr_css
addStylesheet $ StaticR css_vendor_fontawesome_css
-- fonts
@ -1000,16 +1000,18 @@ siteLayout' headingOverride widget = do
addScript $ StaticR js_polyfills_fetchPolyfill_js
addScript $ StaticR js_polyfills_urlPolyfill_js
-- JavaScript utils
addScript $ StaticR js_utils_setup_js
addScript $ StaticR js_utils_tabber_js
addScript $ StaticR js_utils_alerts_js
addScript $ StaticR js_utils_asidenav_js
addScript $ StaticR js_utils_asyncTable_js
addScript $ StaticR js_utils_inputs_js
addScript $ StaticR js_utils_setup_js
addScript $ StaticR js_utils_showHide_js
addStylesheet $ StaticR css_utils_tabber_scss
addScript $ StaticR js_utils_tabber_js
addStylesheet $ StaticR css_utils_alerts_scss
addStylesheet $ StaticR css_utils_asidenav_scss
addStylesheet $ StaticR css_utils_inputs_scss
addStylesheet $ StaticR css_utils_showHide_scss
addStylesheet $ StaticR css_utils_tabber_scss
addStylesheet $ StaticR css_utils_tooltip_scss
-- widgets
$(widgetFile "default-layout")

View File

@ -0,0 +1,308 @@
/* GENERAL STYLES FOR FORMS */
/* FORM GROUPS */
.form-group {
position: relative;
display: flex;
display: grid;
grid-template-columns: 1fr 3fr;
grid-gap: 5px;
justify-content: flex-start;
align-items: flex-start;
padding: 4px 0;
border-left: 2px solid transparent;
+ .form-group {
margin-top: 13px;
}
}
.form-group__label {
font-weight: 600;
padding-top: 6px;
}
.form-group--required {
.form-group__label::after {
content: ' *';
color: var(--color-error);
}
}
.form-group--optional {
.form-group__label::after {
content: '';
}
}
.form-group--submit .form-group__input {
grid-column: 2;
}
@media (max-width: 768px) {
.form-group--submit .form-group__input {
grid-column: 1;
}
}
.form-group--has-error {
background-color: rgba(255, 0, 0, 0.1);
input, textarea {
border-color: var(--color-error) !important;
}
}
@media (max-width: 768px) {
.form-group {
grid-template-columns: 1fr;
align-items: baseline;
margin-top: 17px;
flex-direction: column;
}
}
/* TEXT INPUTS */
input[type="text"],
input[type="search"],
input[type="password"],
input[type="url"],
input[type="number"],
input[type="email"],
input[type*="date"],
input[type*="time"],
select {
/* from bulma.css */
color: #363636;
border-color: #dbdbdb;
background-color: #f3f3f3;
box-shadow: inset 0 1px 2px 1px rgba(50,50,50,.05);
width: 100%;
max-width: 600px;
-webkit-appearance: none;
align-items: center;
border: 1px solid transparent;
border-radius: 4px;
font-size: 1rem;
font-family: var(--font-base);
line-height: 1.5;
padding: 4px 13px;
}
input[type="number"] {
width: 100px;
}
input[type*="date"],
input[type*="time"],
.flatpickr-input[type="text"] {
width: 50%;
width: 250px;
}
/* BUTTON STYLE SEE default-layout.lucius */
/* TEXTAREAS */
textarea {
width: 100%;
height: 170px;
max-width: 600px;
line-height: 1.5;
color: #363636;
background-color: #f3f3f3;
padding: 4px 13px;
font-size: 1rem;
font-family: var(--font-base);
-webkit-appearance: none;
appearance: none;
border: 1px solid #dbdbdb;
border-radius: 2px;
box-shadow: inset 0 1px 2px 1px rgba(50,50,50,.05);
vertical-align: top;
}
/* SHARED STATE RELATED STYLES */
input,
select,
textarea {
&:focus {
border-color: #3273dc;
box-shadow: 0 0 0 0.125em rgba(50,115,220,.25);
outline: 0;
}
&[disabled] {
background-color: #f3f3f3;
color: #7a7a7a;
box-shadow: none;
border-color: #dbdbdb;
}
&[readonly] {
background-color: #f5f5f5;
border-color: #dbdbdb;
}
}
/* OPTIONS */
select,
option {
font-size: 1rem;
line-height: 1.5;
padding: 4px 13px;
border: 1px solid #dbdbdb;
border-radius: 2px;
outline: 0;
color: #363636;
min-width: 200px;
background-color: #f3f3f3;
box-shadow: inset 0 1px 2px 1px rgba(50,50,50,.05);
}
@media (max-width: 425px) {
select, option {
width: 100%;
}
}
/* CUSTOM LEGACY CHECKBOX AND RADIO BOXES */
input[type="checkbox"] {
position: relative;
height: 20px;
width: 20px;
-webkit-appearance: none;
appearance: none;
cursor: pointer;
}
input[type="checkbox"]::before {
content: '';
position: absolute;
width: 20px;
height: 20px;
background-color: var(--color-lighter);
display: flex;
align-items: center;
justify-content: center;
border-radius: 2px;
}
input[type="checkbox"]:checked::before {
background-color: var(--color-light);
}
input[type="checkbox"]:checked::after {
content: '';
position: absolute;
width: 20px;
height: 20px;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: 20px;
}
/* CUSTOM CHECKBOXES AND RADIO BOXES */
/* Completely replaces legacy checkbox and radiobox */
.checkbox,
.radio {
position: relative;
display: inline-block;
[type="checkbox"],
[type="radio"] {
position: fixed;
top: -1px;
left: -1px;
width: 1px;
height: 1px;
overflow: hidden;
}
label {
display: block;
height: 24px;
width: 24px;
background-color: #f3f3f3;
box-shadow: inset 0 1px 2px 1px rgba(50, 50, 50, 0.05);
border: 2px solid var(--color-primary);
border-radius: 4px;
color: white;
cursor: pointer;
}
label::before,
label::after {
position: absolute;
display: block;
top: 12px;
left: 8px;
height: 2px;
width: 8px;
background-color: var(--color-font);
}
:checked + label {
background-color: var(--color-primary);
}
[type="checkbox"]:focus + label,
[type="radio"]:focus + label {
border-color: #3273dc;
box-shadow: 0 0 0 0.125em rgba(50,115,220,.25);
outline: 0;
}
:checked + label::before,
:checked + label::after {
content: '';
}
:checked + label::before {
background-color: white;
transform: rotate(45deg);
left: 4px;
}
:checked + label::after {
background-color: white;
transform: rotate(-45deg);
top: 11px;
width: 13px;
}
[disabled] + label {
pointer-events: none;
border: none;
opacity: 0.6;
filter: grayscale(1);
}
}
.radio::before {
content: '';
position: absolute;
top: 2px;
left: 2px;
right: 2px;
bottom: 2px;
border-radius: 4px;
border: 2px solid white;
z-index: -1;
}
/* CUSTOM FILE INPUT */
.file-input__label {
cursor: pointer;
display: inline-block;
background-color: var(--color-primary);
color: white;
padding: 10px 17px;
border-radius: 3px;
}
.file-input__input--hidden {
display: none;
}

View File

@ -0,0 +1,205 @@
(function collonadeClosure() {
'use strict';
window.utils = window.utils || {};
var HEADER_HEIGHT = 80;
var RESET_OPTIONS = [ 'scrollTo' ];
window.utils.asyncTable = function(wrapper, options) {
options = options || {};
var tableIdent = options.dbtIdent;
var shortCircuitHeader = options ? options.headerDBTableShortcircuit : null;
var ths = [];
var pageLinks = [];
var pagesizeForm;
var scrollTable;
function init() {
var table = wrapper.querySelector('#' + tableIdent);
if (!table) {
return;
}
scrollTable = wrapper.querySelector('.scrolltable');
// sortable table headers
ths = Array.from(table.querySelectorAll('th.sortable')).map(function(th) {
return { element: th };
});
// pagination links
var pagination = wrapper.querySelector('#' + tableIdent + '-pagination');
if (pagination) {
pageLinks = Array.from(pagination.querySelectorAll('.page-link')).map(function(link) {
return { element: link };
});
}
// pagesize form
pagesizeForm = wrapper.querySelector('#' + tableIdent + '-pagesize-form');
// take options into account
if (options && options.scrollTo) {
window.scrollTo(options.scrollTo);
}
if (options && options.horizPos && scrollTable) {
scrollTable.scrollLeft = options.horizPos;
}
setupListeners();
wrapper.classList.add('js-initialized');
}
function setupListeners() {
ths.forEach(function(th) {
th.clickHandler = function(event) {
var boundClickHandler = clickHandler.bind(this);
var horizPos = (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();
var tableOptions = {};
if (tableBoundingRect.top < HEADER_HEIGHT) {
tableOptions.scrollTo = {
top: (scrollTable.offsetTop || 0) - HEADER_HEIGHT,
left: scrollTable.offsetLeft || 0,
behavior: 'smooth',
};
}
boundClickHandler(event, tableOptions);
}
link.element.addEventListener('click', link.clickHandler);
});
if (pagesizeForm) {
var pagesizeSelect = pagesizeForm.querySelector('[name=' + tableIdent + '-pagesize]');
pagesizeSelect.addEventListener('change', changePagesizeHandler);
}
}
function removeListeners() {
ths.forEach(function(th) {
th.element.removeEventListener('click', th.clickHandler);
});
pageLinks.forEach(function(link) {
link.element.removeEventListener('click', link.clickHandler);
});
if (pagesizeForm) {
var pagesizeSelect = pagesizeForm.querySelector('[name=' + tableIdent + '-pagesize]')
pagesizeSelect.removeEventListener('change', changePagesizeHandler);
}
}
function clickHandler(event, tableOptions) {
event.preventDefault();
var url = new URL(window.location.origin + window.location.pathname + getClickDestination(this));
updateTableFrom(url, tableOptions);
}
function getClickDestination(el) {
if (!el.querySelector('a')) {
return '';
}
return el.querySelector('a').getAttribute('href');
}
function changePagesizeHandler(event) {
var currentTableUrl = options.currentUrl || window.location.href;
var url = getUrlWithUpdatedPagesize(currentTableUrl, event.target.value);
url = new URL(getUrlWithResetPagenumber(url));
updateTableFrom(url);
}
function getUrlWithUpdatedPagesize(url, pagesize) {
if (url.indexOf('pagesize') >= 0) {
return url.replace(/pagesize=(\d+|all)/, 'pagesize=' + pagesize);
} else if (url.indexOf('?') >= 0) {
return url += '&' + tableIdent + '-pagesize=' + pagesize;
}
return url += '?' + tableIdent + '-pagesize=' + pagesize;
}
function getUrlWithResetPagenumber(url) {
return url.replace(/-page=\d+/, '-page=0');
}
// fetches new sorted table from url with params and replaces contents of current table
function updateTableFrom(url, tableOptions) {
tableOptions = tableOptions || {};
fetch(url, {
credentials: 'same-origin',
headers: {
'Accept': 'text/html',
[shortCircuitHeader]: tableIdent
}
}).then(function(response) {
if (!response.ok) {
throw new Error('Looks like there was a problem fetching ' + url.href + '. Status Code: ' + response.status);
}
return response.text();
}).then(function(data) {
tableOptions.currentUrl = url.href;
removeListeners();
updateWrapperContents(data, tableOptions);
}).catch(function(err) {
console.error(err);
});
}
function updateWrapperContents(newHtml, tableOptions) {
tableOptions = tableOptions || {};
wrapper.innerHTML = newHtml;
wrapper.classList.remove("js-initialized");
// setup the wrapper and its components to behave async again
window.utils.teardown('asyncTable');
// merge global options and table 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);
window.utils.setup('asyncTable', wrapper, combinedOptions);
// make sure to hide any new submit buttons
document.dispatchEvent(new CustomEvent('setup', {
detail: {
scope: wrapper,
module: 'autoSubmit'
}
}));
}
init();
};
})();

View File

@ -11,13 +11,15 @@
return;
}
options = options || {};
var listener = function(event) {
if (event.detail.targetUtil !== utilType) {
return false;
}
if (options && options.setupFunction) {
if (options.setupFunction) {
options.setupFunction(scope, options);
} else {
var util = window.utils[utilType];
@ -29,9 +31,10 @@
}
};
if (registeredSetupListeners[utilType]) {
if (registeredSetupListeners[utilType] && !options.singleton) {
registeredSetupListeners[utilType].push(listener);
} else {
window.utils.teardown(utilType);
registeredSetupListeners[utilType] = [ listener ];
}
@ -49,6 +52,7 @@
registeredSetupListeners[utilType].forEach(function(listener) {
document.removeEventListener('setup', listener);
});
delete registeredSetupListeners[utilType];
}
}
})();

View File

@ -1,186 +1,10 @@
(function collonadeClosure() {
'use strict';
window.utils = window.utils || {};
window.utils.asyncTable = function(wrapper, options) {
var tableIdent = wrapper.dataset.dbtIdent;
var shortCircuitHeader = #{String (toPathPiece HeaderDBTableShortcircuit)};
var ths = [];
var pageLinks = [];
var pagesizeForm;
var scrollTable;
function init() {
var table = wrapper.querySelector('#' + tableIdent);
if (!table) {
return;
}
scrollTable = wrapper.querySelector('.scrolltable');
// sortable table headers
ths = Array.from(table.querySelectorAll('th.sortable')).map(function(th) {
return { element: th };
});
// pagination links
var pagination = wrapper.querySelector('#' + tableIdent + '-pagination');
if (pagination) {
pageLinks = Array.from(pagination.querySelectorAll('.page-link')).map(function(link) {
return { element: link };
});
}
// pagesize form
pagesizeForm = wrapper.querySelector('#' + tableIdent + '-pagesize-form');
// take options into account
if (options && options.scrollTo) {
window.scrollTo(options.scrollTo);
}
if (options && options.horizPos && scrollTable) {
scrollTable.scrollLeft = options.horizPos;
}
setupListeners();
wrapper.classList.add('js-initialized');
}
function setupListeners() {
ths.forEach(function(th) {
th.clickHandler = function(event) {
var boundClickHandler = clickHandler.bind(this);
var horizPos = (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 wrapperBoundingRect = wrapper.getBoundingClientRect();
var options = {};
if (wrapperBoundingRect.top < 160) {
options.scrollTo = {
top: (wrapper.offsetTop || 0) - 60,
left: wrapper.offsetLeft || 0,
behavior: 'smooth',
};
}
boundClickHandler(event, options);
}
link.element.addEventListener('click', link.clickHandler);
});
if (pagesizeForm) {
var pagesizeSelect = pagesizeForm.querySelector('[name=' + tableIdent + '-pagesize]');
pagesizeSelect.addEventListener('change', changePagesizeHandler);
}
}
function removeListeners() {
ths.forEach(function(th) {
th.element.removeEventListener('click', th.clickHandler);
});
pageLinks.forEach(function(link) {
link.element.removeEventListener('click', link.clickHandler);
});
if (pagesizeForm) {
var pagesizeSelect = pagesizeForm.querySelector('[name=' + tableIdent + '-pagesize]')
pagesizeSelect.removeEventListener('change', changePagesizeHandler);
}
}
function clickHandler(event, options) {
event.preventDefault();
var url = new URL(window.location.origin + window.location.pathname + getClickDestination(this));
updateTableFrom(url, options);
}
function getClickDestination(el) {
if (!el.querySelector('a')) {
return '';
}
return el.querySelector('a').getAttribute('href');
}
function changePagesizeHandler(event) {
var currentTableUrl = wrapper.dataset.currentUrl || window.location.href;
var url = getUrlWithUpdatedPagesize(currentTableUrl, event.target.value);
url = getUrlWithResetPagenumber(url);
updateTableFrom(url);
}
function getUrlWithUpdatedPagesize(url, pagesize) {
if (url.indexOf('pagesize') >= 0) {
return url.replace(/pagesize=(\d+|all)/, 'pagesize=' + pagesize);
} else if (url.indexOf('?') >= 0) {
return url += '&' + tableIdent + '-pagesize=' + pagesize;
}
return url += '?' + tableIdent + '-pagesize=' + pagesize;
}
function getUrlWithResetPagenumber(url) {
return url.replace(/-page=\d+/, '-page=0');
}
function updateWrapperContents(newHtml, options) {
wrapper.innerHTML = newHtml;
wrapper.classList.remove("js-initialized");
// setup the wrapper and its components to behave async again
window.utils.asyncTable(wrapper, options);
// make sure to hide any new submit buttons
document.dispatchEvent(new CustomEvent('setup', {
detail: {
scope: wrapper,
module: 'autoSubmit'
}
}));
}
// fetches new sorted table from url with params and replaces contents of current table
function updateTableFrom(url, options) {
fetch(url, {
credentials: 'same-origin',
headers: {
'Accept': 'text/html',
[shortCircuitHeader]: tableIdent
}
}).then(function(response) {
if (!response.ok) {
throw new Error('Looks like there was a problem fetching ' + url + '. Status Code: ' + response.status);
}
return response.text();
}).then(function(data) {
wrapper.dataset.currentUrl = url;
removeListeners();
updateWrapperContents(data, options);
}).catch(function(err) {
console.error(err);
});
}
init();
};
})();
document.addEventListener('DOMContentLoaded', function() {
var dbtIdent = #{String $ dbtIdent};
var headerDBTableShortcircuit = #{String (toPathPiece HeaderDBTableShortcircuit)};
var selector = '#' + dbtIdent + '-table-wrapper:not(.js-initialized)';
var wrapper = document.querySelector(selector);
if (wrapper) {
wrapper.dataset.dbtIdent = dbtIdent;
window.utils.asyncTable(wrapper);
window.utils.setup('asyncTable', wrapper, { headerDBTableShortcircuit, dbtIdent });
}
});