split the_works.js in smaller files
This commit is contained in:
parent
25616ca5a2
commit
c77afb48d8
38
the_works/static/js/init_dt.js
Normal file
38
the_works/static/js/init_dt.js
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* DATATABLES FUNCTIONS
|
||||||
|
*/
|
||||||
|
// initializes the DataTable functionality for the given table
|
||||||
|
function initDataTable(table_id) {
|
||||||
|
// add # to id if not there already
|
||||||
|
table_id = table_id.slice(0, 1) == "#" ? table_id : "#" + table_id
|
||||||
|
// initialize table
|
||||||
|
let table = new DataTable(table_id, {
|
||||||
|
paging: false,
|
||||||
|
order: []
|
||||||
|
});
|
||||||
|
// remove role from inside th elements to avoid clashing with PicoCSS
|
||||||
|
spans = document.querySelectorAll(table_id + " th span.dt-column-order")
|
||||||
|
.forEach( function(el) {
|
||||||
|
el.removeAttribute("role");
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// create "New"-element and append it to the <div> containing the DataTables search field
|
||||||
|
function initCreateButton(table_id, title, href=null) {
|
||||||
|
// build button element
|
||||||
|
let button = document.createElement("button");
|
||||||
|
button.id = "create-button";
|
||||||
|
button.setAttribute("title", title);
|
||||||
|
button.textContent = "Neu …";
|
||||||
|
// wrap button inside an <a> if href is given
|
||||||
|
if ( href ) {
|
||||||
|
let b = button;
|
||||||
|
button = document.createElement("a");
|
||||||
|
button.setAttribute("href", href);
|
||||||
|
button.appendChild(b);
|
||||||
|
}
|
||||||
|
// insert element
|
||||||
|
document.getElementById(`${table_id.slice(0, 1) == "#" ? table_id.slice(1) : table_id}_wrapper`).firstElementChild.firstElementChild.appendChild(button);
|
||||||
|
}
|
||||||
|
|
||||||
41
the_works/static/js/modal.js
Normal file
41
the_works/static/js/modal.js
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* MODAL FUNCTIONS
|
||||||
|
*/
|
||||||
|
// adds event handlers that raise a modal
|
||||||
|
function initModal(modal_id, input_ids, headings, form_actions) {
|
||||||
|
// if input_ids is not an array, make it a single-element array
|
||||||
|
input_ids = Array.isArray(input_ids) ? input_ids : [ input_ids ];
|
||||||
|
// add event listener to "New" element
|
||||||
|
document.getElementById("create-button").addEventListener("click", () => showDialog(modal_id, input_ids, headings[0], form_actions[0], new Array(input_ids.length).fill(""), 0));
|
||||||
|
// add event listeners to "update" elements
|
||||||
|
for (const el of document.querySelectorAll('.action-update')) {
|
||||||
|
console.log(`input_ids is ${input_ids}`);
|
||||||
|
el.addEventListener("click", event => showDialog(
|
||||||
|
modal_id,
|
||||||
|
input_ids,
|
||||||
|
headings[1],
|
||||||
|
form_actions[1],
|
||||||
|
input_ids.map(input => event.currentTarget.dataset[input.slice(5).toLowerCase()]),
|
||||||
|
event.currentTarget.dataset.id
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// raises a modal with the given options
|
||||||
|
function showDialog(modal_id, input_ids, heading, form_action, input_values, url_id) {
|
||||||
|
console.dir(arguments);
|
||||||
|
// if form action includes the string "update", the id at the end of the URL is a dummy and must be replaced with the correct id
|
||||||
|
if ( form_action.includes("update") && url_id) {
|
||||||
|
form_action = form_action.slice(0, form_action.lastIndexOf("/") + 1) + url_id;
|
||||||
|
}
|
||||||
|
// set modal attributes
|
||||||
|
document.getElementById("dialog-heading").textContent = heading;
|
||||||
|
document.getElementById("form_submit").formAction = form_action;
|
||||||
|
for (var i = 0; i < input_ids.length; i++ ) {
|
||||||
|
document.getElementById(input_ids[i]).value = input_values[i] || "";
|
||||||
|
}
|
||||||
|
// raise modal
|
||||||
|
document.getElementById(modal_id).showModal();
|
||||||
|
}
|
||||||
|
|
||||||
104
the_works/static/js/multiselect.js
Normal file
104
the_works/static/js/multiselect.js
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
/*
|
||||||
|
* MULTISELECT FUNCTIONS
|
||||||
|
*/
|
||||||
|
// initializes all dropdown selects on the page
|
||||||
|
function initAllMultiselects() {
|
||||||
|
// initialize each dropdown individually
|
||||||
|
let dropdowns = document.querySelectorAll("form details.dropdown");
|
||||||
|
dropdowns.forEach(d => initMultiselect(d));
|
||||||
|
// now it's time to set the z-indices
|
||||||
|
// get the_works style sheet
|
||||||
|
let sheet = [...document.styleSheets].filter(s => s.ownerNode.getAttribute("href").includes("the_works"))[0];
|
||||||
|
const initialZ = 20;
|
||||||
|
// add style rules to set z-indices on dropdown elements
|
||||||
|
// using reverse order of dropdown elements on page; this way a dropdown thaht's higher on the page will overlap a lower one
|
||||||
|
for ( let i = 0; i < dropdowns.length; i++ ) {
|
||||||
|
sheet.insertRule(`#${dropdowns[dropdowns.length-i-1].id} { z-index: ${initialZ + i*3};}`, sheet.cssRules.length);
|
||||||
|
sheet.insertRule(`#${dropdowns[dropdowns.length-i-1].id} .dropdown-badge { z-index: ${initialZ+1+i*3};}`, sheet.cssRules.length);
|
||||||
|
sheet.insertRule(`#${dropdowns[dropdowns.length-i-1].id} .dropdown-badge-close { z-index: ${initialZ+2+i*3};}`, sheet.cssRules.length);
|
||||||
|
}
|
||||||
|
// event handler for summary elements (see below)
|
||||||
|
function summaryClick(event, that) {
|
||||||
|
if ( event.target != that && that.contains(event.target) ) {
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// add event handler to summary elements preventing default behavior (toggling the details element) if the click actually targeted a badge
|
||||||
|
document.querySelectorAll("form details.dropdown summary").forEach(summary => summary.addEventListener("click", event => summaryClick(event, summary), true));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// initialize a dropdown select component
|
||||||
|
function initMultiselect(dropdown) {
|
||||||
|
// empty search field
|
||||||
|
let search = dropdown.querySelector("input[type='search']");
|
||||||
|
search.value = "";
|
||||||
|
// add event listener to search field
|
||||||
|
let input_name = dropdown.querySelector("input[type='checkbox']").getAttribute("name");
|
||||||
|
search.addEventListener("input", event => {
|
||||||
|
filterMultiselectChoices(event.target, input_name);
|
||||||
|
});
|
||||||
|
// add event listener to checkboxes
|
||||||
|
let summary = dropdown.querySelector("summary");
|
||||||
|
document.querySelectorAll(`[name='${input_name}']`).forEach( el => {
|
||||||
|
el.addEventListener("change", event => {
|
||||||
|
updateMultiselectSelected(event.target, summary);
|
||||||
|
});
|
||||||
|
// add badges for genre that were already selected
|
||||||
|
if ( el.checked ) {
|
||||||
|
el.dispatchEvent(new Event("change"));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// event handler for dropdown search field; called whenever the search field's input value is changed
|
||||||
|
function filterMultiselectChoices(that, checkbox_name) {
|
||||||
|
// show everything when search field is empty
|
||||||
|
if ( ! that.value || that.value == "" ) {
|
||||||
|
that.parentNode.parentNode.querySelectorAll("[name='" + checkbox_name + "']").forEach( (el) => {
|
||||||
|
el.parentNode.parentNode.classList.remove("filtered-out");
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
// iterate over genre inputs
|
||||||
|
that.parentNode.parentNode.querySelectorAll("[name='" + checkbox_name + "']").forEach( (el) => {
|
||||||
|
// show/hide genre entry depending on whether genre name includes search string
|
||||||
|
let noHits = true;
|
||||||
|
if ( el.parentNode.textContent.toLowerCase().includes(that.value.toLowerCase()) ) {
|
||||||
|
el.parentNode.parentNode.classList.remove("filtered-out");
|
||||||
|
noHits = false;
|
||||||
|
} else {
|
||||||
|
el.parentNode.parentNode.classList.add("filtered-out");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// event handler for dropdown checkboxes; called whenever a checkbox is checked or unchecked
|
||||||
|
function updateMultiselectSelected(that, summary) {
|
||||||
|
if ( that.checked ) {
|
||||||
|
// add badge when checkbox was checked
|
||||||
|
let badge = document.createElement("span");
|
||||||
|
badge.id = that.id + "-badge";
|
||||||
|
badge.classList.add("dropdown-badge");
|
||||||
|
badge.textContent = that.parentNode.textContent;
|
||||||
|
summary.appendChild(badge);
|
||||||
|
// add closing X to badge
|
||||||
|
let badgeX = document.createElement("span");
|
||||||
|
badgeX.classList.add("dropdown-badge-close");
|
||||||
|
badgeX.innerHTML = "×";
|
||||||
|
badge.appendChild(badgeX);
|
||||||
|
badgeX.addEventListener("click", removeMultiselectBadge);
|
||||||
|
} else {
|
||||||
|
// remove badge when checkbox was unchecked
|
||||||
|
document.getElementById(that.id + "-badge").remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// unselect a previously checked checkbox by clicking its badge's "X"
|
||||||
|
function removeMultiselectBadge(event) {
|
||||||
|
let input_id = this.parentNode.id.slice(0, -6);
|
||||||
|
document.getElementById(input_id).checked = false;
|
||||||
|
this.parentNode.remove();
|
||||||
|
event.stopPropagation();
|
||||||
|
}
|
||||||
|
|
||||||
80
the_works/static/js/searchall.js
Normal file
80
the_works/static/js/searchall.js
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* SEARCH-ALL FUNCTIONS
|
||||||
|
*/
|
||||||
|
function search_all(s, url) {
|
||||||
|
// remove previous results
|
||||||
|
document.getElementById("results").innerHTML = "";
|
||||||
|
if ( s == "" ) { return; }
|
||||||
|
|
||||||
|
// fetch search results
|
||||||
|
let fetch_url = new URL(url);
|
||||||
|
fetch_url.search = new URLSearchParams({query: s, case: document.getElementById("match_case").checked ? "match" : "no"});
|
||||||
|
|
||||||
|
fetch(fetch_url)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
// tell user if there are no results
|
||||||
|
if ( Object.keys(data).length === 0 ) {
|
||||||
|
let h3 = document.createElement("h3");
|
||||||
|
h3.innerText = "Die Suchanfrage ergab keine Treffer.";
|
||||||
|
document.getElementById("results").appendChild(h3);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// iterate over search results
|
||||||
|
for ( const db_table of Object.keys(data) ) {
|
||||||
|
let columns = Object.keys(data[db_table][0]);
|
||||||
|
|
||||||
|
// build container, heading, table
|
||||||
|
let container = document.createElement("details");
|
||||||
|
container.classList.add("result-container");
|
||||||
|
container.setAttribute("name", "result-accordion");
|
||||||
|
let heading = document.createElement("summary");
|
||||||
|
container.appendChild(heading);
|
||||||
|
let table = document.createElement("table");
|
||||||
|
|
||||||
|
// build table head
|
||||||
|
let thead = document.createElement("thead");
|
||||||
|
let tr, th, td;
|
||||||
|
tr = document.createElement("tr");
|
||||||
|
for ( const column of columns) {
|
||||||
|
if ( column == "ID" ) { continue; }
|
||||||
|
th = document.createElement("th");
|
||||||
|
th.innerText = column;
|
||||||
|
tr.appendChild(th);
|
||||||
|
}
|
||||||
|
thead.appendChild(tr);
|
||||||
|
table.appendChild(thead);
|
||||||
|
|
||||||
|
// build table body
|
||||||
|
let tbody = document.createElement("tbody");
|
||||||
|
for ( const row of data[db_table] ) {
|
||||||
|
tr = document.createElement("tr");
|
||||||
|
for ( const column of columns ) {
|
||||||
|
// add column "ID" as data attribute, all other columns as regular table columns
|
||||||
|
if ( column == "ID" ) {
|
||||||
|
tr.setAttribute(`data-${db_table}-id`, row[column].toString());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
td = document.createElement("td");
|
||||||
|
td.innerHTML = row[column] ? row[column].toString().replace(s, `<mark>${s}</mark>`) : "";
|
||||||
|
tr.appendChild(td);
|
||||||
|
}
|
||||||
|
tbody.appendChild(tr);
|
||||||
|
}
|
||||||
|
table.appendChild(tbody);
|
||||||
|
heading.innerHTML = `<h3>${db_table} (${tbody.childNodes.length} Treffer)</h3>`;
|
||||||
|
|
||||||
|
// add container element to DOM
|
||||||
|
container.append(table);
|
||||||
|
document.getElementById("results").appendChild(container);
|
||||||
|
|
||||||
|
// open <details> but only if it's the first element
|
||||||
|
if ( document.getElementById("results").children[0] == container ) {
|
||||||
|
container.setAttribute("open", "open");
|
||||||
|
}
|
||||||
|
document.getElementById("results").insertBefore(document.createElement("hr"), container);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
27
the_works/static/js/validate_date.js
Normal file
27
the_works/static/js/validate_date.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* MISC FUNCTIONS
|
||||||
|
*/
|
||||||
|
// validates a date to be of format YYYY, MM-YYYY, DD-MM-YYYY, or empty
|
||||||
|
function validate_date(tag_id="form_Erscheinungstag", monat_id="form_Erscheinungsmonat", jahr_id="form_Erscheinungsjahr") {
|
||||||
|
let t = document.getElementById(tag_id);
|
||||||
|
let m = document.getElementById(monat_id);
|
||||||
|
let j = document.getElementById(jahr_id);
|
||||||
|
t.setCustomValidity("");
|
||||||
|
t.setAttribute("aria-invalid", "false");
|
||||||
|
m.setCustomValidity("");
|
||||||
|
m.setAttribute("aria-invalid", "false");
|
||||||
|
if ( t.value != "" ) {
|
||||||
|
if ( j.value == "" || m.value == "" ) {
|
||||||
|
t.setCustomValidity("wenn der Tag angegeben ist, müssen Monat und Jahr ebenfalls angegeben sein");
|
||||||
|
t.setAttribute("aria-invalid", "true");
|
||||||
|
t.reportValidity();
|
||||||
|
}
|
||||||
|
} else if ( m.value != "" ) {
|
||||||
|
if ( j.value == "") {
|
||||||
|
m.setCustomValidity("wenn der Monat angegeben ist, muss das Jahr ebenfalls angegeben sein");
|
||||||
|
m.setAttribute("aria-invalid", "true");
|
||||||
|
m.reportValidity();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -1,286 +0,0 @@
|
|||||||
/*
|
|
||||||
* DATATABLES FUNCTIONS
|
|
||||||
*/
|
|
||||||
// initializes the DataTable fumctionality for the given table
|
|
||||||
function initDataTable(table_id) {
|
|
||||||
// add # to id if not there already
|
|
||||||
table_id = table_id.slice(0, 1) == "#" ? table_id : "#" + table_id
|
|
||||||
// initialize table
|
|
||||||
let table = new DataTable(table_id, {
|
|
||||||
paging: false,
|
|
||||||
order: []
|
|
||||||
});
|
|
||||||
// remove role from inside th elements to avoid clashing with PicoCSS
|
|
||||||
spans = document.querySelectorAll(table_id + " th span.dt-column-order")
|
|
||||||
.forEach( function(el) {
|
|
||||||
el.removeAttribute("role");
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// create "New"-element and append it to the <div> containing the DataTables search field
|
|
||||||
function initCreateButton(table_id, title, href=null) {
|
|
||||||
// build button element
|
|
||||||
let button = document.createElement("button");
|
|
||||||
button.id = "create-button";
|
|
||||||
button.setAttribute("title", title);
|
|
||||||
button.textContent = "Neu …";
|
|
||||||
// wrap button inside an <a> if href is given
|
|
||||||
if ( href ) {
|
|
||||||
let b = button;
|
|
||||||
button = document.createElement("a");
|
|
||||||
button.setAttribute("href", href);
|
|
||||||
button.appendChild(b);
|
|
||||||
}
|
|
||||||
// insert element
|
|
||||||
document.getElementById(`${table_id.slice(0, 1) == "#" ? table_id.slice(1) : table_id}_wrapper`).firstElementChild.firstElementChild.appendChild(button);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* MODAL FUNCTIONS
|
|
||||||
*/
|
|
||||||
// adds event handlers that raise a modal
|
|
||||||
function initModal(modal_id, input_ids, headings, form_actions) {
|
|
||||||
// if input_ids is not an array, make it a single-element array
|
|
||||||
input_ids = Array.isArray(input_ids) ? input_ids : [ input_ids ];
|
|
||||||
// add event listener to "New" element
|
|
||||||
document.getElementById("create-button").addEventListener("click", () => showDialog(modal_id, input_ids, headings[0], form_actions[0], new Array(input_ids.length).fill(""), 0));
|
|
||||||
// add event listeners to "update" elements
|
|
||||||
for (const el of document.querySelectorAll('.action-update')) {
|
|
||||||
el.addEventListener("click", event => showDialog(modal_id, input_ids, headings[1], form_actions[1], input_ids.map(input => event.currentTarget.dataset[input.slice(5).toLowerCase()]), event.currentTarget.dataset.id));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// raises a modal with the given options
|
|
||||||
function showDialog(modal_id, input_ids, heading, form_action, input_values, url_id) {
|
|
||||||
// if form action includes the string "update", the id at the end of the URL is a dummy and must be replaced with the correct id
|
|
||||||
if ( form_action.includes("update") && url_id) {
|
|
||||||
form_action = form_action.slice(0, form_action.lastIndexOf("/") + 1) + url_id;
|
|
||||||
}
|
|
||||||
// set modal attributes
|
|
||||||
document.getElementById("dialog-heading").textContent = heading;
|
|
||||||
document.getElementById("form_submit").formAction = form_action;
|
|
||||||
for (var i = 0; i < input_ids.length; i++ ) {
|
|
||||||
document.getElementById(input_ids[i]).value = input_values[i] || "";
|
|
||||||
}
|
|
||||||
// raise modal
|
|
||||||
document.getElementById(modal_id).showModal();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* MULTISELECT FUNCTIONS
|
|
||||||
*/
|
|
||||||
// initialize a dropdown select component
|
|
||||||
function initDropdownSelect(dropdown) {
|
|
||||||
// empty search field
|
|
||||||
let search = dropdown.querySelector("input[type='search']");
|
|
||||||
search.value = "";
|
|
||||||
// add event listener to search field
|
|
||||||
let input_name = dropdown.querySelector("input[type='checkbox']").getAttribute("name");
|
|
||||||
search.addEventListener("input", event => {
|
|
||||||
filterDropdownChoices(event.target, input_name);
|
|
||||||
});
|
|
||||||
// add event listener to checkboxes
|
|
||||||
let summary = dropdown.querySelector("summary");
|
|
||||||
document.querySelectorAll(`[name='${input_name}']`).forEach( el => {
|
|
||||||
el.addEventListener("change", event => {
|
|
||||||
updateDropdownSelected(event.target, summary);
|
|
||||||
});
|
|
||||||
// add badges for genre that were already selected
|
|
||||||
if ( el.checked ) {
|
|
||||||
el.dispatchEvent(new Event("change"));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// event handler for dropdown search field; called whenever the search field's input value is changed
|
|
||||||
function filterDropdownChoices(that, checkbox_name) {
|
|
||||||
// show everything when search field is empty
|
|
||||||
if ( ! that.value || that.value == "" ) {
|
|
||||||
that.parentNode.parentNode.querySelectorAll("[name='" + checkbox_name + "']").forEach( (el) => {
|
|
||||||
el.parentNode.parentNode.classList.remove("filtered-out");
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
// iterate over genre inputs
|
|
||||||
that.parentNode.parentNode.querySelectorAll("[name='" + checkbox_name + "']").forEach( (el) => {
|
|
||||||
// show/hide genre entry depending on whether genre name includes search string
|
|
||||||
let noHits = true;
|
|
||||||
if ( el.parentNode.textContent.toLowerCase().includes(that.value.toLowerCase()) ) {
|
|
||||||
el.parentNode.parentNode.classList.remove("filtered-out");
|
|
||||||
noHits = false;
|
|
||||||
} else {
|
|
||||||
el.parentNode.parentNode.classList.add("filtered-out");
|
|
||||||
}
|
|
||||||
if ( noHits ) {
|
|
||||||
console.log("everything has been filtered out")
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// event handler for dropdown checkboxes; called whenever a checkbox is checked or unchecked
|
|
||||||
function updateDropdownSelected(that, summary) {
|
|
||||||
if ( that.checked ) {
|
|
||||||
// add badge when checkbox was checked
|
|
||||||
let badge = document.createElement("span");
|
|
||||||
badge.id = that.id + "-badge";
|
|
||||||
badge.classList.add("dropdown-badge");
|
|
||||||
badge.textContent = that.parentNode.textContent;
|
|
||||||
summary.appendChild(badge);
|
|
||||||
// add closing X to badge
|
|
||||||
let badgeX = document.createElement("span");
|
|
||||||
badgeX.classList.add("dropdown-badge-close");
|
|
||||||
badgeX.innerHTML = "×";
|
|
||||||
badge.appendChild(badgeX);
|
|
||||||
badgeX.addEventListener("click", removeDropdownBadge);
|
|
||||||
} else {
|
|
||||||
// remove badge when checkbox was unchecked
|
|
||||||
document.getElementById(that.id + "-badge").remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// unselect a previously checked checkbox by clicking its badge's "X"
|
|
||||||
function removeDropdownBadge(event) {
|
|
||||||
let input_id = this.parentNode.id.slice(0, -6);
|
|
||||||
document.getElementById(input_id).checked = false;
|
|
||||||
this.parentNode.remove();
|
|
||||||
event.stopPropagation();
|
|
||||||
}
|
|
||||||
|
|
||||||
// initializes all dropdown selects on the page
|
|
||||||
function initAllDropdownSelects() {
|
|
||||||
// initialize each dropdown individually
|
|
||||||
let dropdowns = document.querySelectorAll("form details.dropdown");
|
|
||||||
dropdowns.forEach(d => initDropdownSelect(d));
|
|
||||||
// now it's time to set the z-indices
|
|
||||||
// get the_works style sheet
|
|
||||||
let sheet = [...document.styleSheets].filter(s => s.ownerNode.getAttribute("href").includes("the_works"))[0];
|
|
||||||
const initialZ = 20;
|
|
||||||
// set z-index on dropdowns in reverse order
|
|
||||||
for ( let i = 0; i < dropdowns.length; i++ ) {
|
|
||||||
sheet.insertRule(`#${dropdowns[dropdowns.length-i-1].id} { z-index: ${initialZ + i*3};}`, sheet.cssRules.length);
|
|
||||||
sheet.insertRule(`#${dropdowns[dropdowns.length-i-1].id} .dropdown-badge { z-index: ${initialZ+1+i*3};}`, sheet.cssRules.length);
|
|
||||||
sheet.insertRule(`#${dropdowns[dropdowns.length-i-1].id} .dropdown-badge-close { z-index: ${initialZ+2+i*3};}`, sheet.cssRules.length);
|
|
||||||
}
|
|
||||||
// event handler for summary elements (see below)
|
|
||||||
function summaryClick(event, that) {
|
|
||||||
if ( event.target != that && that.contains(event.target) ) {
|
|
||||||
event.preventDefault();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// add event handler to summary elements preventing default behavior (toggling the details element) if the click actually targeted a badge
|
|
||||||
document.querySelectorAll("form details.dropdown summary").forEach(summary => summary.addEventListener("click", event => summaryClick(event, summary), true));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* SEARCH-ALL FUNCTIONS
|
|
||||||
*/
|
|
||||||
function search_all(s, url) {
|
|
||||||
console.log(`JavaScript function search_all was called with search string ${s} and url ${url}`);
|
|
||||||
// remove previous results
|
|
||||||
document.getElementById("results").innerHTML = "";
|
|
||||||
if ( s == "" ) { return; }
|
|
||||||
|
|
||||||
// fetch search results
|
|
||||||
let fetch_url = new URL(url);
|
|
||||||
fetch_url.search = new URLSearchParams({query: s, case: document.getElementById("match_case").checked ? "match" : "no"});
|
|
||||||
console.log(`fetch_url is ${fetch_url}`);
|
|
||||||
|
|
||||||
fetch(fetch_url)
|
|
||||||
.then(response => response.json())
|
|
||||||
.then(data => {
|
|
||||||
// tell user if there are no results
|
|
||||||
if ( Object.keys(data).length === 0 ) {
|
|
||||||
let h3 = document.createElement("h3");
|
|
||||||
h3.innerText = "Die Suchanfrage ergab keine Treffer.";
|
|
||||||
document.getElementById("results").appendChild(h3);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// iterate over search results
|
|
||||||
for ( const db_table of Object.keys(data) ) {
|
|
||||||
let columns = Object.keys(data[db_table][0]);
|
|
||||||
|
|
||||||
// build container, heading, table
|
|
||||||
let container = document.createElement("details");
|
|
||||||
container.classList.add("result-container");
|
|
||||||
container.setAttribute("name", "result-accordion");
|
|
||||||
let heading = document.createElement("summary");
|
|
||||||
container.appendChild(heading);
|
|
||||||
let table = document.createElement("table");
|
|
||||||
|
|
||||||
// build table head
|
|
||||||
let thead = document.createElement("thead");
|
|
||||||
let tr, th, td;
|
|
||||||
tr = document.createElement("tr");
|
|
||||||
for ( const column of columns) {
|
|
||||||
if ( column == "ID" ) { continue; }
|
|
||||||
th = document.createElement("th");
|
|
||||||
th.innerText = column;
|
|
||||||
tr.appendChild(th);
|
|
||||||
}
|
|
||||||
thead.appendChild(tr);
|
|
||||||
table.appendChild(thead);
|
|
||||||
|
|
||||||
// build table body
|
|
||||||
let tbody = document.createElement("tbody");
|
|
||||||
for ( const row of data[db_table] ) {
|
|
||||||
tr = document.createElement("tr");
|
|
||||||
for ( const column of columns ) {
|
|
||||||
// add column "ID" as data attribute, all other columns as regular table columns
|
|
||||||
if ( column == "ID" ) {
|
|
||||||
tr.setAttribute(`data-${db_table}-id`, row[column].toString());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
td = document.createElement("td");
|
|
||||||
td.innerHTML = row[column] ? row[column].toString().replace(s, `<mark>${s}</mark>`) : "";
|
|
||||||
tr.appendChild(td);
|
|
||||||
}
|
|
||||||
tbody.appendChild(tr);
|
|
||||||
}
|
|
||||||
table.appendChild(tbody);
|
|
||||||
heading.innerHTML = `<h3>${db_table} (${tbody.childNodes.length} Treffer)</h3>`;
|
|
||||||
|
|
||||||
// add container element to DOM
|
|
||||||
container.append(table);
|
|
||||||
document.getElementById("results").appendChild(container);
|
|
||||||
|
|
||||||
// open <details> but only if it's the first element
|
|
||||||
if ( document.getElementById("results").children[0] == container ) {
|
|
||||||
container.setAttribute("open", "open");
|
|
||||||
}
|
|
||||||
document.getElementById("results").insertBefore(document.createElement("hr"), container);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* MISC FUNCTIONS
|
|
||||||
*/
|
|
||||||
// validates a date to be of format YYYY, MM-YYYY, DD-MM-YYYY, or empty
|
|
||||||
function validate_date(tag_id="form_Erscheinungstag", monat_id="form_Erscheinungsmonat", jahr_id="form_Erscheinungsjahr") {
|
|
||||||
let t = document.getElementById(tag_id);
|
|
||||||
let m = document.getElementById(monat_id);
|
|
||||||
let j = document.getElementById(jahr_id);
|
|
||||||
t.setCustomValidity("");
|
|
||||||
t.setAttribute("aria-invalid", "false");
|
|
||||||
m.setCustomValidity("");
|
|
||||||
m.setAttribute("aria-invalid", "false");
|
|
||||||
if ( t.value != "" ) {
|
|
||||||
if ( j.value == "" || m.value == "" ) {
|
|
||||||
t.setCustomValidity("wenn der Tag angegeben ist, müssen Monat und Jahr ebenfalls angegeben sein");
|
|
||||||
t.setAttribute("aria-invalid", "true");
|
|
||||||
t.reportValidity();
|
|
||||||
}
|
|
||||||
} else if ( m.value != "" ) {
|
|
||||||
if ( j.value == "") {
|
|
||||||
m.setCustomValidity("wenn der Monat angegeben ist, muss das Jahr ebenfalls angegeben sein");
|
|
||||||
m.setAttribute("aria-invalid", "true");
|
|
||||||
m.reportValidity();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Loading…
Reference in New Issue
Block a user