Merge branch 'release' into stable

pull/2/head 1.5.0
Frode Petterson 2015-10-07 10:02:12 +02:00
commit 7bb0a928f1
5 changed files with 320 additions and 163 deletions

View File

@ -62,7 +62,7 @@
font-weight: bold; font-weight: bold;
text-align: center; text-align: center;
} }
.intro-page .title > span { .intro-page .title > span {
padding: 0.125em 0.5em; padding: 0.125em 0.5em;
border-radius: 0.125em; border-radius: 0.125em;
background: rgb(255,255,255); /* Fallback for browsers not supporting rgba */ background: rgb(255,255,255); /* Fallback for browsers not supporting rgba */
@ -91,37 +91,7 @@
.qs-footer { .qs-footer {
overflow: hidden; overflow: hidden;
} }
.qs-footer .h5p-button, .qs-startbutton, .qs-finishbutton, .questionset-results .h5p-button, .video-container > .h5p-button {
display: inline-block;
padding: 0 0.7em;
border: 0.2em solid #fff;
border-radius: 0.4em;
margin: 0 0.5em 1em;
cursor: pointer;
color: #ffffff;
box-shadow: 0 0 0.5em #999;
line-height: 1.9em;
background: rgb(100,152,254); /* Old browsers */
background: -moz-linear-gradient(top, rgba(100,152,254,1) 0%, rgba(4,104,206,1) 100%); /* FF3.6+ */
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(100,152,254,1)), color-stop(100%,rgba(4,104,206,1))); /* Chrome,Safari4+ */
background: -webkit-linear-gradient(top, rgba(100,152,254,1) 0%,rgba(4,104,206,1) 100%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top, rgba(100,152,254,1) 0%,rgba(4,104,206,1) 100%); /* Opera 11.10+ */
background: -ms-linear-gradient(top, rgba(100,152,254,1) 0%,rgba(4,104,206,1) 100%); /* IE10+ */
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#6498fe', endColorstr='#0468ce',GradientType=0 ); /* IE6-9 */
}
.qs-footer .h5p-button:hover, .qs-startbutton:hover, .questionset-results .h5p-button:hover, .video-container > .h5p-button:hover {
text-decoration: none;
box-shadow: 0 0 0.5em #999;
color: #ffffff;
border-color: #fff;
background: rgb(4,104,206); /* Old browsers */
background: -moz-linear-gradient(top, rgba(4,104,206,1) 0%, rgba(100,152,254,1) 100%); /* FF3.6+ */
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(4,104,206,1)), color-stop(100%,rgba(100,152,254,1))); /* Chrome,Safari4+ */
background: -webkit-linear-gradient(top, rgba(4,104,206,1) 0%,rgba(100,152,254,1) 100%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top, rgba(4,104,206,1) 0%,rgba(100,152,254,1) 100%); /* Opera 11.10+ */
background: -ms-linear-gradient(top, rgba(4,104,206,1) 0%,rgba(100,152,254,1) 100%); /* IE10+ */
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#0468ce', endColorstr='#6498fe',GradientType=0 ); /* IE6-9 */
}
.qs-footer > .prev { .qs-footer > .prev {
float: left; float: left;
} }
@ -137,35 +107,60 @@
.questionset-results a.h5p-button.qs-retrybutton:before { .questionset-results a.h5p-button.qs-retrybutton:before {
font-family: 'H5PFontAwesome4'; font-family: 'H5PFontAwesome4';
padding-right: 0.5em; padding-right: 0.5em;
content: "\f021"; content: "\f01e";
} }
.qs-footer > .next, .qs-footer > .finish, .qs-finishbutton { .qs-footer > .next, .qs-footer > .finish, .qs-finishbutton {
float: right; float: right;
} }
.qs-footer a.next.h5p-button:after { .h5p-question .h5p-question-prev,
font-family: 'H5PFontAwesome4'; .h5p-question .h5p-question-finish,
content: "\f054"; /* TODO: Use margin not whitespace, spacing is not content! */ .h5p-question .h5p-question-next {
float: right;
} }
.qs-footer a.prev.h5p-button:before { .h5p-question .h5p-question-prev,
font-family: 'H5PFontAwesome4'; .h5p-question .h5p-question-next {
padding: 0;
height: 2.1875em;
width: 2.1875em;
}
.h5p-question .h5p-question-next,
.h5p-question .h5p-question-finish {
margin: 0 0 1.5em 0.5em;
}
.h5p-question .h5p-question-prev {
margin: 0 0.5em 1.5em 0.5em;
}
.h5p-question .h5p-question-next:before {
content: "\f054";
padding-right: 0;
position: relative;
left: 2px;
}
.h5p-question .h5p-question-prev:before {
content: "\f053"; content: "\f053";
padding-right: 0;
position: relative;
left: -2px;
} }
.questionset-results .qs-finishbutton { .questionset-results .qs-finishbutton {
display: none; display: none;
} }
.qs-footer a.finish.h5p-button:before { .h5p-question .h5p-question-finish:before {
font-family: 'H5PFontAwesome4'; content: "\f00c";
content: "\f00c ";
} }
.questionset-results a.h5p-button.qs-solutionbutton:before { .questionset-results a.h5p-button.qs-solutionbutton:before {
font-family: 'H5PFontAwesome4'; font-family: 'H5PFontAwesome4';
content: "\f06e "; content: "\f06e "; /* TODO: Use margin not whitespace, spacing is not content! */
} }
.video-container { .video-container {
@ -192,80 +187,37 @@
padding: 0.625em; padding: 0.625em;
} }
.questionset-results .greeting { .questionset-results .feedback-section {
text-align: left; margin: 1em;
border-bottom: 0.1em solid #ddd;
width: 100%;
} }
.questionset-results .score { .questionset-results .feedback-section .feedback-text {
margin: 0; font-weight: bold;
display: block; color: #1a73d9;
margin-bottom: 2em;
} }
.questionset-results .resulttext { .questionset-results .buttons {
text-align: left; margin-bottom: 1.5em;
font-size: 1.25em;
line-height: 1.25em;
margin: 1em 0em;
background-repeat: no-repeat;
background-position: left center;
} }
.questionset-results .resulttext.fail em { /* No margin for questions when no frame */
font-style: normal; .h5p-no-frame .questionset .h5p-question > * {
color: #b9272d; margin-left: 0;
margin-right: 0;
} }
.questionset-results .score.success .emoticon:before { .h5p-no-frame .questionset-results .feedback-section,
font-family: icomoon-questionset; .h5p-no-frame .questionset .h5p-question > *:first-child {
font-size: 5em; margin-top: 0;
line-height: 100%;
content: "\e606";
float: left;
} }
.questionset-results .score.fail .emoticon:before { .h5p-no-frame .questionset-results .buttons,
font-family: icomoon-questionset; .h5p-no-frame .questionset .h5p-question > *:last-child {
font-size: 5em; margin-bottom: 0;
line-height: 100%;
content: "\e607";
float: left;
} }
.questionset-results .resulttext.success, /* Hide retry and show solution buttons */
.questionset-results .resulttext.almost, .questionset .h5p-question .h5p-question-try-again,
.questionset-results .resulttext.fail .questionset .h5p-question .h5p-question-show-solution {
{ display: none;
display: block;
background: #eee;
padding: 1em;
border-radius: 1em;
margin-left: 6.5em;
position: relative;
font-size: 1em;
}
.questionset-results .resulttext.success:before,
.questionset-results .resulttext.fail:before
{
font-family: icomoon-questionset;
content: "";
font-size: 5em;
position: absolute;
left: -14px;
top: 36px;
height: 0;
width: 0;
border-top: 15px solid transparent;
border-bottom: 15px solid transparent;
border-right: 15px solid #eee;
display: inline-block;
}
.questionset-results .resulttext.success em {
font-style: normal;
color: #6aa81b;
text-align: left;
} }

View File

@ -28,7 +28,7 @@ H5P.QuestionSet = function (options, contentId) {
' <% if (introPage.introduction) { %>' + ' <% if (introPage.introduction) { %>' +
' <div class="introduction"><%= introPage.introduction %></div>' + ' <div class="introduction"><%= introPage.introduction %></div>' +
' <% } %>' + ' <% } %>' +
' <div class="buttons"><a class="qs-startbutton h5p-button"><%= introPage.startButtonText %></a></div>' + ' <div class="buttons"><a class="qs-startbutton h5p-joubelui-button h5p-button"><%= introPage.startButtonText %></a></div>' +
'</div>' + '</div>' +
'<% } %>' + '<% } %>' +
'<div class="questionset<% if (introPage.showIntroPage) { %> hidden<% } %>">' + '<div class="questionset<% if (introPage.showIntroPage) { %> hidden<% } %>">' +
@ -47,20 +47,20 @@ H5P.QuestionSet = function (options, contentId) {
' <span class="progress-text"></span>' + ' <span class="progress-text"></span>' +
' <% } %>' + ' <% } %>' +
' </div>' + ' </div>' +
' <a class="prev h5p-button" title="<%= texts.prevButton %>"></a>' +
' <a class="next h5p-button" title="<%= texts.nextButton %>"></a>' +
' <a class="finish h5p-button"><%= texts.finishButton %></a>' +
' </div>' + ' </div>' +
'</div>'; '</div>';
var resulttemplate = var resulttemplate =
'<div class="questionset-results">' + '<div class="questionset-results">' +
' <div class="greeting"><%= message %></div>' + ' <div class="feedback-section">' +
' <div class="score <%= scoreclass %>">' + ' <div class="feedback-scorebar"></div>' +
' <div class="emoticon"></div>' + ' <div class="feedback-text"></div>' +
' <div class="resulttext <%= scoreclass %>"><% if (comment) { %><h2><%= comment %></h2><% } %><%= score %><br><%= resulttext %></div>' + ' </div>' +
' <div class="buttons">' +
' <a class="h5p-joubelui-button h5p-button qs-finishbutton"><%= finishButtonText %></a>' +
' <a class="h5p-joubelui-button h5p-button qs-solutionbutton"><%= solutionButtonText %></a>' +
' <a class="h5p-joubelui-button h5p-button qs-retrybutton"></a>' +
' </div>' + ' </div>' +
' <div class="buttons"><a class="h5p-button qs-finishbutton"><%= finishButtonText %></a><a class="h5p-button qs-solutionbutton"><%= solutionButtonText %></a><a class="h5p-button qs-retrybutton"></a></div>' +
'</div>'; '</div>';
var defaults = { var defaults = {
@ -109,6 +109,7 @@ H5P.QuestionSet = function (options, contentId) {
var currentQuestion = 0; var currentQuestion = 0;
var questionInstances = []; var questionInstances = [];
var $myDom; var $myDom;
var scoreBar;
renderSolutions = false; renderSolutions = false;
// Instantiate question instances // Instantiate question instances
@ -126,11 +127,15 @@ H5P.QuestionSet = function (options, contentId) {
} }
var questionInstance = H5P.newRunnable(question, contentId, undefined, undefined, {parent: self}); var questionInstance = H5P.newRunnable(question, contentId, undefined, undefined, {parent: self});
questionInstances.push(questionInstance); questionInstances.push(questionInstance);
questionInstance.on('resize', function() {
self.trigger('resize');
});
} }
// Resize all interactions on resize
self.on('resize', function () {
for (var i = 0; i < questionInstances.length; i++) {
questionInstances[i].trigger('resize');
}
});
// Update button state. // Update button state.
var _updateButtons = function () { var _updateButtons = function () {
var answered = true; var answered = true;
@ -138,19 +143,8 @@ H5P.QuestionSet = function (options, contentId) {
answered = answered && (questionInstances[i]).getAnswerGiven(); answered = answered && (questionInstances[i]).getAnswerGiven();
} }
if (currentQuestion === 0) { if (currentQuestion === (params.questions.length - 1) && answered) {
$('.prev.h5p-button', $myDom).hide(); questionInstances[currentQuestion].showButton('finish');
} else {
$('.prev.h5p-button', $myDom).show();
}
if (currentQuestion === (params.questions.length - 1)) {
$('.next.h5p-button', $myDom).hide();
if (answered) {
$('.finish.h5p-button', $myDom).show();
}
} else {
$('.next.h5p-button', $myDom).show();
$('.finish.h5p-button', $myDom).hide();
} }
}; };
@ -201,8 +195,8 @@ H5P.QuestionSet = function (options, contentId) {
questionInstances[i].showSolutions(); questionInstances[i].showSolutions();
} }
catch(error) { catch(error) {
console.log(error); H5P.error("subcontent does not contain a valid showSolutions function");
console.log("subcontent does not contain a valid showSolutions() function"); H5P.error(error);
} }
} }
}; };
@ -218,10 +212,14 @@ H5P.QuestionSet = function (options, contentId) {
questionInstances[i].resetTask(); questionInstances[i].resetTask();
} }
catch(error) { catch(error) {
console.log(error); H5P.error("subcontent does not contain a valid resetTask function");
console.log("subcontent does not contain a valid resetTask() function"); H5P.error(error);
} }
} }
// Hide finish button
questionInstances[questionInstances.length - 1].hideButton('finish');
//Force the last page to be reRendered //Force the last page to be reRendered
rendered = false; rendered = false;
}; };
@ -260,11 +258,7 @@ H5P.QuestionSet = function (options, contentId) {
} }
var eparams = { var eparams = {
message: params.endGame.message,
comment: (success ? params.endGame.successGreeting : params.endGame.failGreeting), comment: (success ? params.endGame.successGreeting : params.endGame.failGreeting),
score: scoreString,
scoreclass: (success ? 'success' : 'fail'),
resulttext: (success ? params.endGame.successComment : params.endGame.failComment),
finishButtonText: params.endGame.finishButtonText, finishButtonText: params.endGame.finishButtonText,
solutionButtonText: params.endGame.solutionButtonText solutionButtonText: params.endGame.solutionButtonText
}; };
@ -272,7 +266,7 @@ H5P.QuestionSet = function (options, contentId) {
// Show result page. // Show result page.
$myDom.children().hide(); $myDom.children().hide();
$myDom.append(endTemplate.render(eparams)); $myDom.append(endTemplate.render(eparams));
$('.qs-finishbutton').click(function () { $('.qs-finishbutton', $myDom).click(function () {
self.trigger('h5pQuestionSetFinished', eventData); self.trigger('h5pQuestionSetFinished', eventData);
}); });
$('.qs-solutionbutton', $myDom).click(function () { $('.qs-solutionbutton', $myDom).click(function () {
@ -286,6 +280,13 @@ H5P.QuestionSet = function (options, contentId) {
resetTask(); resetTask();
$myDom.children().hide().filter('.questionset').show(); $myDom.children().hide().filter('.questionset').show();
_showQuestion(params.initialQuestion);}); _showQuestion(params.initialQuestion);});
if (scoreBar === undefined) {
scoreBar = H5P.JoubelUI.createScoreBar(totals);
}
scoreBar.appendTo($('.feedback-scorebar', $myDom));
scoreBar.setScore(finals);
$('.feedback-text', $myDom).html(scoreString);
}; };
if (params.endGame.showAnimations) { if (params.endGame.showAnimations) {
@ -314,7 +315,7 @@ H5P.QuestionSet = function (options, contentId) {
video.play(); video.play();
if (params.endGame.skipButtonText) { if (params.endGame.skipButtonText) {
$('<a class="h5p-button skip">' + params.endGame.skipButtonText + '</a>').click(function () { $('<a class="h5p-joubelui-button h5p-button skip">' + params.endGame.skipButtonText + '</a>').click(function () {
video.pause(); video.pause();
$videoContainer.hide(); $videoContainer.hide();
displayResults(); displayResults();
@ -331,6 +332,7 @@ H5P.QuestionSet = function (options, contentId) {
// Function for attaching the multichoice to a DOM element. // Function for attaching the multichoice to a DOM element.
this.attach = function (target) { this.attach = function (target) {
this.setActivityStarted();
if (typeof(target) === "string") { if (typeof(target) === "string") {
$myDom = $('#' + target); $myDom = $('#' + target);
} }
@ -358,16 +360,59 @@ H5P.QuestionSet = function (options, contentId) {
} }
} }
var registerImageLoadedListener = function (question) {
H5P.on(question, 'imageLoaded', function () {
self.trigger('resize');
});
};
// Attach questions // Attach questions
for (var i = 0; i < questionInstances.length; i++) { for (var i = 0; i < questionInstances.length; i++) {
var question = questionInstances[i]; var question = questionInstances[i];
question.attach($('.question-container:eq(' + i + ')', $myDom)); question.attach($('.question-container:eq(' + i + ')', $myDom));
// Listen for image resize
registerImageLoadedListener(question);
// Disable feedback for question
question.setBehaviour({disableFeedback: true});
// Add next/finish button
if (questionInstances[questionInstances.length -1] === question) {
// Add finish question set button
question.addButton('finish', params.texts.finishButton, function () {
_displayEndGame();
}, false);
} else {
// Add next question button
question.addButton('next', '', function () {
_showQuestion(currentQuestion + 1);
});
}
// Add previous question button
if (questionInstances[0] !== question) {
question.addButton('prev', '', function () {
_showQuestion(currentQuestion - 1);
});
}
question.on('xAPI', function (event) { question.on('xAPI', function (event) {
if (event.getVerb() === 'attempted') { var shortVerb = event.getVerb();
if (shortVerb === 'interacted' ||
shortVerb === 'answered' ||
shortVerb === 'attempted') {
$('.progress-dot:eq(' + currentQuestion +')', $myDom).removeClass('unanswered').addClass('answered'); $('.progress-dot:eq(' + currentQuestion +')', $myDom).removeClass('unanswered').addClass('answered');
_updateButtons(); _updateButtons();
} }
if (shortVerb === 'completed') {
// An activity within this activity is not allowed to send completed events
event.setVerb('answered');
}
}); });
if (question.getAnswerGiven()) { if (question.getAnswerGiven()) {
$('.progress-dot:eq(' + i +')', $myDom).removeClass('unanswered').addClass('answered'); $('.progress-dot:eq(' + i +')', $myDom).removeClass('unanswered').addClass('answered');
@ -387,15 +432,6 @@ H5P.QuestionSet = function (options, contentId) {
$('.progress-dot', $myDom).click(function () { $('.progress-dot', $myDom).click(function () {
_showQuestion($(this).index()); _showQuestion($(this).index());
}); });
$('.next.h5p-button', $myDom).click(function () {
_showQuestion(currentQuestion + 1);
});
$('.prev.h5p-button', $myDom).click(function () {
_showQuestion(currentQuestion - 1);
});
$('.finish.h5p-button', $myDom).click(function () {
_displayEndGame();
});
// Hide all but initial Question. // Hide all but initial Question.
_showQuestion(params.initialQuestion); _showQuestion(params.initialQuestion);

163
language/fr.json Normal file
View File

@ -0,0 +1,163 @@
{
"semantics": [
{
"label": "Introduction du Quiz ",
"fields": [
{
"label": "Montrer l'introduction"
},
{
"label": "Titre",
"description": "Ce titre sera affiché au-dessus de votre texte d'introduction."
},
{
"label": "Texte d'introduction ",
"description": "Ce texte sera affiché avant le démarrage du quiz."
},
{
"label": "Texte du bouton de démarrage"
},
{
"label": "Image d'arrière-plan",
"description": "Image d'arrière-plan optionnelle pour l'introduction."
}
]
},
{
"label": "Image d'arrière-plan",
"description": "Image d'arrière-plan optionnelle pour la série de questions."
},
{
"label": "Indicateur de progression",
"description": "Style de l'indicateur de progression de la série de questions",
"options": [
{
"label": "Texte"
},
{
"label": "Points"
}
]
},
{
"label": "Pourcentage de réussite",
"description": "Pourcentage exigé pour la réussite du quiz."
},
{
"label": "Questions",
"widgets": [
{
"label": "Par défaut"
},
{
"label": "Texte"
}
],
"entity": "question",
"field": {
"label": "Type de question",
"description": "Types possibles pour cette question."
}
},
{
"label": "Interface des Textes dans le quiz",
"fields": [
{
"label": "Bouton précédent"
},
{
"label": "Bouton suivant"
},
{
"label": "Bouton fin"
},
{
"label": "Texte de progression",
"description": "Texte utilisé si la progression textuelle est utilisée."
}
]
},
{
"label": "Quiz fini",
"fields": [
{
"label": "Montrer les résultats"
},
{
"label": "Feedback de fin",
"description": "Ce texte sera affiché quand l'utilisateur aura totalement terminé le quiz."
},
{
"label": "Texte d'affichage du score",
"description": "Texte utilisé pour afficher le score total de l'utilisateur. \"@score\" sera remplacé par le score de l'utilisateur, \"@total\" sera remplacé par le score maximum possible."
},
{
"label": "Texte de félicitation",
"description": "Texte affiché lors du passage du quiz avec succès."
},
{
"label": "Commentaire de fin de quiz réussi",
"description": "Commentaire affiché lors du passage du quiz avec succès."
},
{
"label": "Texte d'échec",
"description": "Texte affiché lors de l'échec au quiz."
},
{
"label": "Commentaire de fin de quiz échoué",
"description": "Commentaire affiché lors de l'échec au quiz."
},
{
"label": "Texte du bouton Solution",
"description": "Texte pour le bouton de solution."
},
{
"label": "Texte du bouton Réessayer",
"description": "Texte pour le bouton Réessayer."
},
{
"label": "Texte pour le bouton de fin"
},
{
"label": "Montrer une vidéo avant l'affichage des résultats du quiz"
},
{
"label": "Activer le bouton passer la vidéo"
},
{
"label": "Texte du bouton passer la vidéo"
},
{
"label": "Video en cas de succès",
"description": "Vidéo affichée lors du passage du quiz avec succès."
},
{
"label": "Video en cas d'échec",
"description": "Vidéo affichée lors de l'échec au quiz."
}
]
},
{
"label": "Options pour les boutons \"Montrer la solution\" et \"Réessayer\".",
"description": "Ces options vous permettent de choisir quand afficher les boutons \"Solutions\" et \"Réessayer\" dans votre acivité h5p..",
"fields": [
{
"label": "Activer les réglages par défaut pour les boutons \"Solution\" et \"Réessayer\".",
"description": "Si cette option est choisie, les réglages seront valables pour toutes les questions, les réglages individuels ne seront pas pris en compte."
},
{
"label": "Afficher le bouton \"Solution\".",
"description": "Affiche le bouton \"Solution\"."
},
{
"label": "Afficher le bouton \"Réessayer\".",
"description": "Affiche le bouton \"Réessayer\"."
}
]
},
{
"label": "Texte de la question",
"default": "Question"
}
]
}

View File

@ -1,9 +1,10 @@
{ {
"title": "Question set", "title": "Question Set",
"description": "Put together a set of different questions that has to be solved. (Quiz)",
"contentType": "question", "contentType": "question",
"majorVersion": 1, "majorVersion": 1,
"minorVersion": 4, "minorVersion": 5,
"patchVersion": 2, "patchVersion": 0,
"embedTypes": [ "embedTypes": [
"iframe" "iframe"
], ],
@ -13,9 +14,9 @@
"author": "Joubel AS", "author": "Joubel AS",
"coreApi": { "coreApi": {
"majorVersion": 1, "majorVersion": 1,
"minorVersion": 5 "minorVersion": 6
}, },
"license": "cc-by-sa", "license": "MIT",
"preloadedJs": [ "preloadedJs": [
{ {
"path": "js/questionset.js" "path": "js/questionset.js"
@ -35,12 +36,17 @@
{ {
"machineName": "FontAwesome", "machineName": "FontAwesome",
"majorVersion": 4, "majorVersion": 4,
"minorVersion": 1 "minorVersion": 3
}, },
{ {
"machineName": "H5P.Video", "machineName": "H5P.Video",
"majorVersion": 1, "majorVersion": 1,
"minorVersion": 1 "minorVersion": 1
},
{
"machineName": "H5P.JoubelUI",
"majorVersion": 1,
"minorVersion": 2
} }
], ],
"editorDependencies": [ "editorDependencies": [
@ -55,4 +61,4 @@
"minorVersion": 0 "minorVersion": 0
} }
] ]
} }

View File

@ -110,11 +110,11 @@
"label": "Question type", "label": "Question type",
"description": "Library for this question.", "description": "Library for this question.",
"options": [ "options": [
"H5P.MultiChoice 1.3", "H5P.MultiChoice 1.4",
"H5P.DragQuestion 1.4", "H5P.DragQuestion 1.5",
"H5P.Blanks 1.3", "H5P.Blanks 1.4",
"H5P.MarkTheWords 1.3", "H5P.MarkTheWords 1.4",
"H5P.DragText 1.3" "H5P.DragText 1.4"
] ]
} }
}, },