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);
+ }
+ })
+}
+
diff --git a/the_works/static/js/validate_date.js b/the_works/static/js/validate_date.js
new file mode 100644
index 0000000..66c413d
--- /dev/null
+++ b/the_works/static/js/validate_date.js
@@ -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();
+ }
+ }
+}
+
diff --git a/the_works/static/the_works.js b/the_works/static/the_works.js
deleted file mode 100644
index 89eb006..0000000
--- a/the_works/static/the_works.js
+++ /dev/null
@@ -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 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
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, `${s}`) : "";
- tr.appendChild(td);
- }
- tbody.appendChild(tr);
- }
- table.appendChild(tbody);
- heading.innerHTML = `${db_table} (${tbody.childNodes.length} Treffer)
`;
-
- // add container element to DOM
- container.append(table);
- document.getElementById("results").appendChild(container);
-
- // open 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();
- }
- }
-}
-