Finish remaining question types
This commit is contained in:
parent
0d54f756d8
commit
5bd1e821f7
20 changed files with 431 additions and 8 deletions
|
@ -3,3 +3,38 @@
|
|||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.acrostic-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.acrostic-offset,.acrostic-number {
|
||||
display: inline-block;
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
border: 2px solid transparent;
|
||||
}
|
||||
|
||||
.acrostic-input {
|
||||
padding: 0;
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
text-transform: uppercase;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.acrostic-column {
|
||||
background-color: lightgrey;
|
||||
}
|
||||
|
||||
.connections-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 25% 25% 25% 25%;
|
||||
}
|
||||
|
||||
.connections-element {
|
||||
border: 1px solid black;
|
||||
margin: 0.5em;
|
||||
padding: 1em;
|
||||
}
|
||||
|
|
|
@ -24,4 +24,16 @@ class QuestionsController < ApplicationController
|
|||
def handle_politicians_answer
|
||||
@answer.update!(data: params[:order])
|
||||
end
|
||||
|
||||
def handle_acrostic_answer
|
||||
@answer.update!(data: params[:data])
|
||||
end
|
||||
|
||||
def handle_connections_answer
|
||||
@answer.update!(data: params[:order])
|
||||
end
|
||||
|
||||
def handle_lyrics_answer
|
||||
@answer.update!(data: params[:data])
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,6 +4,7 @@ class SectionsController < ApplicationController
|
|||
end
|
||||
|
||||
def show
|
||||
@sections = Section.all
|
||||
@section = Section.find(params[:id])
|
||||
@questions = @section.questions.includes(:answer)
|
||||
end
|
||||
|
|
39
app/javascript/acrostic_answer.js
Normal file
39
app/javascript/acrostic_answer.js
Normal file
|
@ -0,0 +1,39 @@
|
|||
import { submitValueDebounced } from './submit_value.js'
|
||||
|
||||
export default function initAcrosticQuestions() {
|
||||
document.querySelectorAll('[data-behaviour="question_acrostic"]').forEach((acrostic) => {
|
||||
const submitUrl = acrostic.dataset.submitUrl
|
||||
const _submit = submitValueDebounced()
|
||||
|
||||
const allInputs = Array.from(acrostic.querySelectorAll(".acrostic-input"))
|
||||
|
||||
function submit() {
|
||||
const data = allInputs.map((input) => input.value)
|
||||
_submit(submitUrl, {data})
|
||||
}
|
||||
|
||||
allInputs.forEach((input) => {
|
||||
const index = Number.parseInt(input.dataset.index)
|
||||
const previous = acrostic.querySelector(`.acrostic-input[data-index="${index - 1}"]`)
|
||||
const next = acrostic.querySelector(`.acrostic-input[data-index="${index + 1}"]`)
|
||||
input.addEventListener('input', (event) => {
|
||||
if (event.data) {
|
||||
input.value = event.data[0]
|
||||
}
|
||||
submit()
|
||||
if (event.data) {
|
||||
if (next) {
|
||||
next.focus()
|
||||
}
|
||||
} else {
|
||||
if (previous) {
|
||||
previous.focus()
|
||||
}
|
||||
}
|
||||
})
|
||||
input.addEventListener('focus', () => {
|
||||
input.select()
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
|
@ -2,9 +2,19 @@
|
|||
import initSimpleQuestions from './simple_input.js'
|
||||
import initImageQuestions from './image_input.js'
|
||||
import initPoliticianQuestions from './politicians_answer.js'
|
||||
import initAcrosticQuestions from './acrostic_answer.js'
|
||||
import initConnectionsQuestions from './connections_answer.js'
|
||||
import initLyricsQuestions from './lyrics_answer.js'
|
||||
|
||||
import { Sortable, Swap } from 'sortablejs'
|
||||
|
||||
Sortable.mount(new Swap())
|
||||
|
||||
addEventListener("DOMContentLoaded", () => {
|
||||
initSimpleQuestions()
|
||||
initImageQuestions()
|
||||
initPoliticianQuestions()
|
||||
initAcrosticQuestions()
|
||||
initConnectionsQuestions()
|
||||
initLyricsQuestions()
|
||||
})
|
||||
|
|
19
app/javascript/connections_answer.js
Normal file
19
app/javascript/connections_answer.js
Normal file
|
@ -0,0 +1,19 @@
|
|||
import { Sortable } from 'sortablejs'
|
||||
|
||||
import { submitValue } from './submit_value.js'
|
||||
|
||||
export default function initConnectionsQuestions() {
|
||||
|
||||
|
||||
document.querySelectorAll('[data-behaviour="connections_answer').forEach((list) => {
|
||||
const submitUrl = list.dataset.submitUrl
|
||||
|
||||
Sortable.create(list, {
|
||||
swap: true,
|
||||
onUpdate: (event) => {
|
||||
const newOrder = Array.from(event.to.children).map((el) => Number.parseInt(el.dataset.id))
|
||||
submitValue(submitUrl, { order: newOrder })
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
21
app/javascript/lyrics_answer.js
Normal file
21
app/javascript/lyrics_answer.js
Normal file
|
@ -0,0 +1,21 @@
|
|||
import { submitValueDebounced } from './submit_value.js'
|
||||
|
||||
export default function initLyricsQuestions() {
|
||||
document.querySelectorAll('[data-behaviour="lyrics_answer"]').forEach((lyrics) => {
|
||||
const submitUrl = lyrics.dataset.submitUrl
|
||||
const _submit = submitValueDebounced()
|
||||
|
||||
const allInputs = Array.from(lyrics.querySelectorAll(".lyrics-input"))
|
||||
|
||||
function submit() {
|
||||
const data = allInputs.map((input) => input.value)
|
||||
_submit(submitUrl, {data})
|
||||
}
|
||||
|
||||
allInputs.forEach((input) => {
|
||||
const index = Number.parseInt(input.dataset.index)
|
||||
input.addEventListener('input', () => submit())
|
||||
input.addEventListener('change', () => submit())
|
||||
})
|
||||
})
|
||||
}
|
|
@ -1,11 +1,8 @@
|
|||
import { Sortable, Swap } from 'sortablejs'
|
||||
import { Sortable } from 'sortablejs'
|
||||
|
||||
import { submitValue } from './submit_value.js'
|
||||
|
||||
export default function initPoliticianQuestions() {
|
||||
|
||||
Sortable.mount(new Swap())
|
||||
|
||||
document.querySelectorAll('[data-behaviour="politicians_answer').forEach((list) => {
|
||||
const submitUrl = list.dataset.submitUrl
|
||||
|
||||
|
|
|
@ -21,8 +21,8 @@
|
|||
# section_id (section_id => sections.id)
|
||||
#
|
||||
class Question < ApplicationRecord
|
||||
enum :answer_kind, { simple: 0, image: 1, politicians: 2 }, prefix: true
|
||||
enum :question_kind, { simple: 0, video: 1 }, prefix: true
|
||||
enum :answer_kind, { simple: 0, image: 1, politicians: 2, acrostic: 3, connections: 4, lyrics: 5 }, prefix: true
|
||||
enum :question_kind, { simple: 0, video: 1, acrostic: 3 }, prefix: true
|
||||
|
||||
belongs_to :section
|
||||
has_one :answer
|
||||
|
|
22
app/views/questions/_acrostic_form.html.erb
Normal file
22
app/views/questions/_acrostic_form.html.erb
Normal file
|
@ -0,0 +1,22 @@
|
|||
<% max_position = question.data.map { |c| c["position"] }.max %>
|
||||
<% index = -1 %>
|
||||
<div class="acrostic-puzzle"
|
||||
data-behaviour="question_acrostic"
|
||||
data-submit-url="<%= answer_question_url(question.id) %>"
|
||||
>
|
||||
<% question.data.each.with_index do |constraints, i| %>
|
||||
<div class="acrostic-row">
|
||||
<span class="acrostic-number"><%= i + 1 %></span>
|
||||
<% (max_position - constraints["position"]).times do %>
|
||||
<span class="acrostic-offset"></span>
|
||||
<% end %>
|
||||
<% (constraints["position"] - 1).times do %>
|
||||
<%= render partial: "questions/acrostic_input", locals: {on_column: false, index: (index += 1), answer_data: question.answer&.data} %>
|
||||
<% end %>
|
||||
<%= render partial: "questions/acrostic_input", locals: {on_column: true, index: (index += 1), answer_data: question.answer&.data} %>
|
||||
<% (constraints["length"] - constraints["position"]).times do %>
|
||||
<%= render partial: "questions/acrostic_input", locals: {on_column: false, index: (index += 1), answer_data: question.answer&.data} %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
6
app/views/questions/_acrostic_input.html.erb
Normal file
6
app/views/questions/_acrostic_input.html.erb
Normal file
|
@ -0,0 +1,6 @@
|
|||
<%= tag.input class: {"acrostic-input": true, "acrostic-column": on_column},
|
||||
data: {index: index},
|
||||
value: answer_data&.then { |it| it[index] },
|
||||
type: "text",
|
||||
autocomplete: "off"
|
||||
%>
|
3
app/views/questions/_acrostic_show.html.erb
Normal file
3
app/views/questions/_acrostic_show.html.erb
Normal file
|
@ -0,0 +1,3 @@
|
|||
<% question.text.lines.each.with_index do |q, i| %>
|
||||
<p><strong><%= i + 1 %>.</strong> <%= q %></p>
|
||||
<% end %>
|
11
app/views/questions/_connections_form.html.erb
Normal file
11
app/views/questions/_connections_form.html.erb
Normal file
|
@ -0,0 +1,11 @@
|
|||
<div
|
||||
class="connections-grid"
|
||||
data-behaviour="connections_answer"
|
||||
data-submit-url="<%= answer_question_url(question.id) %>"
|
||||
>
|
||||
<% answers = question.data.each.with_index.to_a %>
|
||||
<% answers = reorder_with_indices(answers, question.answer.data) if question.answer.present? %>
|
||||
<% answers.each do |a, i| %>
|
||||
<span class="connections-element" data-id="<%= i %>"><%= a %></span>
|
||||
<% end %>
|
||||
</div>
|
15
app/views/questions/_lyrics_form.html.erb
Normal file
15
app/views/questions/_lyrics_form.html.erb
Normal file
|
@ -0,0 +1,15 @@
|
|||
<% index = -1 %>
|
||||
<div data-behaviour="lyrics_answer"
|
||||
data-submit-url="<%= answer_question_url(question.id) %>"
|
||||
>
|
||||
<% question.data.lines.each do |l| %>
|
||||
<% parts = l.split "{}", -1 %>
|
||||
<p>
|
||||
<%= render partial: "questions/lyrics_given_part", locals: {text: parts[0]} %>
|
||||
<% parts[1..].each do |text| %>
|
||||
<%= render partial: "questions/lyrics_input", locals: {index: (index += 1), answer_data: question.answer&.data} %>
|
||||
<%= render partial: "questions/lyrics_given_part", locals: {text: text} %>
|
||||
<% end %>
|
||||
</p>
|
||||
<% end %>
|
||||
</div>
|
3
app/views/questions/_lyrics_given_part.html.erb
Normal file
3
app/views/questions/_lyrics_given_part.html.erb
Normal file
|
@ -0,0 +1,3 @@
|
|||
<% if text.present? %>
|
||||
<span><%= text %></span>
|
||||
<% end %>
|
6
app/views/questions/_lyrics_input.html.erb
Normal file
6
app/views/questions/_lyrics_input.html.erb
Normal file
|
@ -0,0 +1,6 @@
|
|||
<%= tag.input class: "lyrics-input",
|
||||
data: {index: index},
|
||||
value: answer_data&.then { |it| it[index] },
|
||||
type: "text",
|
||||
autocomplete: "off"
|
||||
%>
|
|
@ -5,8 +5,8 @@
|
|||
<% end %>
|
||||
</div>
|
||||
<div data-behaviour="politicians_answer"
|
||||
data-submit-url="<%= answer_question_url(question.id) %>"
|
||||
>
|
||||
data-submit-url="<%= answer_question_url(question.id) %>"
|
||||
>
|
||||
<% answers = question.data["right"].each.with_index.to_a %>
|
||||
<% answers = reorder_with_indices(answers, question.answer.data) if question.answer.present? %>
|
||||
<% answers.each do |a, i| %>
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
<%= link_to sections_url do %>Home<% end %>
|
||||
<% @sections.each do |section| %>
|
||||
<%= link_to section.title, section_url(section) %>
|
||||
<% end %>
|
||||
|
||||
<h4><%= @section.title %></h4>
|
||||
|
||||
<p><%= @section.description %></p>
|
||||
|
|
202
test/fixtures/questions.yml
vendored
202
test/fixtures/questions.yml
vendored
|
@ -421,3 +421,205 @@ photos_sint_kruis_winkel:
|
|||
text: De grens met Zelzate.
|
||||
answer_kind: <%= Question.answer_kinds[:image] %>
|
||||
question_kind: <%= Question.question_kinds[:simple] %>
|
||||
|
||||
acrostic_acrostic:
|
||||
section: acrostic
|
||||
text: |
|
||||
Wat is het oudste publiek toegankelijke museum van België?
|
||||
Waar is Chokri Ben Chika tegen?
|
||||
Waar kan je met je oldtimer binnen met een dagpas?
|
||||
Wat is de bijnaam van de Gentenaar?
|
||||
Wie kan je bewonderen in Poppentheater Pedrolino?
|
||||
Welke dag gaan jullie het slechtst slapen?
|
||||
Welke mini Gentse Feesten gaan door rond 15 augustus?
|
||||
data: '<%= JSON.dump([
|
||||
{ position: 3, length: 3 },
|
||||
{ position: 5, length: 8 },
|
||||
{ position: 3, length: 3 },
|
||||
{ position: 7, length: 14 },
|
||||
{ position: 4, length: 14 },
|
||||
{ position: 3, length: 9 },
|
||||
{ position: 11, length: 16 },
|
||||
]) %>'
|
||||
answer_kind: <%= Question.answer_kinds[:acrostic] %>
|
||||
question_kind: <%= Question.question_kinds[:acrostic] %>
|
||||
|
||||
connections_buildings:
|
||||
section: connections
|
||||
text: Gebouwen
|
||||
data: '<%=
|
||||
JSON.dump(
|
||||
["Huwelijk", "Burcht", "Middeleeuwen", "Nieuw slot", "UGent", "Wetenschap", "Museum", "Plantentuin", "Hotel", "Matexi", "Provincie", "Defensie"].shuffle
|
||||
)
|
||||
%>'
|
||||
answer_kind: <%= Question.answer_kinds[:connections] %>
|
||||
question_kind: <%= Question.question_kinds[:simple] %>
|
||||
|
||||
connections_food:
|
||||
section: connections
|
||||
text: Eten
|
||||
data: '<%=
|
||||
JSON.dump(
|
||||
["Bouillon", "Kip", "Kervel", "Brood", "Neus", "Kegel", "Framboos", "Kraam", "Kaneel", "Bruine suiker", "Hondsdolheid", "Sint-Hubertus"].shuffle
|
||||
)
|
||||
%>'
|
||||
answer_kind: <%= Question.answer_kinds[:connections] %>
|
||||
question_kind: <%= Question.question_kinds[:simple] %>
|
||||
|
||||
connections_sport:
|
||||
section: connections
|
||||
text: Sport
|
||||
data: '<%=
|
||||
JSON.dump(
|
||||
["Marathon", "Tokyo", "Somalië", "1989", "5K", "Roeien", "Nachez", "Blaarmeersen", "Voetbal", "Baro", "2013", "Arteveldestadion"].shuffle
|
||||
)
|
||||
%>'
|
||||
answer_kind: <%= Question.answer_kinds[:connections] %>
|
||||
question_kind: <%= Question.question_kinds[:simple] %>
|
||||
|
||||
translations_lousbirge:
|
||||
section: translations
|
||||
text: "we goan eu in Lousbirge steeke"
|
||||
answer_kind: <%= Question.answer_kinds[:simple] %>
|
||||
question_kind: <%= Question.question_kinds[:simple] %>
|
||||
|
||||
translations_alvekoate:
|
||||
section: translations
|
||||
text: "da weete mijn kluuten uuk en 't zijn gîen alvekoate"
|
||||
answer_kind: <%= Question.answer_kinds[:simple] %>
|
||||
question_kind: <%= Question.question_kinds[:simple] %>
|
||||
|
||||
translations_deursteeke:
|
||||
section: translations
|
||||
text: "de koarte deursteeke"
|
||||
answer_kind: <%= Question.answer_kinds[:simple] %>
|
||||
question_kind: <%= Question.question_kinds[:simple] %>
|
||||
|
||||
translations_dampuurte:
|
||||
section: translations
|
||||
text: "'k goa eu mee eu muile teege de Dampuurte plakke, dadde viertien doage bruine ziepe schijt"
|
||||
answer_kind: <%= Question.answer_kinds[:simple] %>
|
||||
question_kind: <%= Question.question_kinds[:simple] %>
|
||||
|
||||
translations_wielekes:
|
||||
section: translations
|
||||
text: "o mijn tante wielekes g'hat, 't was een kerre"
|
||||
answer_kind: <%= Question.answer_kinds[:simple] %>
|
||||
question_kind: <%= Question.question_kinds[:simple] %>
|
||||
|
||||
translations_soepe:
|
||||
section: translations
|
||||
text: "veur em schept God den dag en moed'r schept de soepe"
|
||||
answer_kind: <%= Question.answer_kinds[:simple] %>
|
||||
question_kind: <%= Question.question_kinds[:simple] %>
|
||||
|
||||
music_one:
|
||||
section: music
|
||||
text: ""
|
||||
data: '<%= JSON.dump <<END.strip
|
||||
Matthias, ons klein {} gij die boas zijt hier in {}
|
||||
De stad heeft {} gekozen, 74%
|
||||
|
||||
Nee nee, nee nee {}
|
||||
Nee, we gaan dat hier niet doen
|
||||
Nee nee, nee nee {}
|
||||
Nee, we gaan dat hier niet doen
|
||||
|
||||
{} mag vertrekken, meid {} uw voeten niet
|
||||
En gij gaat op dubbel-date met {} en {}
|
||||
|
||||
Nee nee, nee nee {}
|
||||
Nee, we gaan dat hier niet doen
|
||||
Nee nee, nee nee {}
|
||||
Nee, we gaan dat hier niet doen
|
||||
|
||||
Vandaag is de perfecte dag, {} die heeft gezegd
|
||||
Als het moet dan zit mijn {} wel ne keer opzij
|
||||
|
||||
Nee nee, nee nee {}
|
||||
Nee, we gaan dat hier niet doen
|
||||
Nee nee, nee nee {}
|
||||
Nee, we gaan dat hier niet doen
|
||||
END
|
||||
%>'
|
||||
answer_kind: <%= Question.answer_kinds[:lyrics] %>
|
||||
question_kind: <%= Question.question_kinds[:simple] %>
|
||||
|
||||
music_two:
|
||||
section: music
|
||||
text: ""
|
||||
data: '<%= JSON.dump <<END.strip
|
||||
De {} regeert het land
|
||||
Beter dan ooit tevoren
|
||||
{} heeft het licht gezien
|
||||
Ze zegt
|
||||
{} gaat verloren
|
||||
|
||||
Voorlopig gaan we nog even door
|
||||
Op het {} pad
|
||||
Het {} spoor
|
||||
{} als ik vind je overal
|
||||
Op de arbeidsmarkt
|
||||
In dit {}
|
||||
|
||||
Sterren komen
|
||||
Sterren gaan
|
||||
Alleen {} blijft bestaan
|
||||
{} heeft nooit afgezien
|
||||
Ze vraagt
|
||||
Kun jij nog {}
|
||||
END
|
||||
%>'
|
||||
answer_kind: <%= Question.answer_kinds[:lyrics] %>
|
||||
question_kind: <%= Question.question_kinds[:simple] %>
|
||||
|
||||
music_three:
|
||||
section: music
|
||||
text: ""
|
||||
data: '<%= JSON.dump <<END.strip
|
||||
Ik ben nie al te zot van t {}
|
||||
Maar k vange gere {}
|
||||
Marblen en {} kan ik wel
|
||||
Maar daarin ben ik nie fel
|
||||
k Zie tegenwoordig overal
|
||||
En ook al in mijn {}
|
||||
Jongens {} op nen bal
|
||||
Maar k spele t liefst van al
|
||||
|
||||
Mee mijne {}
|
||||
En zijne {}
|
||||
Hij goot omhoge
|
||||
t Es t ziene weert
|
||||
k Geve maar klauwe
|
||||
Op mijn gemak
|
||||
k Heb nog {} bollekens
|
||||
In mijne zak
|
||||
END
|
||||
%>'
|
||||
answer_kind: <%= Question.answer_kinds[:lyrics] %>
|
||||
question_kind: <%= Question.question_kinds[:simple] %>
|
||||
|
||||
music_four:
|
||||
section: music
|
||||
text: ""
|
||||
data: '<%= JSON.dump <<END.strip
|
||||
k è u liere kenne, oan de {} in ne café
|
||||
Gij woar guul {}, ik oa ne moat of draaie mee
|
||||
k woare nog moar binne en k keek een beetse rond
|
||||
En k zag u ginter zitte, k krege t {} in mijne mond
|
||||
|
||||
Ge dronk van uwe {} en k zaaie: "jonges ezuu een {}!"
|
||||
k moest iets onderneme, want ge woar veur maa
|
||||
k wiste nie wa zegge, dat es van mijn {} nie
|
||||
Moar k ben mij kome zette en k zaaie: "meiske, {} hier!"
|
||||
|
||||
Scheetse, loetse, bolleke, zoetse
|
||||
Lieveke, schatse, {}
|
||||
Wilde mee maa {} oastemblieft?
|
||||
Want scheetse, loetse, bolleke, zoetse
|
||||
Lieveke, schatse, {}
|
||||
k è liever een {} dan een {}!
|
||||
END
|
||||
%>'
|
||||
answer_kind: <%= Question.answer_kinds[:lyrics] %>
|
||||
question_kind: <%= Question.question_kinds[:simple] %>
|
||||
|
|
16
test/fixtures/sections.yml
vendored
16
test/fixtures/sections.yml
vendored
|
@ -41,3 +41,19 @@ world:
|
|||
photos:
|
||||
title: Fotoronde
|
||||
description: In deze ronde moet je met elk van de vermelde dingen een foto nemen.
|
||||
|
||||
acrostic:
|
||||
title: Verborgen hint
|
||||
description: Vul alle vragen juist in en vind de verborgen hint. Leestekens en spaties moet je weglaten.
|
||||
|
||||
connections:
|
||||
title: Steekronde
|
||||
description: Verplaats de termen zodat de bijeenhorende begrippen op één rij staan.
|
||||
|
||||
translations:
|
||||
title: Gentse gezegden
|
||||
description: Vertaal de volgende Gentse gezegden
|
||||
|
||||
music:
|
||||
title: Muziekronde
|
||||
description: Vul de onderstaande liedjesteksten aan.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue