added processing and modifying genres associated with texts
This commit is contained in:
parent
4a842850d2
commit
afc5343b61
@ -58,7 +58,6 @@ nav {
|
|||||||
border-color: var(--pico-primary-border);
|
border-color: var(--pico-primary-border);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
table.dataTable span.dt-column-order::before,
|
table.dataTable span.dt-column-order::before,
|
||||||
table.dataTable span.dt-column-order::after
|
table.dataTable span.dt-column-order::after
|
||||||
{
|
{
|
||||||
@ -81,3 +80,7 @@ svg {
|
|||||||
content: " *";
|
content: " *";
|
||||||
color: #cf0000;
|
color: #cf0000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
label:has([type="checkbox"]) {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
@ -1,4 +1,5 @@
|
|||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
|
{% set SPLIT_CHARACTER = "|" %}
|
||||||
|
|
||||||
{% block title %}Texte{% endblock title %}
|
{% block title %}Texte{% endblock title %}
|
||||||
|
|
||||||
@ -7,14 +8,17 @@
|
|||||||
const SCRIPT_ROOT = {{ request.script_root | tojson }};
|
const SCRIPT_ROOT = {{ request.script_root | tojson }};
|
||||||
const textValues = ["Titel", "Untertitel"];
|
const textValues = ["Titel", "Untertitel"];
|
||||||
const selectValues = ["Reihe", "Textform", "Sprache"];
|
const selectValues = ["Reihe", "Textform", "Sprache"];
|
||||||
|
const multiSelectValues = ["Genres"];
|
||||||
|
|
||||||
function showCreateModal() {
|
function showCreateModal() {
|
||||||
// set modal heading
|
// set modal heading
|
||||||
document.getElementById("dialog-heading").textContent = "Text hinzufügen";
|
document.getElementById("dialog-heading").textContent = "Text hinzufügen";
|
||||||
// empty text inputs
|
// empty inputs
|
||||||
for (const v of textValues) { document.getElementById(`form_${v}`).value = ""; }
|
for (const v of textValues) { document.getElementById(`form_${v}`).value = ""; }
|
||||||
// empty select inputs
|
|
||||||
for (const v of selectValues) { document.getElementById(`form_${v}`).selectedIndex = ""; }
|
for (const v of selectValues) { document.getElementById(`form_${v}`).selectedIndex = ""; }
|
||||||
|
for (const v of multiSelectValues) {
|
||||||
|
document.getElementById(`form_${v}`).querySelectorAll("input[type=checkbox]").forEach( cb => { cb.checked = false; })
|
||||||
|
}
|
||||||
// set form action
|
// set form action
|
||||||
document.getElementById("form_submit").formAction = "{{ url_for('text.create') }}";
|
document.getElementById("form_submit").formAction = "{{ url_for('text.create') }}";
|
||||||
// show modal
|
// show modal
|
||||||
@ -22,34 +26,25 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function showUpdateModal() {
|
function showUpdateModal() {
|
||||||
let id = this.dataset.id;
|
let tr = document.getElementById(`text-${this.dataset.id}`);
|
||||||
let url = `${SCRIPT_ROOT}/text/read/${id}`;
|
|
||||||
fetch(url)
|
|
||||||
// throw error if network error occurred, get JSON data otherwise
|
|
||||||
.then((response) => {
|
|
||||||
if (response.ok) {
|
|
||||||
return response.json();
|
|
||||||
}
|
|
||||||
throw new Error ("There was an error while fetching data for the text with ID " + id);
|
|
||||||
})
|
|
||||||
// populate modal with response data and raise modal
|
|
||||||
.then(
|
|
||||||
function (response) {
|
|
||||||
console.log(response);
|
|
||||||
// set modal heading
|
// set modal heading
|
||||||
document.getElementById("dialog-heading").textContent = "Text ansehen / bearbeiten";
|
document.getElementById("dialog-heading").textContent = "Text ansehen / bearbeiten";
|
||||||
// populate text inputs
|
// populate inputs
|
||||||
for (const v of textValues) { document.getElementById(`form_${v}`).value = response[v]; }
|
for (const v of textValues) { document.getElementById(`form_${v}`).value = tr.querySelector(`[data-${v}]`).dataset[v.toLowerCase()]; }
|
||||||
// populate select imputs
|
for (const v of selectValues) { document.getElementById(`form_${v}`).selectedIndex = tr.querySelector(`[data-${v}]`).dataset[v.toLowerCase()]; }
|
||||||
for (const v of selectValues) { document.getElementById(`form_${v}`).selectedIndex = response[v]; }
|
for (const v of multiSelectValues) {
|
||||||
|
let data = tr.querySelector(`[data-${v}]`).dataset[v.toLowerCase()];
|
||||||
|
if ( data ) {
|
||||||
|
for (const i of data.split("{{ SPLIT_CHARACTER }}")) {
|
||||||
|
document.getElementById(`form_${v}_${i}`).checked = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// set form action
|
// set form action
|
||||||
document.getElementById("form_submit").formAction = `${SCRIPT_ROOT}/text/update/${id}`;
|
document.getElementById("form_submit").formAction = `${SCRIPT_ROOT}/text/update/${this.dataset.id}`;
|
||||||
// show modal
|
// show modal
|
||||||
document.getElementById("textmodal").showModal();
|
document.getElementById("textmodal").showModal();
|
||||||
}
|
}
|
||||||
)
|
|
||||||
.catch((error) => console.log(error));
|
|
||||||
}
|
|
||||||
|
|
||||||
window.onload = function () {
|
window.onload = function () {
|
||||||
// initialise DataTable
|
// initialise DataTable
|
||||||
@ -89,17 +84,19 @@
|
|||||||
<th>Reihe</th>
|
<th>Reihe</th>
|
||||||
<th>Textform</th>
|
<th>Textform</th>
|
||||||
<th>Sprache</th>
|
<th>Sprache</th>
|
||||||
|
<th>Genres</th>
|
||||||
<th colspan="2">Aktionen</th>
|
<th colspan="2">Aktionen</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for text in texte %}
|
{% for text in texte %}
|
||||||
<tr id="text-{{ text['id'] }}">
|
<tr id="text-{{ text['id'] }}">
|
||||||
<td title="Titel">{{ text["Titel"] }}</td>
|
<td data-Titel="{{ text['Titel'] }}" title="Titel">{{ text["Titel"] }}</td>
|
||||||
<td title="Untertitel">{{ text["Untertitel"] }}</td>
|
<td data-Untertitel="{{ text['Untertitel'] }}" title="Untertitel">{{ text["Untertitel"] }}</td>
|
||||||
<td title="Reihe">{{ text["Reihe"] }}</td>
|
<td data-Reihe="{{ text['r_id'] }}" title="Reihe">{{ text["Reihe"] }}</td>
|
||||||
<td title="Textform">{{ text["Textform"] }}</td>
|
<td data-Textform="{{ text['tf_id'] }}" title="Textform">{{ text["Textform"] }}</td>
|
||||||
<td title="Sprache">{{ text["Sprache"] }}</td>
|
<td data-Sprache="{{ text['s_id'] }}" title="Sprache">{{ text["Sprache"] }}</td>
|
||||||
|
<td data-Genres="{{ text['g_id_list'] | join(SPLIT_CHARACTER) }}" title="Genres">{{ text["Genre_list"] | join(SPLIT_CHARACTER) }}</td>
|
||||||
<td class="action action-update" data-id="{{ text['id'] }}"><a href="#" title="Text ansehen/bearbeiten"><svg viewbox="0 0 24 24"><use href="#update" /></svg></a></td>
|
<td class="action action-update" data-id="{{ text['id'] }}"><a href="#" title="Text ansehen/bearbeiten"><svg viewbox="0 0 24 24"><use href="#update" /></svg></a></td>
|
||||||
<td id="delete-{{ text['id'] }}" class="action"><a onclick="return confirm('Eintrag wirklich löschen?');" href="{{ url_for('text.delete', id=text['id']) }}" title="Text löschen"><svg viewbox="0 0 24 24"><use href="#delete" /></svg></a></td>
|
<td id="delete-{{ text['id'] }}" class="action"><a onclick="return confirm('Eintrag wirklich löschen?');" href="{{ url_for('text.delete', id=text['id']) }}" title="Text löschen"><svg viewbox="0 0 24 24"><use href="#delete" /></svg></a></td>
|
||||||
</tr>
|
</tr>
|
||||||
@ -118,8 +115,8 @@
|
|||||||
<fieldset>
|
<fieldset>
|
||||||
<article>
|
<article>
|
||||||
<label>
|
<label>
|
||||||
Titel (erforderlich)
|
<span class="required">Titel</span>
|
||||||
<input id="form_Titel" name="form_Titel" aria-Label="Titel" placeholder="Titel" required autofocus />
|
<input class="required" id="form_Titel" name="form_Titel" aria-Label="Titel" placeholder="Titel" required autofocus />
|
||||||
</label>
|
</label>
|
||||||
<label>
|
<label>
|
||||||
Untertitel
|
Untertitel
|
||||||
@ -133,19 +130,30 @@
|
|||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
<label>
|
<label>
|
||||||
Textform (erforderlich)
|
<span class="required">Textform</span>
|
||||||
<select id="form_Textform" name="form_Textform" aria-label="Textform" required>
|
<select id="form_Textform" name="form_Textform" aria-label="Textform" required>
|
||||||
<option selected disabled value="">Textform auswählen …</option>
|
<option selected disabled value="">Textform auswählen …</option>
|
||||||
{% for tf in textformen %}<option value="{{ tf.ID }}">{{ tf.Textform }}</option>{% endfor %}
|
{% for tf in textformen %}<option value="{{ tf.ID }}">{{ tf.Textform }}</option>{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
<label>
|
<label>
|
||||||
Sprache (erforderlich)
|
<span class="required">Sprache</span>
|
||||||
<select id="form_Sprache" name="form_Sprache" aria-label="Sprache des Textes" required>
|
<select id="form_Sprache" name="form_Sprache" aria-label="Sprache des Textes" required>
|
||||||
<option selected disabled value="">Sprache auswählen …</option>
|
<option selected disabled value="">Sprache auswählen …</option>
|
||||||
{% for s in sprachen %}<option value="{{ s.ID }}">{{ s.Sprache }}</option>{% endfor %}
|
{% for s in sprachen %}<option value="{{ s.ID }}">{{ s.Sprache }}</option>{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
|
<label>
|
||||||
|
Genre(s)
|
||||||
|
<details id="form_Genres" class="dropdown">
|
||||||
|
<summary>Genre(s) auswählen …</summary>
|
||||||
|
<ul>
|
||||||
|
{% for g in genres %}
|
||||||
|
<li><label><input id="form_Genres_{{ g.ID }}" name="form_Genres" type="checkbox" value="{{ g.ID }}" />{{ g.Genre }}</label></li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</details>
|
||||||
|
</label>
|
||||||
</article>
|
</article>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
from flask import Blueprint, render_template, request, redirect, flash, url_for
|
from flask import Blueprint, render_template, request, redirect, flash, url_for
|
||||||
from sqlalchemy import select, insert, update, delete
|
from sqlalchemy import select, insert, update, delete
|
||||||
|
from sqlalchemy.orm import joinedload
|
||||||
from the_works.database import db
|
from the_works.database import db
|
||||||
from the_works.models import Text, Reihe, Sprache, Textform
|
from the_works.models import Text, Reihe, Sprache, Textform, Text_Genre, Genre
|
||||||
|
|
||||||
bp = Blueprint("text", __name__)
|
bp = Blueprint("text", __name__)
|
||||||
|
|
||||||
@ -9,10 +10,10 @@ bp = Blueprint("text", __name__)
|
|||||||
@bp.route("/text/all")
|
@bp.route("/text/all")
|
||||||
def all():
|
def all():
|
||||||
# select all rows from table "Text", ORM style
|
# select all rows from table "Text", ORM style
|
||||||
rows = db.session.execute(select(Text, Reihe, Textform, Sprache).join(Text.reihe, isouter=True).join(Text.textform, isouter=True).join(Text.sprache, isouter=True))
|
rows = db.session.execute(select(Text, Reihe, Textform, Sprache).join(Text.reihe, isouter=True).join(Text.textform, isouter=True).join(Text.sprache, isouter=True).options(joinedload(Text.text_genre))).unique()
|
||||||
# condense result into list of dicts
|
# condense result into list of dicts
|
||||||
texte = []
|
texte = []
|
||||||
for row in rows:
|
for row in rows.all():
|
||||||
texte.append({
|
texte.append({
|
||||||
"id": row.Text.ID,
|
"id": row.Text.ID,
|
||||||
"Titel": row.Text.Titel,
|
"Titel": row.Text.Titel,
|
||||||
@ -22,9 +23,11 @@ def all():
|
|||||||
"Textform": row.Textform.Textform,
|
"Textform": row.Textform.Textform,
|
||||||
"tf_id": row.Text.Textform,
|
"tf_id": row.Text.Textform,
|
||||||
"Sprache": row.Sprache.Sprache,
|
"Sprache": row.Sprache.Sprache,
|
||||||
"s_id": row.Text.Sprache
|
"s_id": row.Text.Sprache,
|
||||||
|
"Genre_list": map(lambda tg: tg.genre.Genre, row.Text.text_genre) if row.Text.text_genre else [],
|
||||||
|
"g_id_list": map(lambda tg: tg.Genre, row.Text.text_genre) if row.Text.text_genre else []
|
||||||
})
|
})
|
||||||
return render_template("views/text.html", texte=texte, reihen=db.session.scalars(select(Reihe)), textformen=db.session.scalars(select(Textform)), sprachen=db.session.scalars(select(Sprache)))
|
return render_template("views/text.html", texte=texte, reihen=db.session.scalars(select(Reihe)), textformen=db.session.scalars(select(Textform)), sprachen=db.session.scalars(select(Sprache)), genres=db.session.scalars(select(Genre)))
|
||||||
|
|
||||||
@bp.route("/text/read/<int:id>")
|
@bp.route("/text/read/<int:id>")
|
||||||
def read(id):
|
def read(id):
|
||||||
@ -39,13 +42,16 @@ def read(id):
|
|||||||
|
|
||||||
@bp.route("/text/create", methods=["POST"])
|
@bp.route("/text/create", methods=["POST"])
|
||||||
def create():
|
def create():
|
||||||
db.session.add(Text(
|
text = Text(
|
||||||
Titel = request.form["form_Titel"],
|
Titel = request.form["form_Titel"],
|
||||||
Untertitel = request.form["form_Untertitel"] or None,
|
Untertitel = request.form["form_Untertitel"] or None,
|
||||||
Reihe = request.form["form_Reihe"] or None,
|
Reihe = request.form["form_Reihe"] or None,
|
||||||
Textform = request.form["form_Textform"],
|
Textform = request.form["form_Textform"],
|
||||||
Sprache = request.form["form_Sprache"]
|
Sprache = request.form["form_Sprache"]
|
||||||
))
|
)
|
||||||
|
for g in request.form.getlist("form_Genres"):
|
||||||
|
text.genres.append(g)
|
||||||
|
db.session.add(text)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
flash("Eintrag erfolgreich hinzugefügt")
|
flash("Eintrag erfolgreich hinzugefügt")
|
||||||
return redirect(url_for("text.all"))
|
return redirect(url_for("text.all"))
|
||||||
@ -60,6 +66,12 @@ def update(id):
|
|||||||
text.Reihe = request.form["form_Reihe"] or None
|
text.Reihe = request.form["form_Reihe"] or None
|
||||||
text.Textform = request.form["form_Textform"]
|
text.Textform = request.form["form_Textform"]
|
||||||
text.Sprache = request.form["form_Sprache"]
|
text.Sprache = request.form["form_Sprache"]
|
||||||
|
# update genre list by removing genres not in form selection and adding selected ones not currently in list
|
||||||
|
form_set = set(map(lambda g: int(g), request.form.getlist("form_Genres")))
|
||||||
|
for g in set(text.genres) - form_set:
|
||||||
|
text.genres.remove(g)
|
||||||
|
for g in form_set - set(text.genres):
|
||||||
|
text.genres.append(g)
|
||||||
# commit changes
|
# commit changes
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
flash("Eintrag erfolgreich geändert")
|
flash("Eintrag erfolgreich geändert")
|
||||||
@ -72,4 +84,3 @@ def delete(id):
|
|||||||
db.session.commit()
|
db.session.commit()
|
||||||
flash("Eintrag erfolgreich gelöscht")
|
flash("Eintrag erfolgreich gelöscht")
|
||||||
return redirect(url_for("text.all"))
|
return redirect(url_for("text.all"))
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user