fix: ensure conditional loading of jQuery & Bootstrap

Enhanced global.js and script.js to conditionally load jQuery and Bootstrap only if they are not already present. This change improves loading efficiency and reduces redundant script execution.

Additionally, fixed a bug in renderer.php by removing duplicate Bootstrap loading, which also reduces external dependency.

A new .gitignore file was added to ignore backup files with a .bak extension, helping to keep the repository clean.

Ensured error logging only displays error messages for better clarity.
This commit is contained in:
Kumi 2024-08-05 12:10:33 +02:00
parent f61fc7b852
commit 33f55824d8
Signed by: kumi
GPG key ID: ECBCC9082395383F
4 changed files with 132 additions and 84 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
*.bak

View file

@ -11,7 +11,7 @@ class renderer extends plugin_renderer_base {
private static $modals_rendered = false; private static $modals_rendered = false;
public function render_activity($activity_id) { public function render_activity($activity_id) {
$script = "<script src='https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js' integrity='sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz' crossorigin='anonymous'></script><script data-activity-id='$activity_id' src='/mod/exp360/script.js'></script>"; $script = "<script data-activity-id='$activity_id' src='/mod/exp360/script.js'></>";
return $script; return $script;
} }

161
global.js
View file

@ -14,53 +14,77 @@ document.addEventListener("DOMContentLoaded", function () {
// Function to get URL parameters // Function to get URL parameters
function getUrlParameter(name) { function getUrlParameter(name) {
url = document.location.href; const url = document.location.href;
urlobj = new URL(url); const urlobj = new URL(url);
return urlobj.searchParams.get(name); return urlobj.searchParams.get(name);
} }
// Function to wait until a global variable is defined
function waitForGlobalVariable(variableName) {
return new Promise((resolve) => {
const checkVariable = setInterval(() => {
if (window[variableName]) {
clearInterval(checkVariable);
resolve();
}
}, 100);
});
}
// Check if the 'embed' parameter is set to '1' // Check if the 'embed' parameter is set to '1'
if (getUrlParameter("embed") === "1") { if (getUrlParameter("embed") === "1") {
// Apply custom CSS to hide Moodle interface elements // Apply custom CSS to hide Moodle interface elements
var style = document.createElement("style"); const style = document.createElement("style");
style.innerHTML = ` style.innerHTML = `
body.path-mod { body.path-mod {
#header, #footer, .breadcrumb, .navbar, .side-pre, .side-post, .drawer, .drawer-toggler, .footer-popover, .navigation { #header, #footer, .breadcrumb, .navbar, .side-pre, .side-post, .drawer, .drawer-toggler, .footer-popover, .navigation {
display: none !important; display: none !important;
} }
#region-main { #region-main {
margin: 0; margin: 0;
padding: 0; padding: 0;
} }
} }
`; `;
document.head.appendChild(style); document.head.appendChild(style);
loadScript( // Load jQuery if not already defined
"https://code.jquery.com/jquery-3.7.1.min.js", const jQueryPromise = window.jQuery
"sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=", ? Promise.resolve()
"anonymous" : loadScript(
) "https://code.jquery.com/jquery-3.7.1.min.js",
"sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=",
"anonymous"
).then(() => waitForGlobalVariable("$"));
jQueryPromise
.then(() => { .then(() => {
console.log("jQuery loaded successfully"); console.log("jQuery loaded successfully");
// Load Bootstrap after jQuery is loaded
return loadScript( // Load Bootstrap if not already defined
"https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js", const bootstrapPromise = window.bootstrap
"sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz", ? Promise.resolve()
"anonymous" : loadScript(
); "https://stackpath.bootstrapcdn.com/bootstrap/5.3.3/js/bootstrap.bundle.min.js",
"sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz",
"anonymous"
).then(() => waitForGlobalVariable("bootstrap"));
return bootstrapPromise;
}) })
.then(() => { .then(() => {
console.log("Bootstrap loaded successfully"); console.log("Bootstrap loaded successfully");
$(document).ready(function () {
$(".btn-secondary:contains('Back')").hide()
var embedded = getUrlParameter("embed"); $(document).ready(function () {
var inModal = getUrlParameter("modal"); $(".btn-secondary:contains('Back')").hide();
const embedded = getUrlParameter("embed");
const inModal = getUrlParameter("modal");
const page = getUrlParameter("page") ? getUrlParameter("page") : 0;
// Set required attribute on inputs associated with labels containing <i title="Required field"> // Set required attribute on inputs associated with labels containing <i title="Required field">
$('label:has(i[title="Required field"])').each(function () { $('label:has(i[title="Required field"])').each(function () {
var inputId = $(this).attr("for"); const inputId = $(this).attr("for");
$("#" + inputId).attr("required", "required"); $("#" + inputId).attr("required", "required");
}); });
@ -70,7 +94,14 @@ document.addEventListener("DOMContentLoaded", function () {
}); });
$("form").each(function () { $("form").each(function () {
var form = $(this); const form = $(this);
// Check if the form has a button where the text contains "Finish attempt"
let isLast = false;
const finishButton = form.find('input[type="submit"][value*="Finish attempt"]');
if (finishButton.length) {
isLast = true;
}
form.submit(function (event) { form.submit(function (event) {
event.preventDefault(); // Prevent the default form submission event.preventDefault(); // Prevent the default form submission
@ -82,10 +113,10 @@ document.addEventListener("DOMContentLoaded", function () {
} }
// Serialize the form data // Serialize the form data
var formData = form.serialize(); let formData = form.serialize();
// Add the submit button's data to formData // Add the submit button's data to formData
var submitButton = form.find( const submitButton = form.find(
'input[type="submit"][name="savevalues"]' 'input[type="submit"][name="savevalues"]'
); );
if (submitButton.length) { if (submitButton.length) {
@ -96,35 +127,57 @@ document.addEventListener("DOMContentLoaded", function () {
encodeURIComponent(submitButton.val()); encodeURIComponent(submitButton.val());
} }
var sesskey = form.find('input[name=sesskey]').val(); const sesskey = form.find('input[name=sesskey]').val();
var attempt = form.find('input[name=attempt]').val(); const attempt = form.find('input[name=attempt]').val();
console.log(sesskey);
console.log(attempt);
// Perform the AJAX request // Perform the AJAX request
$.ajax({ $.ajax({
url: form.attr("action"), // Use the form's action attribute url: form.attr("action"), // Use the form's action attribute
type: form.attr("method"), // Use the form's method attribute type: form.attr("method"), // Use the form's method attribute
data: formData, data: formData,
success: function (response) { success: function (response, status, xhr) {
if (form.attr("action").includes("/quiz/")) { if (form.attr("action").includes("/quiz/")) {
var finalize = "/mod/quiz/processattempt.php"; // Check if the quiz has a next page by calling the attempt.php page
var data = { let nextUrl = form.attr("action").replace("processattempt", "attempt");
attempt: attempt, nextUrl += "&page=" + (parseInt(page) + 1) + "&attempt=" + attempt + "&sesskey=" + sesskey;
finishattempt: 1,
sesskey: sesskey, if (isLast) {
}; nextUrl = "https://invalid.invalid";
$.post(finalize, data, function (response) { }
console.log(response);
// Close the modal if `modal=1` is set $.get(nextUrl, function (response) {
console.log(nextUrl + " seems to be a valid URL, redirecting...");
nextUrl = nextUrl + "&embed=1";
if (inModal === "1") { if (inModal === "1") {
window.top.closeQuizModal(); nextUrl += "&modal=1";
} else {
// Else call the nextContent function
window.top.nextContent();
} }
});
document.location.href = nextUrl;
return;
})
.fail(function () {
console.log("No next page found at " + nextUrl + ", finalizing attempt...");
const finalize = "/mod/quiz/processattempt.php";
const data = {
attempt: attempt,
finishattempt: 1,
sesskey: sesskey,
};
$.post(finalize, data, function (response) {
console.log(response);
// Close the modal if `modal=1` is set
if (inModal === "1") {
window.top.closeQuizModal();
} else {
// Else call the nextContent function
window.top.nextContent();
}
});
});
} else { } else {
// Close the modal if `modal=1` is set // Close the modal if `modal=1` is set
if (inModal === "1") { if (inModal === "1") {
@ -147,7 +200,7 @@ document.addEventListener("DOMContentLoaded", function () {
}); });
}) })
.catch((error) => { .catch((error) => {
console.error(error); console.error(error.message);
}); });
} }
}); });

View file

@ -29,32 +29,31 @@
var currentScript = document.currentScript; var currentScript = document.currentScript;
var myModal = document.getElementById("fullScreenModal"); function waitForGlobalVariable(variableName) {
return new Promise((resolve) => {
const checkVariable = setInterval(() => {
if (window[variableName]) {
clearInterval(checkVariable);
resolve();
}
}, 100);
});
}
myModal.addEventListener("shown.bs.modal", function () { waitForGlobalVariable("bootstrap")
const modalIframe = window.$("#modal-iframe");
modalIframe.css("width", "100%");
modalIframe.css("height", "100%");
modalIframe.css("border", "none");
});
loadScript(
"https://code.jquery.com/jquery-3.7.1.min.js",
"sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=",
"anonymous"
)
.then(() => {
console.log("jQuery loaded successfully");
window.$ = jQuery;
return loadScript(
"https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js",
"sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz",
"anonymous"
);
})
.then(() => { .then(() => {
console.log("Bootstrap loaded successfully"); console.log("Bootstrap loaded successfully");
var myModal = $("#fullScreenModal");
myModal[0].addEventListener("shown.bs.modal", function () {
const modalIframe = window.$("#modal-iframe");
modalIframe.css("width", "100%");
modalIframe.css("height", "100%");
modalIframe.css("border", "none");
});
var scriptId = "script-" + Math.random().toString(36).substring(2, 9); var scriptId = "script-" + Math.random().toString(36).substring(2, 9);
currentScript.id = scriptId; currentScript.id = scriptId;
@ -164,7 +163,6 @@
window.top.closeQuizModal = closeQuizModal; window.top.closeQuizModal = closeQuizModal;
window.top.goToQuiz = window.top.nextContent; window.top.goToQuiz = window.top.nextContent;
$(currentScript) $(currentScript)
.parent() .parent()
.append( .append(
@ -180,12 +178,8 @@
$(currentScript).closest("li.section").attr("id") $(currentScript).closest("li.section").attr("id")
); );
}); });
$("head").append(
'<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">'
);
}) })
.catch((error) => { .catch((error) => {
console.error(error); console.error(error.message);
}); });
})(); })();