Allow the user to assign additional cards after the ordering step

- Helptexts are not properly implemented yet
- Empty additional slots are not supported yet
This commit is contained in:
Lukas Fürderer 2020-08-23 19:05:50 +02:00
parent 9a855dbf7c
commit 15043de56a
3 changed files with 103 additions and 41 deletions

View File

@ -19,14 +19,17 @@
<path d="M20 0V20L0 10Z" fill="#2b8856" /> <path d="M20 0V20L0 10Z" fill="#2b8856" />
</svg> </svg>
</div> </div>
<template v-for="elem in solution"> <template v-for="(elem, row) in solution">
<div class="row"> <div class="row">
<div class="card" v-bind:class="{incorrect: incorrects[elem.main_idx]}"> <div v-for="(idx, column) in elem.idx" class="card" v-bind:class="{incorrect: column == store.section && incorrects[row]}">
{{ solution_main_text(elem) }} {{ solution_text(elem, column) }}
<svg width=20 height=20 v-if="!order_correct" v-on:click="remove_solution(elem)"> <svg width=20 height=20 v-if="column == store.section && !solution_correct" v-on:click="remove_solution(row)">
<path d="M2 2L18 18M18 2L2 18" stroke="#f00" stroke-width="2px" /> <path d="M2 2L18 18M18 2L2 18" stroke="#f00" stroke-width="2px" />
</svg> </svg>
</div> </div>
<svg v-if="elem.idx.length == store.section && store.selected != null" v-on:click="add_card_to(row)" class="plus" width="20" height="20">
<path d="M8 0H12V8H20V12H12V20H8V12H0V8H8Z" fill="#2b8856" />
</svg>
</div> </div>
<div class="arrow" v-bind:style="{visibility: arrows_visible ? 'visible' : 'hidden'}"> <div class="arrow" v-bind:style="{visibility: arrows_visible ? 'visible' : 'hidden'}">
<svg width="20" height="20" v-on:click="insert_after(elem)"> <svg width="20" height="20" v-on:click="insert_after(elem)">
@ -36,8 +39,9 @@
</template> </template>
</div> </div>
<div class="description"> <div class="description">
<div class="helptext" v-if="!all_inserted || order_revealed">{{ helptext }}</div> <div class="helptext" v-if="!all_inserted || solution_revealed">{{ helptext }}</div>
<button v-if="all_inserted && !order_revealed" v-on:click="reveal_order">Reihenfolge prüfen</button> <button v-if="all_inserted && !solution_revealed" v-on:click="reveal_order">Reihenfolge prüfen</button>
<button v-if="solution_correct" v-on:click="open_next_column">Weiter</button>
</div> </div>
<div class="close_button" v-on:click="is_open = false"> <div class="close_button" v-on:click="is_open = false">
<svg width="30" height="30"> <svg width="30" height="30">

View File

@ -37,6 +37,7 @@ body {
} }
#quiz .description { #quiz .description {
grid-area: 1 / 2 / 3 / 3; grid-area: 1 / 2 / 3 / 3;
overflow-y: auto;
padding: 10px; padding: 10px;
} }
#quiz .close_button { #quiz .close_button {
@ -94,6 +95,10 @@ body {
#quiz .row .card:hover svg { #quiz .row .card:hover svg {
visibility: visible; visibility: visible;
} }
#quiz .row svg.plus {
cursor: pointer;
vertical-align: middle;
}
#quiz .arrow { #quiz .arrow {
height: 0; height: 0;
width: 0; width: 0;

123
quiz.js
View File

@ -27,6 +27,34 @@ let cards_content = [
"Segen", "Segen",
"Entlassung", "Entlassung",
], ],
[
"Die versammelte Gemeinde wartet auf ihren Herrn, um mit ihm die Eucharistie zu feiern.",
"Wir beginnen mit der Feier. Das Kreuzzeichen macht uns bewusst, dass Gott (Vater, Sohn und Heiliger Geist) in unserer Gemeinschaft gegenwärtig ist. Es ist ein kurzes Glaubensbekenntnis",
"Die Gemeinde wird willkommen geheißen. Einstimmung auf den Gottesdienst und die damit verbundenen Anliegen.",
"Bekennen der eigenen Schuld, die uns voneinander und von Gott trennt, im Vertrauen darauf, dass Gott uns verzeiht und uns bedingungslos annimmt.",
"Begrüßungsruf, mit dem früher die Herrscher begrüßt wurden. Die Gläubigen rufen ihren Herrn Jesus Christus an und bitten ihn um seine Zuwendung.",
"Lobpreis Gottes",
"Kurzes zusammenfassendes Gebet im Namen der Gemeinde, verbunden mit dem Tagesanliegen des Gottesdienstes.",
"Die Erfahrungen des Volkes Israel mit seinem Gott Jahwe.",
"Meditation zur ersten Lesung",
"Erfahrungen der Apostel und der ersten Christengemeinden mit der Botschaft Jesu werden an uns heutige Menschen weitergegeben.",
"Jubelruf zur Begrüßung Jesu Christi.",
"Frohe Botschaft: Geschichte Gottes mit den Menschen auf das Leben und Wirken Jesu bezogen.",
"Deutung und Aktualisierung der frohen Botschaft für unser Leben.",
"Wir antworten auf Gottes Wort und seine Zuwendung, indem wir unseren Glauben an ihn bekennen.",
"Die Nöte und Sorgen der Menschen werden vor Gott ausgesprochen, mit der Bitte um seine Hilfe.",
"Mit Brot und Wein bringen wir uns selbst vor Gott, damit auch wir verwandelt werden. Wir bringen unsere Gaben für andere (Kollekte).",
"Großes Lob- und Dankgebet, Wechselgebet, Einleitung zum großen Dankgebet.",
"Lob Gottes",
"Jesus ist in den Zeichen von Brot und Wein bei uns. Die Gemeinschaft mit ihm befähigt uns, in seiner Nachfolge zu leben.",
"Im Gebet, das Jesus uns lehrte, sind die Grundbedürfnisse des Menschen angesprochen. Jesu Bitten sind unsere Bitten.",
"Frieden ist ein Geschenk Gottes. Gleichzeitig sind wir dazu aufgerufen, Frieden und Versöhnung unter den Menschen zu stiften.",
"Lamm Gottes: Das geteilte Brot, Zeichen dafür, dass alle Anteil haben an dem einen Leib Christi. Bitte um Erbarmen.",
"In Gemeinschaft verbunden mit Christus und untereinander. (Kumpane, lat. Cum pane = mit Brot; Kumpane sind Menschen, die miteinander durch gemeinsames Brotessen verbunden sind.)\nWir werden auf unserem Weg zu Gott gestärkt.",
"Dank für die Erfahrung der Nähe Gottes und dieser Gemeinschaft, Dank für die Stärkung durch die Kommunion.",
"Wir erhalten Stärkung und alle guten Wünsche für den Alltag, sowie den Auftrag, Gott in der Welt zu bezeugen.",
"Aufforderung, das Evangelium im Alltag zu leben und zu bezeugen.",
],
]; ];
function shuffle(a) { function shuffle(a) {
@ -38,9 +66,9 @@ function shuffle(a) {
} }
} }
function shuffle_cards() { function shuffle_cards(section) {
let a = []; let a = [];
for (let i=0; i<cards_content[0].length; i++) { for (let i=0; i<cards_content[section].length; i++) {
a.push(i); a.push(i);
} }
shuffle(a); shuffle(a);
@ -87,26 +115,25 @@ function choose_incorrects(idx_vals) {
options[result_chain].forEach((elem) => { options[result_chain].forEach((elem) => {
a[elem] = false; a[elem] = false;
}); });
return a; return idx_vals.map(idx => a[idx]);
} }
var app = new Vue({ var app = new Vue({
el: "#quiz", el: "#quiz",
data: { data: {
is_open: true, is_open: true,
cards_content,
store: { store: {
section: 0, section: 0,
selected: null, selected: null,
items: shuffle_cards(), items: shuffle_cards(0),
}, },
solution: [], solution: [],
order_revealed: false, solution_revealed: false,
}, },
computed: { computed: {
helptext: function() { helptext: function() {
if (this.order_revealed) { if (this.solution_revealed) {
if (this.order_correct) { if (this.solution_correct) {
return "Perfekt! Die Reihenfolge ist korrekt."; return "Perfekt! Die Reihenfolge ist korrekt.";
} else { } else {
return "Die Reihenfolge passt leider noch nicht ganz. Falsch eingeordnete Elemente sind rot markiert. Entferne diese mit einem Klick auf das rote X und füge sie neu ein, bis die Reihenfolge stimmt."; return "Die Reihenfolge passt leider noch nicht ganz. Falsch eingeordnete Elemente sind rot markiert. Entferne diese mit einem Klick auf das rote X und füge sie neu ein, bis die Reihenfolge stimmt.";
@ -126,39 +153,51 @@ var app = new Vue({
} }
}, },
all_inserted: function() { all_inserted: function() {
return this.solution.length == this.cards_content[0].length; if (this.store.section == 0) {
}, return this.solution.length == cards_content[0].length;
arrows_visible: function() {
return this.store.selected != null;
},
incorrects: function() {
if (this.order_revealed) {
let idx_vals = this.solution.map(elem => elem.main_idx);
return choose_incorrects(idx_vals);
} else { } else {
return []; let available = this.store.items.length;
let inserted = 0;
for (let i=0; i<this.solution.length; i++) {
if (this.solution[i].idx.length > this.store.section) {
inserted++;
}
}
return inserted == available;
} }
}, },
order_correct: function() { arrows_visible: function() {
return this.order_revealed && this.all_inserted && !this.incorrects.includes(true); return this.store.section == 0 && this.store.selected != null;
},
incorrects: function() {
if (!this.solution_revealed) {
return this.solution.map(elem => false);
}
if (this.store.section == 0) {
let idx_vals = this.solution.map(elem => elem.idx[0]);
return choose_incorrects(idx_vals);
} else {
return this.solution.map((elem, i) => {
return elem.idx.length > this.store.section
&& elem.idx[this.store.section] != i;
});
}
},
solution_correct: function() {
return this.solution_revealed && this.all_inserted && !this.incorrects.includes(true);
}, },
}, },
methods: { methods: {
store_text: function(idx) { store_text: function(idx) {
return this.cards_content[this.store.section][idx]; return cards_content[this.store.section][idx];
}, },
store_card_visible: function(idx) { store_card_visible: function(idx) {
for (let i=0; i<this.solution.length; i++) { return !this.solution.some(solution => solution.idx[this.store.section] == idx);
if (this.solution[i].main_idx == idx) {
return false;
}
}
return true;
}, },
store_select: function(i) { store_select: function(i) {
if (this.solution.length == 0) { if (this.solution.length == 0) {
this.solution.push({ this.solution.push({
main_idx: i, idx: [i],
}); });
} else if (i == this.store.selected) { } else if (i == this.store.selected) {
this.store.selected = null; this.store.selected = null;
@ -166,12 +205,12 @@ var app = new Vue({
this.store.selected = i; this.store.selected = i;
} }
}, },
solution_main_text: function(elem) { solution_text: function(elem, column) {
return cards_content[0][elem.main_idx]; return cards_content[column][elem.idx[column]];
}, },
insert_front: function() { insert_front: function() {
this.solution.splice(0, 0, { this.solution.splice(0, 0, {
main_idx: this.store.selected, idx: [this.store.selected],
}); });
this.store.selected = null; this.store.selected = null;
}, },
@ -184,15 +223,29 @@ var app = new Vue({
}, },
insert_after: function(elem) { insert_after: function(elem) {
this.solution.splice(this.find_solution(elem)+1, 0, { this.solution.splice(this.find_solution(elem)+1, 0, {
main_idx: this.store.selected, idx: [this.store.selected],
}); });
this.store.selected = null; this.store.selected = null;
}, },
remove_solution: function(elem) { remove_solution: function(row_idx) {
this.solution.splice(this.find_solution(elem), 1); if (this.store.section == 0) {
this.solution.splice(row_idx, 1);
} else {
this.solution[row_idx].idx.pop();
}
}, },
reveal_order: function() { reveal_order: function() {
this.order_revealed = true; this.solution_revealed = true;
},
open_next_column: function() {
this.store.section++;
this.store.selected = null;
this.store.items = shuffle_cards(this.store.section);
this.solution_revealed = false;
},
add_card_to: function(row) {
this.solution[row].idx.push(this.store.selected);
this.store.selected = null;
}, },
}, },
}); });