// © 2022 Uniwersytet im. Adama Mickiewicza w Poznaniu // Biblioteka pozwala na zapisywanie różnych informacji o aktywnościach studenta. var contentFrameReference = null; var courseWindowReference = null; const scoReadyTime = getTimeAsStringShort(); var allInteractionsForLinksInitialized = false; var allInteractionsForQuizInitialized = false; var allInteractionsForFillInInitialized = false; var allInteractionsForFillInNumericInitialized = false; var allInteractionsForDragAndDropInitialized = false; var quizClicksArr = []; var interactiondIDList = []; $(function() { quizClicksArr = []; interactiondIDList = []; let interactionsCountSet = false; $(window).scroll(function(){ if (!interactionsCountSet) { const result = prepare(interactionsCountSet, null); interactionsCountSet = result.interactionsCountSet; } }); if ($("a[target='popup']").size() > 0) { $("a[target='popup']").click(function() { let interactionId = -1; const interactionName = $(this).text() + " url:" + $(this).attr("href") + " sco: " + getScoName() + " (" + getScoId() + ")"; const result = prepare(interactionsCountSet, interactionName); interactionsCountSet = result.interactionsCountSet; interactionId = result.interactionId; if (interactionId != -1) { saveData(interactionId, "clicked", "neutral"); } }); } if ($(".el-draganddrop-buttons-container").size() > 0) { $(".el-draganddrop-buttons-container").each(function() { let container$ = $(this); container$.find(".el-draganddrop-checkbutton").click(function() { let interactionId = -1; const header = $(this).find(".el-element-header-text") != undefined ? "header: " + $(this).find(".el-element-header-text").text() : ""; const interactionName = "type: matching " + header + " sco: " + getScoName() + " (" + getScoId() + ")"; const result = prepare(interactionsCountSet, interactionName); interactionsCountSet = result.interactionsCountSet; interactionId = result.interactionId; console.log("interactionId dd: " + interactionId); if (interactionId != -1) { let d = $(this).closest(".eduexe-library-draganddrop-container"); let answers = ""; let correctness = "correct"; d.find(".el-draganddrop-draggable").each(function() { let draggableId = $(this).attr("data-drag-id"); let draggableDivQuery = 'div[data-drag-id=\"'.concat(draggableId).concat('\"]'); let draggableDiv = container$.find(draggableDivQuery); let draggableDivText = draggableDiv.text(); let droppedonDivQuery = 'div[data-droppedon-id=\"'.concat(draggableId).concat('\"]'); let droppedonDiv = container$.find(droppedonDivQuery); let dropDivQuery = 'div[data-drop-id=\"'.concat(draggableId).concat('\"]'); let dropDiv = container$.find(dropDivQuery); let dropDivKeywordText = dropDiv.prevAll(".el-draganddrop-keyword:first").text(); if (droppedonDiv.length) { var droppedonDivPairId = droppedonDiv.attr("data-drop-id"); if (droppedonDivPairId == draggableId) { // Element draggable upuszczono na właściwy element droppable draggableDiv.css("border", "2px solid green"); } else { // Element draggable upuszczono na niewłaściwy element droppable draggableDiv.css("border", "2px solid red"); correctness = "incorrect"; } } else { if (dropDiv.length) { // Element draggable pozostawiono nieupuszczony, ale była do niego para draggableDiv.css("border", "2px solid red"); correctness = "incorrect"; } else { // Element draggable pozostawiono nieupuszczony i nie było do niego pary draggableDiv.css("border", "2px solid green"); } } answers = answers + dropDivKeywordText + "[.]" + draggableDivText + "[,]"; // puste dropDivKeywordText i draggableDivText ?! :( }); answers = answers.substring(0, answers.length - 3); saveData(interactionId, answers, correctness); } }); }); } if ($(".eduexe-library-quiz-container form").size() > 0) { $(".eduexe-library-quiz-container form").click(function() { let interactionId = -1; const header = $(this).parent().parent().parent().parent().find(".el-element-header-text") != undefined ? "header: " + $(this).parent().parent().parent().parent().find(".el-element-header-text").text() : ""; const interactionName = "type: quiz " + header + " introduction:" + $(this).parent().parent().parent().parent().find("el-quiz-introduction").text() + " question:" + $(this).parent().parent().parent().parent().find(".el-quiz-question").text() + " sco: " + getScoName() + " (" + getScoId() + ")"; const result = prepare(interactionsCountSet, interactionName); interactionsCountSet = result.interactionsCountSet; interactionId = result.interactionId; if (interactionId != -1) { if (quizClicksArr.includes(interactionId)) { const index = quizClicksArr.indexOf(interactionId); if (index > -1) { quizClicksArr.splice(index, 1); } let answers = ""; let correctness = "correct"; let correctN = 0; let k = 0; const selector = $(this).parent().parent().find(".el-checkbox").size() > 0 ? ".el-checkbox" : ".el-radio"; $(this).find(selector).each(function() { if ($(this).find("input").attr("data-val") == "true") { correctN++; } }); let answersCorrectN = 0; const n = $(this).find(selector + " input:checked").size(); $(this).find(selector).each(function() { if ($(this).find("input").is(":checked")) { answers += $(this).find("p").text(); if (k < n - 1) { answers += ";"; } if ($(this).find("input").attr("data-val") == "false") { correctness = "incorrect"; } else { answersCorrectN++; } k++; } }); if (answers.length == 0) { correctness = "incorrect"; } if (correctN != answersCorrectN) { correctness = "incorrect"; } saveData(interactionId, answers, correctness); } else { quizClicksArr.push(interactionId); } } }); } if ($(".eduexe-library-fillin-container form input").size() > 0) { const $input = $('.eduexe-library-fillin-container form input'); $input.each(function() { const that = $(this); let typingTimer; //timer identifier const doneTypingInterval = 500; //time in ms, 0.5 second that.on('keyup', function(event) { const keyCode = event.keyCode || event.which; clearTimeout(typingTimer); typingTimer = setTimeout(function() { let $target = $(event.target); if (keyCode == 9) { $target = $target.parent().parent().prev().find("input"); } if ($target) { interactionsCountSet = doneTypingFillIn($target, interactionsCountSet); } if (keyCode == 9) { let nextInput = $(event.target); if (nextInput) { nextInput.focus(); } } }, doneTypingInterval); }); that.on('keydown', function() { clearTimeout(typingTimer); }); }); } if ($(".eduexe-library-numeric-container form input").size() > 0) { const $inputNumeric = $('.eduexe-library-numeric-container form input'); $inputNumeric.each(function() { const that = $(this); let typingTimerNumeric; //timer identifier const doneTypingIntervalNumeric = 500; //time in ms, 0.5 second that.on('keyup', function(event) { const keyCode = event.keyCode || event.which; clearTimeout(typingTimerNumeric); typingTimerNumeric = setTimeout(function() { let $target = $(event.target); if (keyCode == 9) { $target = $target.parent().parent().prev().find("input"); } if ($target) { interactionsCountSet = doneChangingFillInNumeric(that, interactionsCountSet); } if (keyCode == 9) { let nextInput = $(event.target); if (nextInput) { nextInput.focus(); } } }, doneTypingIntervalNumeric); }); that.on('keydown', function() { clearTimeout(typingTimerNumeric); }); let typingTimerNumericMouse; //timer identifier const doneTypingIntervalNumericMouse = 500; //time in ms, 0.5 second that.on('click', function() { clearTimeout(typingTimerNumericMouse); typingTimerNumericMouse = setTimeout(function() { interactionsCountSet = doneChangingFillInNumeric(that, interactionsCountSet); }, doneTypingIntervalNumericMouse); }); let typingTimerNumericMouseWheel; //timer identifier const doneTypingIntervalNumericMouseWheel = 500; //time in ms, 0.5 second that.on('wheel', function() { clearTimeout(typingTimerNumericMouseWheel); typingTimerNumericMouseWheel = setTimeout(function() { interactionsCountSet = doneChangingFillInNumeric(that, interactionsCountSet); }, doneTypingIntervalNumericMouseWheel); }); }); } }); function doneChangingFillInNumeric(that, interactionsCountSet) { let interactionId = -1; const header = that.parent().parent().parent().parent().parent().parent().find(".el-element-header-text") != undefined ? "header: " + that.parent().parent().parent().parent().parent().parent().find(".el-element-header-text").text() : ""; const interactionName = "type: fill-in numeric " + header + " question: " + that.parent().find(".el-slide-content-header").text() + " sco: " + getScoName() + " (" + getScoId() + ")"; let result = prepare(interactionsCountSet, interactionName); interactionsCountSet = result.interactionsCountSet; interactionId = result.interactionId; if (interactionId != -1) { let correctness = "correct"; const answerCorrect = that.attr("data-val"); const answerRange = that.attr("data-range"); const userAnswer = that.val(); const answer = that.val(); that.attr("data-userans", userAnswer); // walidacja odpowiedzi if (answerCorrect == userAnswer) { // wpisano dobrą odpowiedź correctness = "correct"; } else { if (answerRange !== undefined && Math.abs(answerCorrect - userAnswer) <= answerRange) { // wpisano niedokładną odpowiedź, ale mieszczącą się w dopuszczalnym zakresie błędu correctness = "correct"; } else { // wpisano złą odpowiedź correctness = "incorrect"; } } saveData(interactionId, answer, correctness); } } function doneTypingFillIn(that, interactionsCountSet) { let interactionId = -1; const header = that.parent().parent().parent().parent().parent().parent().find(".el-element-header-text") != undefined ? "header: " + that.parent().parent().parent().parent().parent().parent().find(".el-element-header-text").text() : ""; const interactionName = "type: fill-in " + header + " question: " + that.parent().find(".el-slide-content-header").text() + " sco: " + getScoName() + " (" + getScoId() + ")"; const result = prepare(interactionsCountSet, interactionName); interactionsCountSet = result.interactionsCountSet; interactionId = result.interactionId; if (interactionId != -1) { let correctness = "correct"; let answerCorrect = that.attr("data-val"); let userAnswer = that.val(); const answer = that.val(); // zastosuj małe litery answerCorrect = answerCorrect.toLowerCase(); userAnswer = userAnswer.toLowerCase(); // walidacja odpowiedzi const answerCorrectArr = answerCorrect.split(";"); let userAnswerWasCorrect = false; for (let i = 0; i < answerCorrectArr.length; i++) { if (answerCorrectArr[i] == userAnswer) { // wpisano dobrą odpowiedź userAnswerWasCorrect = true; break; } } // wpisano złą odpowiedź if (!userAnswerWasCorrect) { correctness = "incorrect"; } saveData(interactionId, answer, correctness); } return interactionsCountSet; } function getContentFrameReference() { if (document.getElementById('page-content-frame') != null) { contentFrameReference = document.getElementById('page-content-frame').contentWindow; } else { contentFrameReference = window; } } function getCourseWindowReference() { if (typeof window.parent.coursejson !== 'undefined') { courseWindowReference = window.parent; } else { courseWindowReference = window; } } /*function countInteractions() { const isPlainSCORM = courseWindowReference.getParsedCourseJson().scormPlain; const scosNumber = courseWindowReference.getParsedCourseJson().children.length; let numberOfInteractions = 0; for (let i = 1; i <= scosNumber; i++) { if (isPlainSCORM && i != getScoId()) { continue; } let currentSCOManifest = courseWindowReference.manifestDataCopy.structure['sco_' + i]; let interactions = currentSCOManifest.interactions; numberOfInteractions += interactions.length; for (let j = 0; j < interactions.length; j++) { let inter = interactions[j].id; if (interactiondIDList.indexOf(inter) == -1) { interactiondIDList.push(inter); } } } return numberOfInteractions; }*/ function countInteractionsFunction() { console.log("countInteractionsFunction"); let i = 0; let inter = contentFrameReference.doGetValue("cmi.interactions.0.id"); while (inter != "") { if (interactiondIDList.indexOf(inter) == -1) { interactiondIDList.push(inter); } i++; inter = contentFrameReference.doGetValue("cmi.interactions." + i + ".id"); } return i; } function initAllInteractionsForFillInNumeric(interactionsCount) { if ($(".eduexe-library-numeric-container form input").size() > 0) { const scoId = getScoId(); const scoTitle = getScoName(); $(".eduexe-library-numeric-container form input").each(function() { const header = $(this).parent().parent().parent().parent().parent().parent().find(".el-element-header-text") != undefined ? "header: " + $(this).parent().parent().parent().parent().parent().parent().find(".el-element-header-text").text() : ""; const interactionName = "type: fill-in numeric " + header + " question: " + $(this).parent().find(".el-slide-content-header").text() + " sco: " + getScoName() + " (" + getScoId() + ")"; initOtherInteraction( interactionsCount, interactionName, scoId, scoTitle, $(this).text(), "numeric" ); interactionsCount++; }); // contentFrameReference.doCommit(); allInteractionsForFillInNumericInitialized = true; } return interactionsCount; } function initAllInteractionsForFillIn(interactionsCount) { if ($(".eduexe-library-fillin-container form input").size() > 0) { const scoId = getScoId(); const scoTitle = getScoName(); $(".eduexe-library-fillin-container form input").each(function() { const header = $(this).parent().parent().parent().parent().parent().parent().find(".el-element-header-text") != undefined ? "header: " + $(this).parent().parent().parent().parent().parent().parent().find(".el-element-header-text").text() : ""; const interactionName = "type: fill-in " + header + " question: " + $(this).parent().find(".el-slide-content-header").text() + " sco: " + getScoName() + " (" + getScoId() + ")"; initOtherInteraction( interactionsCount, interactionName, scoId, scoTitle, $(this).text(), "fill-in" ); interactionsCount++; }); // contentFrameReference.doCommit(); allInteractionsForFillInInitialized = true; } return interactionsCount; } function initAllInteractionsForQuiz(interactionsCount) { if ($(".eduexe-library-quiz-container").size() > 0) { const scoId = getScoId(); const scoTitle = getScoName(); $(".eduexe-library-quiz-container").each(function() { const header = $(this).find(".el-element-header-text") != undefined ? "header: " + $(this).find(".el-element-header-text").text() : ""; const introduction = $(this).find("el-quiz-introduction") != undefined ? " introduction:" + $(this).find("el-quiz-introduction").text() : ""; const interactionName = "type: quiz " + header + introduction + " question:" + $(this).find(".el-quiz-question").text() + " sco: " + getScoName() + " (" + getScoId() + ")"; const type = $(this).find(".el-quiz").find(".el-checkbox").size() > 0 ? "multiple-choice" : "single-choice"; initOtherInteraction( interactionsCount, interactionName, scoId, scoTitle, $(this).text(), type ); interactionsCount++; }); // contentFrameReference.doCommit(); allInteractionsForQuizInitialized = true; } return interactionsCount; } function initAllInteractionsForDragAndDrop(interactionsCount) { if ($(".eduexe-library-draganddrop-container").size() > 0) { const scoId = getScoId(); const scoTitle = getScoName(); $(".eduexe-library-draganddrop-container").each(function() { const header = $(this).find(".el-element-header-text") != undefined ? "header: " + $(this).find(".el-element-header-text").text() : ""; const interactionName = "type: matching " + header + " sco: " + getScoName() + " (" + getScoId() + ")"; initOtherInteraction( interactionsCount, interactionName, scoId, scoTitle, $(this).text(), "matching" ); interactionsCount++; }); // contentFrameReference.doCommit(); allInteractionsForDragAndDropInitialized = true; } return interactionsCount; } function initAllInteractionsForLinks(interactionsCount) { if ($("a[target='popup']").size() > 0) { const scoId = getScoId(); const scoTitle = getScoName(); $("a[target='popup']").each(function() { const interactionName = $(this).text() + " url:" + $(this).attr("href") + " sco: " + getScoName() + " (" + getScoId() + ")"; initOtherInteraction( interactionsCount, interactionName, scoId, scoTitle, $(this).prop('outerHTML'), "other" ); interactionsCount++; }); // contentFrameReference.doCommit(); allInteractionsForLinksInitialized = true; } return interactionsCount; } function getCurrentInteractionId(interactionName) { return interactiondIDList.indexOf(btoa(encodeURIComponent(interactionName))); } function prepare(interactionsCountSet, interactionName) { let interactionsCount = 0; console.log("interactionsCountSet:" + interactionsCountSet); if (!interactionsCountSet) { getContentFrameReference(); getCourseWindowReference(); interactionsCount = countInteractionsFunction(); } else { interactionsCount = interactiondIDList.length; } interactionsCountSet = true; if (!allInteractionsForLinksInitialized) { interactionsCount = initAllInteractionsForLinks(interactionsCount); } if (!allInteractionsForQuizInitialized) { interactionsCount = initAllInteractionsForQuiz(interactionsCount); } if (!allInteractionsForFillInInitialized) { interactionsCount = initAllInteractionsForFillIn(interactionsCount); } if (!allInteractionsForFillInNumericInitialized) { interactionsCount = initAllInteractionsForFillInNumeric(interactionsCount); } if (!allInteractionsForDragAndDropInitialized) { interactionsCount = initAllInteractionsForDragAndDrop(interactionsCount); } let interactionId = null; if (interactionName != null) { interactionId = getCurrentInteractionId(interactionName); } const result = { interactionsCountSet: interactionsCountSet, interactionId: interactionId }; return result; } function getScoId() { return "sco_" + $("body").attr("data-sco-id").trim(); } function getScoName() { return $(".eduexe-sco-title").first().text().trim(); } function initOtherInteraction(interactionID, interactionName, scoId, scoTitle, content, type) { const interEncoded = btoa(encodeURIComponent(interactionName)); if (interactiondIDList.indexOf(interEncoded) == -1) { interactiondIDList.push(interEncoded); contentFrameReference.doSetValue('cmi.interactions.' + interactionID + '.id', interEncoded); contentFrameReference.doSetValue('cmi.interactions.' + interactionID + '.type', "other"); contentFrameReference.doSetValue('cmi.interactions.' + interactionID + '.timestamp', scoReadyTime); contentFrameReference.CMI.encodeAndSetValue('cmi.interactions.' + interactionID + '.description', content); contentFrameReference.doSetValue('cmi.interactions.' + interactionID + '.weighting', 0.0); contentFrameReference.doSetValue('cmi.interactions.' + interactionID + '.objectives.0.id', '0:learning_object'); const scoTitleSafe = btoa(encodeURIComponent(scoTitle)); contentFrameReference.doSetValue('cmi.interactions.' + interactionID + '.objectives.1.id', '1:' + scoTitleSafe); contentFrameReference.doSetValue('cmi.interactions.' + interactionID + '.objectives.2.id', '2:' + scoId); contentFrameReference.doSetValue('cmi.interactions.' + interactionID + '.objectives.3.id', '3:' + type); contentFrameReference.doSetValue('cmi.interactions.' + interactionID + '.objectives.4.id', '4:'); contentFrameReference.doSetValue('cmi.interactions.' + interactionID + '.objectives.5.id', '5:drawn'); contentFrameReference.doSetValue('cmi.interactions.' + interactionID + '.objectives.6.id', '6:'); contentFrameReference.doSetValue('cmi.interactions.' + interactionID + '.objectives.7.id', '7:'); contentFrameReference.doSetValue('cmi.interactions.' + interactionID + '.objectives.8.id', '8:'); contentFrameReference.doSetValue('cmi.interactions.' + interactionID + '.objectives.9.id', '9:'); contentFrameReference.doSetValue('cmi.interactions.' + interactionID + '.objectives.10.id', '10:'); } } function saveData(interactionId, answer, result) { updateLearnerResponse(interactionId, answer); updateResult(interactionId, result); saveInteractionChangeTime(interactionId, answer, result); saveTimeSpentInInteractions(interactionId); // contentFrameReference.doCommit(); } function saveInteractionLatency(interactionId) { const latencyFromCMI = contentFrameReference.doGetValue("cmi.interactions." + interactionId + ".latency"); if (latencyFromCMI == "") { const testStartTime = Date.parse(doGetValue("cmi.interactions." + interactionId + ".timestamp") + ".000Z"); const currentTime = contentFrameReference.getTimeAsTimestamp(); const lacencyTime = currentTime - testStartTime; const lacencyTimeSeconds = Math.round(lacencyTime / 1000); const latencyFormatted = "PT" + lacencyTimeSeconds + "S"; contentFrameReference.doSetValue('cmi.interactions.' + interactionId + '.latency', latencyFormatted); } } function updateNumberOfAnswerChanges(interactionId) { const dataOfObjectives8Raw = contentFrameReference.doGetValue("cmi.interactions." + interactionId + ".objectives.8.id"); let numberOfAnswerChanges = dataOfObjectives8Raw.substr(2); if (numberOfAnswerChanges == "") { contentFrameReference.doSetValue("cmi.interactions." + interactionId + ".objectives.8.id", "8:1"); } else { numberOfAnswerChanges = parseInt(numberOfAnswerChanges) + 1; contentFrameReference.doSetValue("cmi.interactions." + interactionId + ".objectives.8.id", "8:" + numberOfAnswerChanges.toString()); } } function updateLearnerResponse(interactionId, answer) { contentFrameReference.CMI.encodeAndSetValue('cmi.interactions.' + interactionId + '.learner_response', answer); } function updateResult(interactionId, result) { contentFrameReference.doSetValue('cmi.interactions.' + interactionId + '.result', result); } function saveInteractionChangeTime(interactionId, answer, result) { const dataOfObjectives9Raw = contentFrameReference.doGetValue("cmi.interactions." + interactionId + ".objectives.9.id"); const changesArrayStr = dataOfObjectives9Raw.substr(2); let changesArrayObj = []; if (changesArrayStr != "") { changesArrayObj = JSON.parse(contentFrameReference.CMI.eduexeDecodeText(changesArrayStr)); } if (answer.length > 0 && ((changesArrayObj.length > 0 && changesArrayObj[changesArrayObj.length - 1].answer != answer && answer != "clicked") || changesArrayObj.length == 0)) { changesArrayObj.push({ "time": contentFrameReference.getTimeAsTimestamp(), "answer": answer, "result": result }); saveInteractionLatency(interactionId); updateNumberOfAnswerChanges(interactionId); contentFrameReference.doSetValue("cmi.interactions." + interactionId + ".objectives.9.id", "9:" + contentFrameReference.CMI.eduexeEncodeText(JSON.stringify(changesArrayObj))); } } function saveTimeSpentInInteractions(interactionId) { const currentTime = Date.now(); const intStarted = contentFrameReference.doGetValue('cmi.interactions.' + interactionId + '.timestamp'); const intStartedDate = new Date(intStarted + '.000Z'); let timeSpent = currentTime - intStartedDate.getTime(); timeSpent = Math.round(timeSpent / 1000); let timeSpentPrevious = contentFrameReference.doGetValue('cmi.interactions.' + interactionId + '.objectives.10.id'); timeSpentPrevious = timeSpentPrevious.substr(3); if (timeSpentPrevious == "") { contentFrameReference.doSetValue('cmi.interactions.' + interactionId + '.objectives.10.id', "10:" + timeSpent.toString()); } else { timeSpent += parseInt(timeSpentPrevious); contentFrameReference.doSetValue('cmi.interactions.' + interactionId + '.objectives.10.id', "10:" + timeSpent.toString()); } } function getTimeAsStringShort() { const date = new Date(); return dateStr = date.toISOString().split(".")[0]; }