diff --git a/crowdin.yml b/crowdin.yml new file mode 100644 index 0000000..48edea1 --- /dev/null +++ b/crowdin.yml @@ -0,0 +1,3 @@ +files: + - source: /language/.en.json + translation: /language/%two_letters_code%.json diff --git a/css/questionset.css b/css/questionset.css index 22e65d2..a9eb1fc 100644 --- a/css/questionset.css +++ b/css/questionset.css @@ -1,15 +1,3 @@ -/* IcoMoon font licensed under the GNU General Public License: http://www.gnu.org/licenses/gpl.html */ -@font-face { - font-family: 'icomoon-questionset'; - src:url('../fonts/icomoon.eot'); - src:url('../fonts/icomoon.eot?#iefix') format('embedded-opentype'), - url('../fonts/icomoon.woff') format('woff'), - url('../fonts/icomoon.ttf') format('truetype'), - url('../fonts/icomoon.svg#icomoon') format('svg'); - font-weight: normal; - font-style: normal; -} - .questionset-results h2 { font-size: 1.2em; font-weight: bold; @@ -237,30 +225,27 @@ font-size: 1.25em; } -.questionset-results .feedback-section .feedback-text { - font-weight: normal; - color: #777; -} - .questionset-results .buttons { - margin-bottom: 1.5em; + margin: 2em 0 1em 0; } .questionset-results .result-header, -.questionset-results .result-text { +.questionset-results .result-text, +.questionset-results .feedback-section .feedback-text { color: #1a73d9; font-weight: bold; } .questionset-results .result-header { font-size: 2em; - margin-top: 1em; + margin: 1em 0.5em 0.5em 0.5em; } -.questionset-results .result-text { +.questionset-results .result-text, +.questionset-results .feedback-section .feedback-text { font-size: 1.25em; line-height: 1.25em; - margin: 1em 1em 2.25em; + margin: 1em; } /* No margin for questions when no frame */ diff --git a/fonts/icomoon.eot b/fonts/icomoon.eot deleted file mode 100644 index d8cdc1a..0000000 Binary files a/fonts/icomoon.eot and /dev/null differ diff --git a/fonts/icomoon.svg b/fonts/icomoon.svg deleted file mode 100644 index 1a48364..0000000 --- a/fonts/icomoon.svg +++ /dev/null @@ -1,14 +0,0 @@ - - - -Generated by IcoMoon - - - - - - - - - - \ No newline at end of file diff --git a/fonts/icomoon.ttf b/fonts/icomoon.ttf deleted file mode 100644 index 9649f7e..0000000 Binary files a/fonts/icomoon.ttf and /dev/null differ diff --git a/fonts/icomoon.woff b/fonts/icomoon.woff deleted file mode 100644 index 5d29f5d..0000000 Binary files a/fonts/icomoon.woff and /dev/null differ diff --git a/js/questionset.js b/js/questionset.js index 0fdd085..0a29e99 100644 --- a/js/questionset.js +++ b/js/questionset.js @@ -61,6 +61,10 @@ H5P.QuestionSet = function (options, contentId, contentData) { ' ' + ''; + var solutionButtonTemplate = options.endGame.showSolutionButton ? + ' ': + ''; + var resulttemplate = '
' + '
<%= message %>
' + @@ -76,7 +80,7 @@ H5P.QuestionSet = function (options, contentId, contentData) { ' <% } %>' + '
' + ' ' + - ' ' + + solutionButtonTemplate + ' ' + '
' + '
'; @@ -108,17 +112,20 @@ H5P.QuestionSet = function (options, contentId, contentData) { showResultPage: true, noResultMessage: 'Finished', message: 'Your result:', - successGreeting: 'Congratulations!', - successComment: 'You have enough correct answers to pass the test.', - failGreeting: 'Sorry!', - failComment: "You don't have enough correct answers to pass this test.", - scoreString: 'You got @score of @total points', + oldFeedback: { + successGreeting: '', + successComment: '', + failGreeting: '', + failComment: '' + }, + overallFeedback: [], finishButtonText: 'Finish', solutionButtonText: 'Show solution', retryButtonText: 'Retry', showAnimations: false, skipButtonText: 'Skip video' }, + override: {}, disableBackwardsNavigation: false }; @@ -154,27 +161,27 @@ H5P.QuestionSet = function (options, contentId, contentData) { var randomizeQuestionOrdering = function (questions) { // Save the original order of the questions in a multidimensional array [[question0,0],[question1,1]... - var questionOrdering = questions.map(function(questionInstance, index) { return [questionInstance, index] }); + var questionOrdering = questions.map(function (questionInstance, index) { return [questionInstance, index]; }); // Shuffle the multidimensional array questionOrdering = H5P.shuffleArray(questionOrdering); // Retrieve question objects from the first index - var questions = []; + questions = []; for (var i = 0; i < questionOrdering.length; i++) { questions[i] = questionOrdering[i][0]; } // Retrieve the new shuffled order from the second index var newOrder = []; - for (var i = 0; i< questionOrdering.length; i++) { + for (var j = 0; j < questionOrdering.length; j++) { // Use a previous order if it exists - if(contentData.previousState && contentData.previousState.questionOrder) { - newOrder[i] = questionOrder[questionOrdering[i][1]]; + if (contentData.previousState && contentData.previousState.questionOrder) { + newOrder[j] = questionOrder[questionOrdering[j][1]]; } else { - newOrder[i] = questionOrdering[i][1]; + newOrder[j] = questionOrdering[j][1]; } } @@ -189,7 +196,7 @@ H5P.QuestionSet = function (options, contentId, contentData) { if (params.poolSize > 0) { // If a previous pool exists, recreate it - if(contentData.previousState && contentData.previousState.poolOrder) { + if (contentData.previousState && contentData.previousState.poolOrder) { poolOrder = contentData.previousState.poolOrder; // Recreate the pool from the saved data @@ -243,7 +250,7 @@ H5P.QuestionSet = function (options, contentId, contentData) { * @param {object} questions H5P content types to be created as instances * @return {array} Array of questions instances */ - var createQuestionInstancesFromQuestions = function(questions) { + var createQuestionInstancesFromQuestions = function (questions) { var result = []; // Create question instances from questions // Instantiate question instances @@ -265,9 +272,6 @@ H5P.QuestionSet = function (options, contentId, contentData) { } question.params = question.params || {}; - question.params.overrideSettings = question.params.overrideSettings || {}; - question.params.overrideSettings.$confirmationDialogParent = $template.last(); - question.params.overrideSettings.instance = this; var hasAnswers = contentData.previousState && contentData.previousState.answers; var questionInstance = H5P.newRunnable(question, contentId, undefined, undefined, { @@ -282,7 +286,7 @@ H5P.QuestionSet = function (options, contentId, contentData) { } return result; - } + }; // Create question instances from questions given by params questionInstances = createQuestionInstancesFromQuestions(params.questions); @@ -311,8 +315,8 @@ H5P.QuestionSet = function (options, contentId, contentData) { var _updateButtons = function () { // Verify that current question is answered when backward nav is disabled if (params.disableBackwardsNavigation) { - if (questionInstances[currentQuestion].getAnswerGiven() - && questionInstances.length-1 !== currentQuestion) { + if (questionInstances[currentQuestion].getAnswerGiven() && + questionInstances.length-1 !== currentQuestion) { questionInstances[currentQuestion].showButton('next'); } else { @@ -353,6 +357,8 @@ H5P.QuestionSet = function (options, contentId, contentData) { currentQuestion = questionNumber; + handleAutoPlay(currentQuestion); + // Hide all questions $('.question-container', $myDom).hide().eq(questionNumber).show(); @@ -403,6 +409,31 @@ H5P.QuestionSet = function (options, contentId, contentData) { return currentQuestion; }; + /** + * Handle autoplays, limit to one at a time + * + * @param {number} currentQuestionIndex + */ + var handleAutoPlay = function (currentQuestionIndex) { + for (var i = 0; i < questionInstances.length; i++) { + questionInstances[i].pause(); + } + + var currentQuestion = params.questions[currentQuestionIndex]; + + var hasAutoPlay = currentQuestion && + currentQuestion.params.media && + currentQuestion.params.media.params && + currentQuestion.params.media.params.playback && + currentQuestion.params.media.params.playback.autoplay; + + if (hasAutoPlay && typeof questionInstances[currentQuestionIndex].play === 'function') { + questionInstances[currentQuestionIndex].play(); + } + }; + + + /** * Show solutions for subcontent, and hide subcontent buttons. * Used for contracts with integrated content. @@ -496,7 +527,7 @@ H5P.QuestionSet = function (options, contentId, contentData) { //Force the last page to be reRendered rendered = false; - if(params.poolSize > 0){ + if (params.poolSize > 0) { // Make new pool from params.questions // Randomize and get the results @@ -549,7 +580,7 @@ H5P.QuestionSet = function (options, contentId, contentData) { var replaceQuestionsInDOM = function (questionInstances) { // Find all question containers and detach questions from them - $('.question-container', $myDom).each(function (){ + $('.question-container', $myDom).each(function () { $(this).children().detach(); }); @@ -564,19 +595,19 @@ H5P.QuestionSet = function (options, contentId, contentData) { question.attach($('.question-container:eq(' + i + ')', $myDom)); //Show buttons if necessary - if(questionInstances[questionInstances.length -1] === question - && question.hasButton('finish')) { + if (questionInstances[questionInstances.length -1] === question && + question.hasButton('finish')) { question.showButton('finish'); } - if(questionInstances[questionInstances.length -1] !== question - && question.hasButton('next')) { + if (questionInstances[questionInstances.length -1] !== question && + question.hasButton('next')) { question.showButton('next'); } - if(questionInstances[0] !== question - && question.hasButton('prev') - && !params.disableBackwardsNavigation) { + if (questionInstances[0] !== question && + question.hasButton('prev') && + !params.disableBackwardsNavigation) { question.showButton('prev'); } @@ -617,7 +648,7 @@ H5P.QuestionSet = function (options, contentId, contentData) { * @param {number} dotIndex Index of dot * @param {boolean} isAnswered True if is answered, False if not answered */ - var toggleAnsweredDot = function(dotIndex, isAnswered) { + var toggleAnsweredDot = function (dotIndex, isAnswered) { var $el = $('.progress-dot:eq(' + dotIndex +')', $myDom); // Skip current button @@ -679,12 +710,9 @@ H5P.QuestionSet = function (options, contentId, contentData) { // Get total score. var finals = self.getScore(); var totals = self.getMaxScore(); - var scoreString = params.endGame.scoreString.replace("@score", finals).replace("@total", totals); + + var scoreString = H5P.Question.determineOverallFeedback(params.endGame.overallFeedback, finals / totals).replace('@score', finals).replace('@total', totals); var success = ((100 * finals / totals) >= params.passPercentage); - var eventData = { - score: scoreString, - passed: success - }; /** * Makes our buttons behave like other buttons. @@ -707,8 +735,8 @@ H5P.QuestionSet = function (options, contentId, contentData) { var eparams = { message: params.endGame.showResultPage ? params.endGame.message : params.endGame.noResultMessage, - comment: params.endGame.showResultPage ? (success ? params.endGame.successGreeting : params.endGame.failGreeting) : undefined, - resulttext: params.endGame.showResultPage ? (success ? params.endGame.successComment : params.endGame.failComment) : undefined, + comment: params.endGame.showResultPage ? (success ? params.endGame.oldFeedback.successGreeting : params.endGame.oldFeedback.failGreeting) : undefined, + resulttext: params.endGame.showResultPage ? (success ? params.endGame.oldFeedback.successComment : params.endGame.oldFeedback.failComment) : undefined, finishButtonText: params.endGame.finishButtonText, solutionButtonText: params.endGame.solutionButtonText, retryButtonText: params.endGame.retryButtonText @@ -719,10 +747,6 @@ H5P.QuestionSet = function (options, contentId, contentData) { $myDom.append(endTemplate.render(eparams)); if (params.endGame.showResultPage) { - // Add event handlers to summary buttons - hookUpButton('.qs-finishbutton', function () { - self.trigger('h5pQuestionSetFinished', eventData); - }); hookUpButton('.qs-solutionbutton', function () { showSolutions(); $myDom.children().hide().filter('.questionset').show(); @@ -852,7 +876,7 @@ H5P.QuestionSet = function (options, contentId, contentData) { }); // Hide next button if it is the last question - if(questionInstances[questionInstances.length -1] === question) { + if (questionInstances[questionInstances.length -1] === question) { question.hideButton('next'); } @@ -1080,10 +1104,10 @@ H5P.QuestionSet = function (options, contentId, contentData) { return info; }; - this.getQuestions = function() { + this.getQuestions = function () { return questionInstances; }; - this.showSolutions = function() { + this.showSolutions = function () { renderSolutions = true; }; @@ -1141,7 +1165,7 @@ H5P.QuestionSet = function (options, contentId, contentData) { /** * Add the question itself to the definition part of an xAPIEvent */ - var addQuestionToXAPI = function(xAPIEvent) { + var addQuestionToXAPI = function (xAPIEvent) { var definition = xAPIEvent.getVerifiedStatementValue(['object', 'definition']); $.extend(definition, getxAPIDefinition()); }; @@ -1152,8 +1176,8 @@ H5P.QuestionSet = function (options, contentId, contentData) { * @param {Object} metaContentType * @returns {array} */ - var getXAPIDataFromChildren = function(metaContentType) { - return metaContentType.getQuestions().map(function(question) { + var getXAPIDataFromChildren = function (metaContentType) { + return metaContentType.getQuestions().map(function (question) { return question.getXAPIData(); }); }; @@ -1164,7 +1188,7 @@ H5P.QuestionSet = function (options, contentId, contentData) { * * @see contract at {@link https://h5p.org/documentation/developers/contracts#guides-header-6} */ - this.getXAPIData = function(){ + this.getXAPIData = function () { var xAPIEvent = this.createXAPIEventTemplate('answered'); addQuestionToXAPI(xAPIEvent); xAPIEvent.setScoredResult(this.getScore(), @@ -1176,7 +1200,7 @@ H5P.QuestionSet = function (options, contentId, contentData) { return { statement: xAPIEvent.data.statement, children: getXAPIDataFromChildren(this) - } + }; }; }; diff --git a/language/.en.json b/language/.en.json new file mode 100644 index 0000000..5dbdf69 --- /dev/null +++ b/language/.en.json @@ -0,0 +1,251 @@ +{ + "semantics": [ + { + "label": "Quiz introduction", + "fields": [ + { + "label": "Display introduction" + }, + { + "label": "Title", + "description": "This title will be displayed above the introduction text." + }, + { + "label": "Introduction text", + "description": "This text will be displayed before the quiz starts." + }, + { + "label": "Start button text", + "default": "Start Quiz" + }, + { + "label": "Background image", + "description": "An optional background image for the introduction." + } + ] + }, + { + "label": "Background image", + "description": "An optional background image for the Question set." + }, + { + "label": "Progress indicator", + "description": "Question set progress indicator style.", + "options": [ + { + "label": "Textual" + }, + { + "label": "Dots" + } + ], + "default": "dots" + }, + { + "label": "Pass percentage", + "description": "Percentage of Total score required for passing the quiz." + }, + { + "label": "Questions", + "widgets": [ + { + "label": "Default" + }, + { + "label": "Textual" + } + ], + "entity": "question", + "field": { + "label": "Question type", + "description": "Library for this question." + } + }, + { + "label": "Interface texts in quiz", + "fields": [ + { + "label": "Back button", + "default": "Previous question" + }, + { + "label": "Next button", + "default": "Next question" + }, + { + "label": "Finish button", + "default": "Finish" + }, + { + "label": "Progress text", + "description": "Text used if textual progress is selected.", + "default": "Question: @current of @total questions" + }, + { + "label": "Label for jumping to a certain question", + "description": "You must use the placeholder '%d' instead of the question number, and %total instead of total amount of questions.", + "default": "Question %d of %total" + }, + { + "label": "Copyright dialog question label", + "default": "Question" + }, + { + "label": "Readspeaker progress", + "description": "May use @current and @total question variables", + "default": "Question @current of @total" + }, + { + "label": "Unanswered question text", + "default": "Unanswered" + }, + { + "label": "Answered question text", + "default": "Answered" + }, + { + "label": "Current question text", + "default": "Current question" + } + ] + }, + { + "label": "Disable backwards navigation", + "description": "This option will only allow you to move forward in Question Set" + }, + { + "label": "Randomize questions", + "description": "Enable to randomize the order of questions on display." + }, + { + "label": "Number of questions to be shown:", + "description": "Create a randomized batch of questions from the total." + }, + { + "label": "Quiz finished", + "fields": [ + { + "label": "Display results" + }, + { + "label": "Display solution button" + }, + { + "label": "No results message", + "description": "Text displayed on end page when \"Display results\" is disabled", + "default": "Finished" + }, + { + "label": "Feedback heading", + "default": "Your result:", + "description": "This heading will be displayed at the end of the quiz when the user has answered all questions." + }, + { + "label": "Overall Feedback", + "fields": [ + { + "widgets": [], + "label": "Define custom feedback for any score range", + "description": "Example: 0-20% Bad score, 21-91% Average Score, 91-100% Great Score!", + "entity": "range", + "field": { + "fields": [ + { + "label": "Score Range" + }, + {}, + { + "label": "Feedback for defined score range", + "placeholder": "Fill in the feedback" + } + ] + } + } + ] + }, + { + "label": "Old Feedback", + "fields": [ + { + "label": "Quiz passed greeting", + "description": "This text will be displayed above the score if the user has successfully passed the quiz." + }, + { + "label": "Passed comment", + "description": "This comment will be displayed after the score if the user has successfully passed the quiz." + }, + { + "label": "Quiz failed title", + "description": "This text will be displayed above the score if the user has failed the quiz." + }, + { + "label": "Failed comment", + "description": "This comment will be displayed after the score if the user has failed the quiz." + } + ] + }, + { + "label": "Solution button label", + "default": "Show solution", + "description": "Text for the solution button." + }, + { + "label": "Retry button label", + "default": "Retry", + "description": "Text for the retry button." + }, + { + "label": "Finish button text", + "default": "Finish" + }, + { + "label": "Display video before quiz results" + }, + { + "label": "Enable skip video button" + }, + { + "label": "Skip video button label", + "default": "Skip video" + }, + { + "label": "Passed video", + "description": "This video will be played if the user successfully passed the quiz." + }, + { + "label": "Fail video", + "description": "This video will be played if the user failes the quiz." + } + ] + }, + { + "label": "Settings for \"Show solution\" and \"Retry\" buttons", + "fields": [ + { + "label": "Override \"Show Solution\" button", + "description": "This option determines if the \"Show Solution\" button will be shown for all questions, disabled for all or configured for each question individually.", + "options": [ + { + "label": "Enabled" + }, + { + "label": "Disabled" + } + ] + }, + { + "label": "Override \"Retry\" button", + "description": "This option determines if the \"Retry\" button will be shown for all questions, disabled for all or configured for each question individually.", + "options": [ + { + "label": "Enabled" + }, + { + "label": "Disabled" + } + ] + } + ] + } + ] +} diff --git a/language/ar.json b/language/ar.json index 838ccf7..e8b0509 100644 --- a/language/ar.json +++ b/language/ar.json @@ -121,6 +121,9 @@ { "label": "عرض النتائج" }, + { + "label": "Display solution button" + }, { "label": "No results message", "description": "Text displayed on end page when \"Display results\" is disabled", @@ -210,4 +213,4 @@ ] } ] -} +} \ No newline at end of file diff --git a/language/bs.json b/language/bs.json new file mode 100644 index 0000000..c92f10e --- /dev/null +++ b/language/bs.json @@ -0,0 +1,229 @@ +{ + "semantics": [ + { + "label": "Uvod u kviz", + "fields": [ + { + "label": "Prikaži uvod" + }, + { + "label": "Naziv", + "description": "Ovaj će naziv biti prikazan iznad uvodnog teksta." + }, + { + "label": "Tekst uvoda", + "description": "Ovaj će naziv biti prikazan prije početka kviza." + }, + { + "label": "Oznaka za dugme \"Start\"", + "default": "Start" + }, + { + "label": "Slika pozadine", + "description": "Slika pozadine na početku. (opcionalno)." + } + ] + }, + { + "label": "Slika pozadine", + "description": "Slika pozadine seta pitanja. (opcionalno)." + }, + { + "label": "Prikaz napredovanja", + "description": "Prikazivanje napredovanja", + "options": [ + { + "label": "Tekst" + }, + { + "label": "Bodovi" + } + ] + }, + { + "label": "Minimalno procenata za prolaz", + "description": "Minimalno osvojenih procenata da bi se kviz smatrao uspješno prođenim." + }, + { + "label": "Pitanja", + "widgets": [ + { + "label": "Standard" + }, + { + "label": "Tekst" + } + ], + "entity": "Pitanje", + "field": { + "label": "Vrsta pitanja", + "description": "Biblioteka za ovo pitanje." + } + }, + { + "label": "Prikaz teksta u kvizu", + "fields": [ + { + "label": "Oznaka za dugme \"Nazad\"", + "default": "Zurück" + }, + { + "label": "Oznaka za dugme \"Naprijed\"", + "default": "Weiter" + }, + { + "label": "Oznaka za dugme \"Završi\"", + "default": "Završi" + }, + { + "label": "Tekst o napredovanju", + "description": "Koristi tekst ako je izabran za napredak u pisanom obliku.", + "default": "Aktuelno pitanje: @current od @total pitanja" + }, + { + "label": "Označavanje za skakanje do određene tačke", + "description": "Koristi mjesto '%d' za redoslijed pitanja i %total za ukupan broj pitanja.", + "default": "Pitanje %d od %total" + }, + { + "label": "Opis pitanja u vezi sa vezi s autorom", + "default": "Pitanje" + }, + { + "label": "Napredno \"Readspeaker\"", + "description": "Varijable: @current i @total", + "default": "Pitanje @current od @total" + }, + { + "label": "Tekst za neodgovorena pitanja", + "default": "Neodgovoreno" + }, + { + "label": "Tekst za odgovorena pitanja", + "default": "Odgovoreno" + }, + { + "label": "Tekst za trenutno pitanja", + "default": "Trenutno pitanje" + } + ] + }, + { + "label": "Deaktivirati mogućnost povratka unazad", + "description": "Ako je aktivirano, korisnik će moći ići samo naprijed u odgovaranju na pitanja." + }, + { + "label": "Izmješati pitanja", + "description": "Ako je aktivirano, pitanja će kod svakog učitavanja kviza imati drugi raspored." + }, + { + "label": "Broj pitanja za prikaz:", + "description": "Može se koristiti kod odabira slučajnog pitanja." + }, + { + "label": "Završi kviz", + "fields": [ + { + "label": "Prikaz rezultata" + }, + { + "label": "Napomena ako nema rezultata", + "description": "Tekst koji će biti prikazan u slučaju da je \"Prikaz rezultata\" deaktiviran", + "default": "Završi" + }, + { + "label": "Oznaka za povratne informacije", + "default": "Tvoj rezultat:", + "description": "Ovaj tekst će biti prikazan na kraju kviza kada korisnik odgovori na pitanja." + }, + { + "label": "Tekst za prikaz broj odova", + "description": "Ovaj tekst će se koristiti da prikaže ukupan broj bodova korisnika. \"@score\" će biti zamjenjen sa osvojenim bodovima, \"@total\" će biti zamjenjeno sa maksimalnim brojem bodova.", + "default": "Osvojeno @score bodova od @total mogućih." + }, + { + "label": "Oznaka za \"Kviz položen\"", + "placeholder": "BRAVO!", + "default": "BRAVO!", + "description": "Ovaj tekst će biti prikazan iznad broja bodova kada je korisnik uspješno završio kviz." + }, + { + "label": "Komentar za uspješno završen kviz", + "default": "Nije loše!", + "description": "Ovaj tekst će biti prikazan iznad broja bodova kada je korisnik uspješno završio kviz." + }, + { + "label": "Oznaka kod neuspješnog završetka kviza", + "default": "Ovoga puta nije dovoljno dobro.", + "description": "Ovaj tekst će biti prikazan iznad broja bodova kada je korisnik nije uspješno završio kviz." + }, + { + "label": "Oznaka kod neuspješnog završetka kviza", + "default": "Pokušaj još jednom!", + "description": "Ovaj komentar će se pokazati nakon što korisnik nije sakupio dovoljan broj bodova za uspješan završetak kviza." + }, + { + "label": "Oznaka za dugme \"Prikaži rješenje\"", + "default": "Prikaži rješenje", + "description": "Oznaka za dugme \"Prikaži rješenje\"" + }, + { + "label": "Oznaka za dugme \"Ponovi\"", + "default": "Ponovi", + "description": "Oznaka za dugme \"Ponovi\"" + }, + { + "label": "Oznaka za dugme \"Završi\"", + "default": "Završi" + }, + { + "label": "Prikaži video prije rezultata kviza" + }, + { + "label": "Aktiviraj dugme \"Preskoči vidio\"" + }, + { + "label": "Oznaka za dugme \"Preskoči video\"", + "default": "Preskoči video" + }, + { + "label": "Video nakon položenog kviza", + "description": "Ovaj video se prikazuje nakon što korisnik uspješno položi kviz." + }, + { + "label": "Video nakon nepoloženog kviza", + "description": "Ovaj video se prikazuje nakon što korisnik neuspješno završi kviz." + } + ] + }, + { + "label": "Podešavanje dugmeta \"Prikaži rješenje\" i \"Ponovi\".", + "fields": [ + { + "label": "Poništi dugme \"Prikaži rješenje\"", + "description": "Ova opcija podešava prikazivanje dugmeta \"Prikaži rješenje\" za sva pitanja ili da bude za svako posebno pitanje konfigurirano.", + "options": [ + { + "label": "Prikaži" + }, + { + "label": "Nemoj prikazati" + } + ] + }, + { + "label": "Poništi dugme \"Ponovi\"", + "description": "Ova opcija podešava prikazivanje dugmeta \"Ponovi\" za sva pitanja ili da bude za svako posebno pitanje konfigurirano.", + "options": [ + { + "label": "Prikaži" + }, + { + "label": "Nemoj prikazati" + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/language/da.json b/language/da.json new file mode 100644 index 0000000..c629729 --- /dev/null +++ b/language/da.json @@ -0,0 +1,255 @@ +{ + "semantics":[ + { + "label":"Quiz introduction", + "fields":[ + { + "label":"Display introduction" + }, + { + "label":"Title", + "description":"This title will be displayed above the introduction text." + }, + { + "label":"Introduction text", + "description":"This text will be displayed before the quiz starts." + }, + { + "label":"Start button text", + "default":"Start Quiz" + }, + { + "label":"Background image", + "description":"An optional background image for the introduction." + } + ] + }, + { + "label":"Background image", + "description":"An optional background image for the Question set." + }, + { + "label":"Progress indicator", + "description":"Question set progress indicator style.", + "options":[ + { + "label":"Textual" + }, + { + "label":"Dots" + } + ], + "default":"dots" + }, + { + "label":"Pass percentage", + "description":"Percentage of Total score required for passing the quiz." + }, + { + "label":"Questions", + "widgets":[ + { + "label":"Default" + }, + { + "label":"Textual" + } + ], + "entity":"question", + "field":{ + "label":"Question type", + "description":"Library for this question." + } + }, + { + "label":"Interface texts in quiz", + "fields":[ + { + "label":"Back button", + "default":"Forrige spørgsmål" + }, + { + "label":"Next button", + "default":"Næste spørgsmål" + }, + { + "label":"Finish button", + "default":"Færdig" + }, + { + "label":"Progress text", + "description":"Text used if textual progress is selected.", + "default":"Spørgsmål:nummer @current ud af @spørgsmål" + }, + { + "label":"Label for jumping to a certain question", + "description":"You must use the placeholder '%d' instead of the question number, and %total instead of total amount of questions.", + "default":"Spørgsmål %d ud af %total" + }, + { + "label":"Copyright dialog question label", + "default":"Spørgsmål" + }, + { + "label":"Readspeaker progress", + "description":"May use @current and @total question variables", + "default":"Spørgsmål @current ud af @total" + }, + { + "label":"Unanswered question text", + "default":"Ubesvaret" + }, + { + "label":"Answered question text", + "default":"Besvaret" + }, + { + "label":"Current question text", + "default":"Aktuel spørgsmål" + } + ] + }, + { + "label":"Disable backwards navigation", + "description":"This option will only allow you to move forward in Question Set" + }, + { + "label":"Randomize questions", + "description":"Enable to randomize the order of questions on display." + }, + { + "label":"Number of questions to be shown:", + "description":"Create a randomized batch of questions from the total." + }, + { + "label":"Quiz finished", + "fields":[ + { + "label":"Display results" + }, + { + "label":"Display solution button" + }, + { + "label":"No results message", + "description":"Text displayed on end page when \"Display results\" is disabled", + "default":"Finished" + }, + { + "label":"Feedback heading", + "default":"Your result:", + "description":"This heading will be displayed at the end of the quiz when the user has answered all questions." + }, + { + "label":"Overall Feedback", + "fields":[ + { + "widgets":[ + + ], + "label":"Define custom feedback for any score range", + "description":"Example: 0-20% Bad score, 21-91% Average Score, 91-100% Great Score!", + "entity":"range", + "field":{ + "fields":[ + { + "label":"Score Range" + }, + { + + }, + { + "label":"Feedback for defined score range", + "placeholder":"Fill in the feedback" + } + ] + } + } + ] + }, + { + "label":"Old Feedback", + "fields":[ + { + "label":"Quiz passed greeting", + "description":"This text will be displayed above the score if the user has successfully passed the quiz." + }, + { + "label":"Passed comment", + "description":"This comment will be displayed after the score if the user has successfully passed the quiz." + }, + { + "label":"Quiz failed title", + "description":"This text will be displayed above the score if the user has failed the quiz." + }, + { + "label":"Failed comment", + "description":"This comment will be displayed after the score if the user has failed the quiz." + } + ] + }, + { + "label":"Solution button label", + "default":"Show solution", + "description":"Text for the solution button." + }, + { + "label":"Retry button label", + "default":"Retry", + "description":"Text for the retry button." + }, + { + "label":"Finish button text", + "default":"Finish" + }, + { + "label":"Display video before quiz results" + }, + { + "label":"Enable skip video button" + }, + { + "label":"Skip video button label", + "default":"Skip video" + }, + { + "label":"Passed video", + "description":"This video will be played if the user successfully passed the quiz." + }, + { + "label":"Fail video", + "description":"This video will be played if the user failes the quiz." + } + ] + }, + { + "label":"Settings for \"Show solution\" and \"Retry\" buttons", + "fields":[ + { + "label":"Override \"Show Solution\" button", + "description":"This option determines if the \"Show Solution\" button will be shown for all questions, disabled for all or configured for each question individually.", + "options":[ + { + "label":"Enabled" + }, + { + "label":"Disabled" + } + ] + }, + { + "label":"Override \"Retry\" button", + "description":"This option determines if the \"Retry\" button will be shown for all questions, disabled for all or configured for each question individually.", + "options":[ + { + "label":"Enabled" + }, + { + "label":"Disabled" + } + ] + } + ] + } + ] +} diff --git a/language/de.json b/language/de.json index 1713d8b..8c8542e 100644 --- a/language/de.json +++ b/language/de.json @@ -103,7 +103,7 @@ "default": "Beantwortet" }, { - "label": "Text fpr aktuelle Frage", + "label": "Text für aktuelle Frage", "default": "Aktuelle Frage" } ] @@ -154,7 +154,7 @@ }, { "label": "Kopfzeile für nicht bestandenes Quiz", - "default": "Diese Mal hast du nicht bestanden.", + "default": "Dieses Mal hast du nicht bestanden.", "description": "Dieser Text wird oberhalb der Punkte angezeigt, wenn der Nutzer das Quiz nicht bestanden hat." }, { diff --git a/language/fr.json b/language/fr.json index dc445fa..25d6038 100644 --- a/language/fr.json +++ b/language/fr.json @@ -126,6 +126,9 @@ { "label": "Afficher les résultats" }, + { + "label": "Display solution button" + }, { "label": "Message si pas de résultats", "description": "Texte affiché sur la page finale si l'option \"Afficher les résultats\" est désactivée.", @@ -226,4 +229,4 @@ ] } ] -} +} \ No newline at end of file diff --git a/language/it.json b/language/it.json index d520b11..7b7a5b5 100644 --- a/language/it.json +++ b/language/it.json @@ -121,6 +121,9 @@ { "label": "Visualizza risultati" }, + { + "label": "Display solution button" + }, { "label": "No results message", "description": "Text displayed on end page when \"Display results\" is disabled", @@ -210,4 +213,4 @@ ] } ] -} +} \ No newline at end of file diff --git a/language/nb.json b/language/nb.json index 4c2aa48..650641d 100644 --- a/language/nb.json +++ b/language/nb.json @@ -126,6 +126,9 @@ { "label": "Vis resultater" }, + { + "label": "Vis resultatknapp" + }, { "label": "Melding når resultater ikke vises", "description": "Teksten vises på avslutnings-siden når resultater ikke vises", @@ -225,4 +228,4 @@ ] } ] -} +} \ No newline at end of file diff --git a/language/nn.json b/language/nn.json index 33507d1..54a5a25 100644 --- a/language/nn.json +++ b/language/nn.json @@ -126,6 +126,9 @@ { "label": "Vis resultat" }, + { + "label": "Vis resultatknapp" + }, { "label": "Melding når resultater ikke vises", "description": "Teksten vises på avslutnings-siden når resultater ikke vises", @@ -225,4 +228,4 @@ ] } ] -} +} \ No newline at end of file diff --git a/library.json b/library.json index dcb9339..0c46467 100644 --- a/library.json +++ b/library.json @@ -3,8 +3,8 @@ "description": "Put together a set of different questions that has to be solved. (Quiz)", "contentType": "question", "majorVersion": 1, - "minorVersion": 12, - "patchVersion": 1, + "minorVersion": 13, + "patchVersion": 0, "embedTypes": [ "iframe" ], @@ -14,7 +14,7 @@ "author": "Joubel", "coreApi": { "majorVersion": 1, - "minorVersion": 6 + "minorVersion": 14 }, "license": "MIT", "preloadedJs": [ @@ -50,6 +50,11 @@ } ], "editorDependencies": [ + { + "machineName": "H5PEditor.RangeList", + "majorVersion": 1, + "minorVersion": 0 + }, { "machineName": "H5PEditor.VerticalTabs", "majorVersion": 1, @@ -61,4 +66,4 @@ "minorVersion": 2 } ] -} \ No newline at end of file +} diff --git a/semantics.json b/semantics.json index a501305..733e68e 100644 --- a/semantics.json +++ b/semantics.json @@ -121,11 +121,11 @@ "importance": "high", "description": "Library for this question.", "options": [ - "H5P.MultiChoice 1.9", - "H5P.DragQuestion 1.9", - "H5P.Blanks 1.7", - "H5P.MarkTheWords 1.6", - "H5P.DragText 1.5", + "H5P.MultiChoice 1.10", + "H5P.DragQuestion 1.11", + "H5P.Blanks 1.8", + "H5P.MarkTheWords 1.7", + "H5P.DragText 1.6", "H5P.TrueFalse 1.1" ] } @@ -255,6 +255,12 @@ "importance": "low", "default": true }, + { + "name": "showSolutionButton", + "type": "boolean", + "label": "Display solution button", + "default": true + }, { "name": "noResultMessage", "type": "text", @@ -270,7 +276,6 @@ "label": "Feedback heading", "importance": "low", "default": "Your result:", - "optional": true, "description": "This heading will be displayed at the end of the quiz when the user has answered all questions.", "tags": [ "strong", @@ -278,75 +283,127 @@ ] }, { - "name": "scoreString", - "type": "text", - "label": "Score display text", + "name": "overallFeedback", + "type": "group", + "label": "Overall Feedback", "importance": "low", - "description": "Text used to display Total user score. \"@score\" will be replaced by calculated score, \"@total\" will be replaced by maximum possible score. ", - "default": "You got @score of @total points", - "optional": true - }, - { - "name": "successGreeting", - "type": "text", - "label": "Quiz passed greeting", - "importance": "low", - "placeholder": "Congratulations!", - "default": "Congratulations!", - "optional": true, - "description": "This text will be displayed above the score if the user has successfully passed the quiz.", - "tags": [ - "strong", - "em" + "fields": [ + { + "name": "overallFeedback", + "type": "list", + "widgets": [ + { + "name": "RangeList", + "label": "Default" + } + ], + "importance": "high", + "label": "Define custom feedback for any score range", + "description": "Example: 0-20% Bad score, 21-91% Average Score, 91-100% Great Score!", + "entity": "range", + "min": 1, + "defaultNum": 1, + "optional": true, + "field": { + "name": "overallFeedback", + "type": "group", + "importance": "low", + "fields": [ + { + "name": "from", + "type": "number", + "label": "Score Range", + "min": 0, + "max": 100, + "default": 0, + "unit": "%" + }, + { + "name": "to", + "type": "number", + "min": 0, + "max": 100, + "default": 100, + "unit": "%" + }, + { + "name": "feedback", + "type": "text", + "label": "Feedback for defined score range", + "importance": "low", + "placeholder": "Fill in the feedback", + "optional": true + } + ] + } + } ] }, { - "name": "successComment", - "type": "text", - "widget": "html", - "label": "Passed comment", + "name": "oldFeedback", + "type": "group", + "label": "Old Feedback", "importance": "low", - "default": "You did very well!", - "optional": true, - "description": "This comment will be displayed after the score if the user has successfully passed the quiz.", - "tags": [ - "sub", - "sup", - "strong", - "em", - "a", - "p" - ] - }, - { - "name": "failGreeting", - "type": "text", - "label": "Quiz failed title", - "importance": "low", - "default": "You did not pass this time.", - "optional": true, - "description": "This text will be displayed above the score if the user has failed the quiz.", - "tags": [ - "strong", - "em" - ] - }, - { - "name": "failComment", - "type": "text", - "widget": "html", - "label": "Failed comment", - "importance": "low", - "default": "Have another try!", - "optional": true, - "description": "This comment will be displayed after the score if the user has failed the quiz.", - "tags": [ - "sub", - "sup", - "strong", - "em", - "a", - "p" + "deprecated": true, + "fields": [ + { + "name": "successGreeting", + "type": "text", + "label": "Quiz passed greeting", + "importance": "low", + "optional": true, + "description": "This text will be displayed above the score if the user has successfully passed the quiz.", + "tags": [ + "strong", + "em" + ] + }, + { + "name": "successComment", + "type": "text", + "widget": "html", + "label": "Passed comment", + "importance": "low", + "optional": true, + "description": "This comment will be displayed after the score if the user has successfully passed the quiz.", + "tags": [ + "sub", + "sup", + "strong", + "em", + "a", + "p" + ] + }, + { + "name": "failGreeting", + "type": "text", + "label": "Quiz failed title", + "importance": "low", + "optional": true, + "description": "This text will be displayed above the score if the user has failed the quiz.", + "tags": [ + "strong", + "em" + ] + }, + { + "name": "failComment", + "type": "text", + "widget": "html", + "label": "Failed comment", + "importance": "low", + "optional": true, + "description": "This comment will be displayed after the score if the user has failed the quiz.", + "tags": [ + "sub", + "sup", + "strong", + "em", + "a", + "p" + ] + } ] }, { @@ -454,4 +511,4 @@ } ] } -] \ No newline at end of file +] diff --git a/upgrades.js b/upgrades.js index dc41328..7829f31 100644 --- a/upgrades.js +++ b/upgrades.js @@ -52,6 +52,52 @@ H5PUpgrades['H5P.QuestionSet'] = (function ($) { // Remove old copyright dialog question label delete parameters.questionLabel; + finished(null, parameters); + }, + + /** + * Asynchronous content upgrade hook. + * + * Upgrade params to support overall feedback + * + * @param {Object} parameters + * @param {function} finished + */ + 13: function (parameters, finished) { + + parameters.endGame = parameters.endGame || {}; + parameters.endGame.overallFeedback = []; + + if (parameters.endGame.scoreString) { + parameters.endGame.overallFeedback.push({ + from: 0, + to: 100, + feedback: parameters.endGame.scoreString + }); + + delete parameters.endGame.scoreString; + } + + // Group old feedback fields + if (parameters.endGame.successGreeting || + parameters.endGame.successComment || + parameters.endGame.failGreeting || + parameters.endGame.failComment) { + parameters.endGame.oldFeedback = {}; + if (parameters.endGame.successGreeting) { + parameters.endGame.oldFeedback.successGreeting = parameters.endGame.successGreeting; + } + if (parameters.endGame.successComment) { + parameters.endGame.oldFeedback.successComment = parameters.endGame.successComment; + } + if (parameters.endGame.failGreeting) { + parameters.endGame.oldFeedback.failGreeting = parameters.endGame.failGreeting; + } + if (parameters.endGame.failComment) { + parameters.endGame.oldFeedback.failComment = parameters.endGame.failComment; + } + } + finished(null, parameters); } }