philomena/assets/js/boorujs.js

158 lines
3.8 KiB
JavaScript
Raw Normal View History

2019-10-05 02:09:52 +02:00
/**
* BoorUJS
*
* Apply event-based actions through data-* attributes. The attributes are structured like so: [data-event-action]
*/
import { $, $$ } from './utils/dom';
2019-10-05 02:09:52 +02:00
import { fetchHtml, handleError } from './utils/requests';
import { showBlock } from './utils/image';
import { addTag } from './tagsinput';
// Event types and any qualifying conditions - return true to not run action
const types = {
2024-07-03 22:54:14 +02:00
click(event) {
return event.button !== 0; /* Left-click only */
},
2019-10-05 02:09:52 +02:00
2024-07-03 22:54:14 +02:00
change() {
/* No qualifier */
},
2019-10-05 02:09:52 +02:00
2024-07-03 22:54:14 +02:00
fetchcomplete() {
/* No qualifier */
},
2019-10-05 02:09:52 +02:00
};
const actions = {
2024-07-03 22:54:14 +02:00
hide(data) {
2024-07-03 23:03:46 +02:00
selectorCb(data.base, data.value, el => el.classList.add('hidden'));
2024-07-03 22:54:14 +02:00
},
2019-10-05 02:09:52 +02:00
2024-07-03 22:54:14 +02:00
tabHide(data) {
2024-07-03 23:03:46 +02:00
selectorCbChildren(data.base, data.value, el => el.classList.add('hidden'));
2024-07-03 22:54:14 +02:00
},
2024-07-03 22:54:14 +02:00
show(data) {
2024-07-03 23:03:46 +02:00
selectorCb(data.base, data.value, el => el.classList.remove('hidden'));
2024-07-03 22:54:14 +02:00
},
2019-10-05 02:09:52 +02:00
2024-07-03 22:54:14 +02:00
toggle(data) {
2024-07-03 23:03:46 +02:00
selectorCb(data.base, data.value, el => el.classList.toggle('hidden'));
2024-07-03 22:54:14 +02:00
},
2019-10-05 02:09:52 +02:00
2024-07-03 22:54:14 +02:00
submit(data) {
2024-07-03 23:03:46 +02:00
selectorCb(data.base, data.value, el => el.submit());
2024-07-03 22:54:14 +02:00
},
2019-10-05 02:09:52 +02:00
2024-07-03 22:54:14 +02:00
disable(data) {
2024-07-03 23:03:46 +02:00
selectorCb(data.base, data.value, el => {
2024-07-03 22:54:14 +02:00
el.disabled = true;
});
},
2019-10-05 02:09:52 +02:00
copy(data) {
document.querySelector(data.value).select();
document.execCommand('copy');
},
2019-10-05 02:09:52 +02:00
2024-07-03 22:54:14 +02:00
inputvalue(data) {
document.querySelector(data.value).value = data.el.dataset.setValue;
},
2019-10-05 02:09:52 +02:00
2024-07-03 22:54:14 +02:00
selectvalue(data) {
document.querySelector(data.value).value = data.el.querySelector(':checked').dataset.setValue;
},
2019-10-05 02:09:52 +02:00
2024-07-03 22:54:14 +02:00
checkall(data) {
2024-07-03 23:03:46 +02:00
$$(`${data.value} input[type=checkbox]`).forEach(c => {
2024-07-03 22:54:14 +02:00
c.checked = !c.checked;
});
},
2024-07-03 22:54:14 +02:00
focus(data) {
document.querySelector(data.value).focus();
},
2019-10-05 02:09:52 +02:00
2024-07-03 22:54:14 +02:00
preventdefault() {
/* The existence of this entry is enough */
},
2019-10-05 02:09:52 +02:00
addtag(data) {
addTag(document.querySelector(data.el.closest('[data-target]').dataset.target), data.el.dataset.tagName);
},
tab(data) {
const block = data.el.parentNode.parentNode,
2024-07-03 22:54:14 +02:00
newTab = $(`.block__tab[data-tab="${data.value}"]`),
loadTab = data.el.dataset.loadTab;
2019-10-05 02:09:52 +02:00
// Switch tab
const selectedTab = block.querySelector('.selected');
if (selectedTab) {
selectedTab.classList.remove('selected');
}
data.el.classList.add('selected');
// Switch contents
this.tabHide({ base: block, value: '.block__tab' });
2019-10-05 02:09:52 +02:00
this.show({ base: block, value: `.block__tab[data-tab="${data.value}"]` });
// If the tab has a 'data-load-tab' attribute, load and insert the content
if (loadTab && !newTab.dataset.loaded) {
fetchHtml(loadTab)
.then(handleError)
2024-07-03 23:03:46 +02:00
.then(response => response.text())
.then(response => {
2024-07-03 22:54:14 +02:00
newTab.innerHTML = response;
})
.then(() => {
newTab.dataset.loaded = true;
})
.catch(() => {
newTab.textContent = 'Error!';
});
2019-10-05 02:09:52 +02:00
}
},
2024-07-03 22:54:14 +02:00
unfilter(data) {
showBlock(data.el.closest('.image-show-container'));
},
2019-10-05 02:09:52 +02:00
};
// Use this function to apply a callback to elements matching the selectors
function selectorCb(base = document, selector, cb) {
[].forEach.call(base.querySelectorAll(selector), cb);
}
function selectorCbChildren(base = document, selector, cb) {
const sel = $$(selector, base);
for (const el of base.children) {
if (!sel.includes(el)) continue;
cb(el);
}
}
2019-10-05 02:09:52 +02:00
function matchAttributes(event) {
if (!types[event.type](event)) {
for (const action in actions) {
2019-12-02 15:55:48 +01:00
const attr = `data-${event.type}-${action.toLowerCase()}`,
2024-07-03 22:54:14 +02:00
el = event.target && event.target.closest(`[${attr}]`),
value = el && el.getAttribute(attr);
2019-10-05 02:09:52 +02:00
if (el) {
// Return true if you don't want to preventDefault
actions[action]({ attr, el, value }) || event.preventDefault();
}
}
}
}
function registerEvents() {
for (const type in types) document.addEventListener(type, matchAttributes);
}
export { registerEvents };