built custom dropdown field to select a titelbild from the database
This commit is contained in:
parent
edb19bde80
commit
bcf8fa5d66
@ -171,8 +171,8 @@ form:not([novalidate]) input:user-valid[type="search"] {
|
||||
}
|
||||
|
||||
/* style for Klappentext tooltips */
|
||||
[data-tooltip][data-placement="bottom"]::after,
|
||||
[data-tooltip][data-placement="bottom"]::before {
|
||||
[data-tooltip][data-placement="bottom"]:after,
|
||||
[data-tooltip][data-placement="bottom"]:before {
|
||||
white-space: pre-line;
|
||||
max-width: 400px;
|
||||
}
|
||||
@ -212,6 +212,68 @@ form:not([novalidate]) input:user-valid[type="search"] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* imageselect styles */
|
||||
label:has([type="radio"]) {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.imageselect-entry,
|
||||
.imageselect-entry-summary {
|
||||
display: inline grid;
|
||||
grid-template-columns: 2rem 2rem auto;
|
||||
grid-column-gap: var(--pico-form-element-spacing-horizontal);
|
||||
align-content: center;
|
||||
height: calc(1rem * var(--pico-line-height) + var(--pico-form-element-spacing-vertical) * 2 + var(--pico-border-width) * 2);
|
||||
padding: var(--pico-form-element-spacing-vertical) var(--pico-form-element-spacing-horizontal);
|
||||
|
||||
.imageselect-div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
border: var(--pico-border-width) solid var(--pico-table-border-color);
|
||||
cursor: zoom-in;
|
||||
max-height: 100%;
|
||||
text-align: center;
|
||||
width: calc(1rem * var(--pico-line-height));
|
||||
|
||||
/* display: block;
|
||||
padding: 0px;
|
||||
margin: auto;*/
|
||||
}
|
||||
|
||||
.imageselect-img,
|
||||
.imageselect-svg {
|
||||
object-fit: contain;
|
||||
height: calc(1rem * var(--pico-line-height));
|
||||
}
|
||||
}
|
||||
|
||||
details.imageselect > summary.imageselect-summary {
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
#imagepreview-modal {
|
||||
max-height: 95vh;
|
||||
|
||||
.imagepreview-div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* .imageselect-overlay {
|
||||
position: absolute;
|
||||
top: 50px;
|
||||
left: 50px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.imageselect-div:hover .imageselect-overlay {
|
||||
display: block;
|
||||
} */
|
||||
|
||||
|
||||
[data-display-werksform]::before {
|
||||
|
||||
20
the_works/static/js/imagepreview.js
Normal file
20
the_works/static/js/imagepreview.js
Normal file
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* IMAGEPREVIEW FUNCTIONS
|
||||
*/
|
||||
function initImagepreview(modal_id) {
|
||||
// event handlers for all the thumbnails that raise the preview modal on click
|
||||
document.querySelectorAll(".imageselect-div").forEach(el => el.addEventListener("click", handleImagepreview, true));
|
||||
// enable closing the modal
|
||||
document.getElementById(modal_id).addEventListener("click", event => event.target.close());
|
||||
document.querySelector("dialog button.modal-close").addEventListener("click", event => event.target.closest("dialog").close());
|
||||
}
|
||||
|
||||
function handleImagepreview(event) {
|
||||
let modal = document.getElementById("imagepreview-modal");
|
||||
modal.querySelector("img").setAttribute("src", event.target.closest(".imageselect-entry").dataset["bild"]);
|
||||
modal.querySelector(".imagepreview-details").innerText = event.target.closest(".imageselect-entry").querySelector(".imageselect-label").innerText;
|
||||
modal.showModal();
|
||||
if ( event.target.closest(".imageselect-entry").localName.toLowerCase() == "div" ) {
|
||||
event.stopPropagation();
|
||||
}
|
||||
}
|
||||
53
the_works/static/js/imageselect.js
Normal file
53
the_works/static/js/imageselect.js
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* IMAGESELECT FUNCTIONS
|
||||
*/
|
||||
// initialize imege select with given id
|
||||
function initImageselect(id) {
|
||||
console.log("this is initImageselect!");
|
||||
let is = document.getElementById(id);
|
||||
// add event listener to radio buttons
|
||||
let summary = is.querySelector("summary");
|
||||
let input_name = is.querySelector("input[type='radio']").getAttribute("name");
|
||||
document.querySelectorAll(`[name='${input_name}']`).forEach( el => {
|
||||
el.addEventListener("change", event => updateImageselect(event.target, summary));
|
||||
if ( el.checked ) {
|
||||
el.dispatchEvent(new Event("change"));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// event handler for imageselect radio buttons; displays the selected entry in the dropdown's summary element
|
||||
function updateImageselect(that, summary) {
|
||||
// clear summary contents
|
||||
summary.innerHTML = "";
|
||||
|
||||
// create new element which will contain a copy of the entry in the dropdown menu
|
||||
let div = document.createElement("div");
|
||||
div.classList.add("imageselect-entry");
|
||||
div.dataset["bild"] = that.closest(".imageselect-entry").dataset["bild"];
|
||||
|
||||
// remove radio button's attributes id (no duplicates allowed) and name (so it won't count towards the form)
|
||||
let n = that.closest(".imageselect-entry").querySelector(".imageselect-input").cloneNode(true);
|
||||
n.firstElementChild.removeAttribute("name");
|
||||
n.firstElementChild.removeAttribute("id");
|
||||
n.firstElementChild.setAttribute("checked", "");
|
||||
div.appendChild(n);
|
||||
|
||||
// clone image part
|
||||
n = that.closest(".imageselect-entry").querySelector(".imageselect-div").cloneNode(true);
|
||||
n.addEventListener("click", handleImagepreview, true);
|
||||
div.appendChild(n);
|
||||
|
||||
// remove label element (but keep the contents) so it doesn't interfere with the dropdown functionality
|
||||
n = that.closest(".imageselect-entry").querySelector(".imageselect-title").cloneNode(true);
|
||||
let innerText = n.firstElementChild.innerText;
|
||||
n.classList.add("imageselect-label");
|
||||
n.firstElementChild.remove();
|
||||
n.innerText = innerText;
|
||||
div.appendChild(n);
|
||||
|
||||
// add div to summary
|
||||
summary.appendChild(div);
|
||||
}
|
||||
|
||||
@ -9,7 +9,6 @@ function initModal(modal_id, input_ids, headings, form_actions) {
|
||||
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,
|
||||
@ -19,6 +18,8 @@ console.log(`input_ids is ${input_ids}`);
|
||||
event.currentTarget.dataset.id
|
||||
));
|
||||
}
|
||||
// add event listener to close button
|
||||
document.querySelector("dialog button.modal-close").addEventListener("click", event => event.target.closest("dialog").close());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
// initializes all dropdown selects on the page
|
||||
function initAllMultiselects() {
|
||||
// initialize each dropdown individually
|
||||
let dropdowns = document.querySelectorAll("form details.dropdown");
|
||||
let dropdowns = document.querySelectorAll("form details.multiselect");
|
||||
dropdowns.forEach(d => initMultiselect(d));
|
||||
// now it's time to set the z-indices
|
||||
// get the_works style sheet
|
||||
@ -24,7 +24,7 @@ function initAllMultiselects() {
|
||||
}
|
||||
}
|
||||
// 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));
|
||||
document.querySelectorAll("form details.multiselect summary").forEach(summary => summary.addEventListener("click", event => summaryClick(event, summary), true));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -45,6 +45,7 @@ Werk bearbeiten
|
||||
{% for wf in werksformen %}<option value="{{ wf.ID }}"{% if wf.ID == werk['Werksform'] %} selected{% endif %}>{{ wf.Werksform }}</option>{% endfor %}
|
||||
</select>
|
||||
</label>
|
||||
<div class="grid">
|
||||
<label>
|
||||
Reihe
|
||||
<select id="form_Reihe" name="form_Reihe" aria-label="Der Text gehört zur Reihe …">
|
||||
@ -56,6 +57,7 @@ Werk bearbeiten
|
||||
Reihennummer
|
||||
<input id="form_Reihennummer" name="form_Reihennummer" aria-label="Reihennummer" placeholder="keine Reihennummer" value="{{ werk['Reihennummer'] or '' }}" />
|
||||
</label>
|
||||
</div>
|
||||
<label>
|
||||
Verlag
|
||||
<select id="form_Verlag" name="form_Verlag" aria-label="Verlag">
|
||||
@ -67,6 +69,41 @@ Werk bearbeiten
|
||||
Preis
|
||||
<input id="form_Preis" name="form_Preis" aria-label="Preis" placeholder="kein Preis" value="{{ werk['Preis'] or '' }}" />
|
||||
</label>
|
||||
<label>
|
||||
Titelbild
|
||||
<details id="form_Titelbild_dropdown" class="dropdown imageselect">
|
||||
<summary id="form_Titelbild_summary" class="imageselect-summary">
|
||||
</summary>
|
||||
<ul>
|
||||
<li class="imageselect-entry" data-bild="">
|
||||
<div class="imageselect-input">
|
||||
<input id="imageselect-radio-0" type="radio" name="form_Titelbild" value="" {% if not werk['Titelbild'] %}checked{% endif %}/>
|
||||
</div>
|
||||
<div class="imageselect-div">
|
||||
<svg viewbox="0 0 90 128">
|
||||
<use class="imageselect-svg" href="#placeholder" />
|
||||
</svg>
|
||||
</div>
|
||||
<div class="imageselect-title">
|
||||
<label class="imageselect-label" for="imageselect-radio-0">kein Titelbild</label>
|
||||
</div>
|
||||
</li>
|
||||
{% for t in titelbilder %}
|
||||
<li class="imageselect-entry" data-bild="{{ t.Bild }}">
|
||||
<div class="imageselect-input">
|
||||
<input id="imageselect-radio-{{ t.ID }}" type="radio" name="form_Titelbild" value="{{ t.ID }}" {% if werk['Titelbild'] == t.ID %}checked{% endif %}/>
|
||||
</div>
|
||||
<div class="imageselect-div">
|
||||
<img class="imageselect-img" src="{{ t.Thumbnail }}" />
|
||||
</div>
|
||||
<div class="imageselect-title">
|
||||
<label class="imageselect-label" for="imageselect-radio-{{ t.ID }}">{{ t.Dateiname }} ({{ t.Breite }} x {{ t.Hoehe }}, {{ t.Dateigroesse }} Bytes)</label>
|
||||
</div>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</details>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label>
|
||||
@ -91,7 +128,7 @@ Werk bearbeiten
|
||||
</label>
|
||||
<label>
|
||||
Genre(s)
|
||||
<details id="form_Genre_dropdown" class="dropdown">
|
||||
<details id="form_Genre_dropdown" class="dropdown multiselect">
|
||||
<summary id="form_Genre_summary" data-default="kein Genre ausgewählt"></summary>
|
||||
<ul>
|
||||
<li>
|
||||
@ -110,7 +147,7 @@ Werk bearbeiten
|
||||
</label>
|
||||
<label>
|
||||
Herausgeber:in(nen)
|
||||
<details id="form_Herausgeber_dropdown" class="dropdown">
|
||||
<details id="form_Herausgeber_dropdown" class="dropdown multiselect">
|
||||
<summary id="form_Herausgeber_summary" data-default="kein(e) Herausgeber:in(nen) ausgewählt"></summary>
|
||||
<ul>
|
||||
<li>
|
||||
@ -141,35 +178,6 @@ Werk bearbeiten
|
||||
{{ werk['Anmerkungen'] or '' }}</textarea>
|
||||
</label>
|
||||
</section>
|
||||
<hr />
|
||||
<section>
|
||||
<label>
|
||||
Titelbild
|
||||
<div id="titelbild-wrapper">
|
||||
<div id="titelbild-pic">
|
||||
<a id="titelbild-link" href="{{ titelbild['Bild'] | default('') }}" title="zum Originalbild"{{ ' class="display-none"' | safe if not titelbild }}>
|
||||
<img id="titelbild-thumbnail" alt="Thumbnail" src="{{ titelbild['Thumbnail'] | default('') }}" />
|
||||
</a>
|
||||
<div id="titelbild-placeholder"{{ ' class="display-none"' | safe if titelbild }}>
|
||||
<svg viewbox="0 0 90 128">
|
||||
<use href="#placeholder" />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div id="titelbild-controls">
|
||||
<button id="titelbild-delete" class="contrast" type="button"{{ ' disabled' | safe if not titelbild }}>Bild löschen</button>
|
||||
<input type="file" id="titelbild-upload" name="form_Titelbild" aria-label="Titelbild" placeholder="kein Titelbild" accept="image/*"/>
|
||||
<input type="hidden" id="titelbild-haschanged" name="form_Titelbild_haschanged" value="" />
|
||||
</div>
|
||||
<div id="titelbild-info"{{ ' class="display-none"' | safe if not titelbild }}>
|
||||
<small>
|
||||
Dateigröße: <span id="titelbild-dateigroesse">{{ titelbild["Dateigroesse"] | default('') }}</span> Bytes<br />
|
||||
Abmessungen: <span id="titelbild-breite">{{ titelbild["Breite"] | default('') }}</span>x<span id="titelbild-hoehe">{{ titelbild["Hoehe"] | default('') }}</span> px
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
</section>
|
||||
|
||||
<footer class="grid">
|
||||
<button id="form_submit" type="submit" onclick="return validate_date()" formmethod="post" formaction="{% if create_mode %}{{ url_for('werk.create') }}{% else %}{{ url_for('werk.update', id=werk['ID']) }}{% endif %}">
|
||||
@ -179,14 +187,31 @@ Werk bearbeiten
|
||||
<a role="button" class="contrast" href="{{ url_for('werk.all') }}">Abbrechen (nicht speichern)</a>
|
||||
</footer>
|
||||
</form>
|
||||
|
||||
<dialog id="imagepreview-modal">
|
||||
<article>
|
||||
<header>
|
||||
<button class="modal-close" aria-label="close" rel="prev"></button>
|
||||
<div class="imagepreview-details"></div>
|
||||
</header>
|
||||
<div class="imagepreview-div">
|
||||
<img src="#" alt="#" />
|
||||
</div>
|
||||
</article>
|
||||
</dialog>
|
||||
|
||||
{% endblock content %}
|
||||
|
||||
{% block script %}
|
||||
<script src="{{ url_for('static', filename='js/multiselect.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/imageselect.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/imagepreview.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/validate_date.js') }}"></script>
|
||||
<script>
|
||||
window.onload = () => {
|
||||
initAllMultiselects();
|
||||
initImageselect("form_Titelbild_dropdown");
|
||||
initImagepreview("imagepreview-modal");
|
||||
}
|
||||
</script>
|
||||
{% endblock script %}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user