A quiz with 4 questions, just one is correct. This repository is an optional module for the "lerntools". For installation and configuration, please see the documentation in https://codeberg.org/lerntools/base
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

340 lines
14 KiB

<template>
<div>
<page-title :title="$t('edit-title')" :subtitle="$t('edit-subtitle')" :button="$t('help')" v-on:click="showModalHelp=!showModalHelp"/>
<!-- basic settings-->
<div class="container mt-3">
<div class="card">
<div class="card-header bg-dark text-white">{{$t('basic-settings')}}</div>
<div class="card-body">
<div class="form-group row">
<label class="col-md-3 col-form-label" for='title'>{{$t('title-label')}}</label>
<input class="col-md-9 form-control" name='title' v-model="abcd.title" v-on:change="changed=true"
:class="{'is-invalid':!$v(abcd.title,true,$consts.REGEX_TEXT_300)}">
<label class="col-md-3 col-form-label" for='subject'>{{$t('subject')}}</label>
<input class="col-md-9 form-control" name='subject' v-model="abcd.subject" :placeholder="$t('hint-subject')" v-on:change="changed=true"
:class="{'is-invalid':!$v(abcd.subject,false,$consts.REGEX_TEXT_300)}">
<label class="col-md-3 col-form-label" for='description'>{{$t('description')}}</label>
<input class="col-md-9 form-control" name='description' v-model="abcd.desc" :placeholder="$t('hint-description')" v-on:change="changed=true"
:class="{'is-invalid':!$v(abcd.desc,false,$consts.REGEX_TEXT_300)}">
<label class="col-md-3 col-form-label" for='ticket'>{{$t('ticket')}}</label>
<input class="col-md-6 form-control" name='ticket' v-model="abcd.ticket" :placeholder="$t('hint-ticket')" v-on:change="changed=true"
:class="{'is-invalid':!$v(abcd.ticket,false,$consts.REGEX_TICKET)}">
<button class="btn col-md-3 btn-secondary" v-on:click="generateTicket()">{{$t('generate')}}</button>
<label class="col-md-3 col-form-label" for='visibility'>{{$t('visibility')}}</label>
<select class="col-md-9 form-control" name='visible' v-model="abcd.visible" v-on:change="changed=true">
<option class="form" value='true'>{{$t('public')}}</option>
<option class="form" value='false'>{{$t('private')}}</option>
</select>
</div>
</div>
</div>
</div>
<!--questions-->
<div class="container">
<div v-if="abcd.questions.length>0">
<div class="card my-4" v-if="" v-for="(question,qnr) in abcd.questions">
<div class="card-header bg-var text-white">
{{$t('question')+' '+(qnr+1)}}
<span class="float-right">
<tooltip-icon v-if="qnr<abcd.questions.length-1" :tip="$t('move-question-down')" invert="true" src="~Main/img/down.svg" v-on:click="moveQuestion(qnr,+1)"/>
<tooltip-icon v-if="qnr>0" :tip="$t('move-question-up')" src="~Main/img/up.svg" invert="true" v-on:click="moveQuestion(qnr,-1)"/>
<tooltip-icon :tip="$t('duplicate-question')" src="~Main/img/duplicate.svg" invert="true" v-on:click="duplicateQuestion(qnr)"/>
<tooltip-icon :tip="$t('delete-question')" src="~Main/img/delete.svg" invert="true" v-on:click="deleteQuestion(qnr)"/>
</span>
</div>
<div class="card-body">
<div class="row">
<label class="col-md-3 col-form-label">{{$t('question')}}</label>
<textarea class="col-md-9 form-control" rows="2" :placeholder="$t('hint-question')" v-model="question.text" v-on:change="changed=true" :class="{'is-invalid':!$v(question.text,true,$consts.REGEX_TEXT_300)}"/>
</div>
<div class="row" v-for="onr in [0,1,2,3]">
<label class="col-md-3 col-form-label">{{$t('answer-char',{char:['A','B','C','D'][onr]})}}</label>
<div class="input-group col-md-9 p-0">
<input class="form-control" :placeholder="$t('hint-answer')" v-model="question.options[onr]" v-on:change="changed=true"
:class="{'is-invalid':!$v(question.options[onr],true,$consts.REGEX_TEXT_300)}">
<div class="input-group-append">
<div class="input-group-text">
<tooltip-icon :tip="$t('hint-hide-option')" size="tiny" src="~Main/img/close.svg" v-on:click="delOption(qnr,onr);"/>
</div>
</div>
</div>
</div>
<div class="row">
<label class="col-md-3 col-form-label">{{$t('correct-answer')}}</label>
<select class="col-md-3 form-control" v-model="question.answer"
:class="{'is-invalid':!$v(question.answer,true,$consts.REGEX_NUMBER)}">
<option v-for="i in [0,1,2,3]" :value="i">{{['A','B','C','D'][i]}}</option>
</select>
<label class="col-md-3 col-form-label">{{$t('time')}}</label>
<input class="col-md-3 form-control" :placeholder="$t('hint-time')" v-model:number="question.time" type="number" min="1" max="300" :class="{'is-invalid':!question.time}" v-on:change="changed=true">
<label class="col-md-3 col-form-label">{{$t('answer-info')}}</label>
<textarea class="col-md-9 form-control" v-model="question.info" rows="3" v-on:change="changed=true"
:class="{'is-invalid':!$v(question.info,false,$consts.REGEX_TEXT_AREA_300)}"/>
</div>
<div v-if="question.image" class="row mt-2">
<label class="col-md-3 col-form-label">{{$t('image')}}</label>
<div class="col-md-8 text-center" style="height:10em">
<img :src="question.image" style="height:9em">
</div>
<div class="col-md-1 text-right">
<tooltip-icon :tip="$t('delete-image')" src="~Main/img/delete.svg" v-on:click="question.image=''"/>
</div>
</div>
<div v-else class="row mt-2">
<label class="col-md-3 col-form-label">{{$t('image-optional')}}</label>
<file-upload force="image" :maxsize="config.imageMaxSize" v-on:upload="function(image) {uploadImage(image,qnr)}"/>
</div>
</div>
</div>
</div>
<div class="container mt-2">
<warning-list v-if="warnings" :warnings="warnings"/>
<button v-if="changed" class="mr-1 btn btn-primary" v-on:click="save()">{{$t('save')}}</button>
<button v-if="changed" class="btn btn-secondary" v-on:click="modalConfirmCancel=true">{{$t('cancel')}}</button>
<button v-else class="btn btn-secondary" v-on:click="$router.push({name:'abcd-index'})">{{$t('cancel')}}</button>
</div>
<div class="text-right">
<button class="mr-1 btn btn-primary" v-on:click="addQuestion()">{{$t('add-question-button')}}</button>
</div>
</div>
<!--modal help-->
<modal-info v-if="showModalHelp" v-on:close="showModalHelp=false">
<ul class="list-group">
<li class="list-group-item">{{$t('help-text1')}}</li>
<li class="list-group-item">{{$t('help-text2')}}</li>
<li class="list-group-item">{{$t('help-text3')}}</li>
<li class="list-group-item">{{$t('help-text4',{size:Math.round($consts.MAX_INLINE_IMAGE_SIZE/1024)})}}</li>
</ul>
</modal-info>
<!-- modal error-->
<modal-info v-if="modalErrorText" v-on:close="modalErrorText=''">
<p>{{modalErrorText}}</p>
</modal-info>
<!-- confirm abort-->
<modal-confirm-cancel v-if="modalConfirmCancel" v-on:close="modalConfirmCancel=false" v-on:accept="$router.push({name:'abcd-index'})"/>
<modal-info v-if="saving"><wait-icon/></modal-info>
</div>
</template>
<script>
import PageTitle from 'Main/components/PageTitle.vue';
import FileUpload from 'Main/components/FileUpload.vue';
import WarningList from 'Main/components/WarningList.vue';
import TooltipIcon from 'Main/components/TooltipIcon.vue';
import ModalInfo from 'Main/components/ModalInfo.vue';
import ModalConfirmCancel from 'Main/components/ModalConfirmCancel.vue';
import WaitIcon from 'Main/components/WaitIcon.vue';
import store from 'Main/js/store.js';
import color from 'Main/js/color.js';
import config from '../config.js';
import generator from 'Main/js/password-generator'
export default {
components: {PageTitle, ModalInfo, ModalConfirmCancel, TooltipIcon,WarningList, WaitIcon, FileUpload},
data:function() {
return {
abcd:{questions:[]},
showModalHelp:false,
modalErrorText:'',
modalConfirmCancel:false,
id:'',
validationErrors:0,
warnings:'',
saving:false,
config:config,
changed:false
}
},
created: function() {
var id=this.$route.params['id'];
var title=this.$route.params['title'];
if (id) {
this.id=id;
this.$axios.get('abcd/sets/'+id).then(response=> {
if (!response.data.title) return this.$router.push({name:'abcd-index'});
this.abcd=response.data;
})
}
else {
this.abcd.title=title;
this.abcd.ticket=generator.generate({length:8, numbers: true});
this.abcd.visible=true;
}
},
updated: function() {
color.setBgVar();
},
methods: {
generateTicket: function() {
this.abcd.ticket=generator.generate({length:8, numbers: true});
},
delOption: function(qnr,onr) {
this.abcd.questions[qnr].options[onr]='–';
this.$forceUpdate();
this.changed=true;
},
moveQuestion: function(src, direction) {
var dst=src+direction;
var question=this.abcd.questions[src];
this.abcd.questions[src]=this.abcd.questions[dst];
this.abcd.questions[dst]=question;
this.changed=true;
this.$forceUpdate();
},
duplicateQuestion: function(qnr) {
var newQuestion=Object.assign({}, this.abcd.questions[qnr]);
this.abcd.questions.push(newQuestion);
this.changed=true;
},
deleteQuestion: function(qnr) {
this.abcd.questions.splice(qnr,1);
this.changed=true;
},
addQuestion: function() {
this.abcd.questions.push({
text:'',
options: ['','','',''],
answer: '',
info: '',
image: '',
time: ''
})
this.changed=true;
},
save: function() {
//check for validation errors
this.validationErrors=document.getElementsByClassName('is-invalid').length;
if (this.validationErrors>0) {
this.modalErrorText=this.$t('validation-errors',{num:this.validationErrors});
return;
}
this.saving=true;
//update existing set
if (this.id) {
this.$axios.put('abcd/sets/'+this.id,{abcd: this.abcd}).then(response=> {
if (response.data[0]) this.warnings=response.data;
else this.$router.push({name:'abcd-index'});
this.saving=false;
})
}
//create new set
else {
this.$axios.post('abcd/sets',{abcd: this.abcd}).then(response=> {
if (response.data[0]) this.warnings=response.data;
else this.$router.push({name:'abcd-index'});
this.saving=false;
})
}
},
uploadImage: function(image,qnr) {
var reader=new FileReader();
reader.readAsDataURL(image);
reader.onload=e=>{
this.abcd.questions[qnr].image=e.target.result;
this.changed=true;
this.$forceUpdate();
};
}
}
}
</script>
<style>
img.invert {filter:invert(1)}
</style>
<i18n>
{
"de": {
"answer-char": "Option {char}",
"hint-answer":"Mögliche Antwort",
"edit-title": "ABCD Quiz bearbeiten",
"edit-subtitle": "Hier können Sie die Fragensammlung bearbeiten. Fügen Sie mindestens eine Frage hinzu, damit Sie das Quiz starten können.",
"help": "Hilfe",
"basic-settings": "Grundlegende Einstellungen",
"title-label": "Titel",
"subject": "Fach",
"hint-subject": "Bitte geben Sie das zugehörige Fach ein",
"description": "Beschreibung",
"hint-description": "Bitte geben Sie eine aussagekrägtige Beschreibung an",
"ticket": "Ticket",
"hint-ticket": "Ticket zum Zugriff für Schüler auf das Set",
"visibility": "Sichtbarkeit",
"public": "Öffentlich",
"private": "Privat",
"question": "Frage",
"move-question-down": "Nach unten verschieben",
"move-question-up": "Nach oben verschieben",
"duplicate-question": "Frage duplizieren",
"delete-question": "Frage löschen",
"hint-question": "Fragenstellung",
"hint-hide-option": "Option ausblenden",
"correct-answer": "Korrekte Antwort",
"time": "Zeit",
"hint-time": "Zeit in Sekunden zur Beantwortung der Frage",
"answer-info": "Information zur richtigen Antwort",
"image": "Bild",
"delete-image": "Bild löschen",
"image-optional": "Bild – optional",
"save": "Speichern",
"cancel": "Abbrechen",
"add-question": "Frage hinzufügen",
"help-text1": "Falls Sie nicht möchten, dass das ABCD-Quiz über einen Link freigegeben werden kann, so löschen Sie bitte das Ticket.",
"help-text2": "Soll das Quiz nur Ihnen zur Verfügung steht, dann kennzeichnen Sie es bitte als „privat“.",
"help-text3": "Fragen können mittels der vertikalen Pfeile verschoben werden.",
"generate": "Generieren",
"validation-errors":"Bitte korrigieren bzw. ergänzen Sie die Angaben in den rot markierten Eingabefeldern. Die Anzahl der Fehler beträgt {num}.",
"add-question-button":"Frage hinzufügen"
},
"en": {
"answer-char": "Option {char}",
"hint-answer":"Possible Answer",
"edit-title": "Edit ABCD Quiz",
"edit-subtitle": "Edit the ABCD questionnaire. Add at least one question to start the quiz.",
"help": "Help",
"basic-settings": "Basic Settings",
"title-label": "Title",
"subject": "Subject",
"hint-subject": "Please enter the appropriate subject",
"description": "Description",
"hint-description": "Please provide a descriptive description",
"ticket": "Ticket",
"hint-ticket": "Ticket for student access to the set",
"visibility": "Visibility",
"public": "Public",
"private": "Private",
"question": "Question",
"move-question-down": "Move question down",
"move-question-up": "Move question up",
"duplicate-question": "Duplicate question",
"delete-question": "Delete question",
"hint-question": "Question",
"hint-hide-option": "Hide option",
"correct-answer": "Correct answer",
"time": "Time",
"hint-time": "Time in seconds to answer the question",
"answer-info": "Information on the correct answer",
"image": "Image",
"delete-image": "Delete image",
"image-optional": "Image - optional",
"save": "Save",
"cancel": "Cancel",
"add-question": "Add question",
"help-text1": "If you do not want the ABCD quiz to be shared via a link, please delete the ticket.",
"help-text2": "If you want this quiz to only be visible for you, please mark it as \"private\".",
"help-text3": "Questions can be moved using the up and down arrows.",
"generate": "Generate",
"validation-errors": "Please correct or add the information in the red marked fields. The number of errors is {num}.",
"add-question-button":"Add question"
}
}
</i18n>