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:
parent
f61fc7b852
commit
33f55824d8
4 changed files with 132 additions and 84 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
*.bak
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
105
global.js
105
global.js
|
@ -14,15 +14,27 @@ 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 {
|
||||||
|
@ -36,31 +48,43 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||||
`;
|
`;
|
||||||
document.head.appendChild(style);
|
document.head.appendChild(style);
|
||||||
|
|
||||||
loadScript(
|
// Load jQuery if not already defined
|
||||||
|
const jQueryPromise = window.jQuery
|
||||||
|
? Promise.resolve()
|
||||||
|
: loadScript(
|
||||||
"https://code.jquery.com/jquery-3.7.1.min.js",
|
"https://code.jquery.com/jquery-3.7.1.min.js",
|
||||||
"sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=",
|
"sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=",
|
||||||
"anonymous"
|
"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
|
||||||
|
? Promise.resolve()
|
||||||
|
: loadScript(
|
||||||
|
"https://stackpath.bootstrapcdn.com/bootstrap/5.3.3/js/bootstrap.bundle.min.js",
|
||||||
"sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz",
|
"sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz",
|
||||||
"anonymous"
|
"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,21 +127,41 @@ 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");
|
||||||
|
nextUrl += "&page=" + (parseInt(page) + 1) + "&attempt=" + attempt + "&sesskey=" + sesskey;
|
||||||
|
|
||||||
|
if (isLast) {
|
||||||
|
nextUrl = "https://invalid.invalid";
|
||||||
|
}
|
||||||
|
|
||||||
|
$.get(nextUrl, function (response) {
|
||||||
|
console.log(nextUrl + " seems to be a valid URL, redirecting...");
|
||||||
|
nextUrl = nextUrl + "&embed=1";
|
||||||
|
|
||||||
|
if (inModal === "1") {
|
||||||
|
nextUrl += "&modal=1";
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
attempt: attempt,
|
||||||
finishattempt: 1,
|
finishattempt: 1,
|
||||||
sesskey: sesskey,
|
sesskey: sesskey,
|
||||||
|
@ -125,6 +176,8 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||||
window.top.nextContent();
|
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);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
42
script.js
42
script.js
|
@ -29,9 +29,24 @@
|
||||||
|
|
||||||
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")
|
||||||
|
.then(() => {
|
||||||
|
console.log("Bootstrap loaded successfully");
|
||||||
|
|
||||||
|
var myModal = $("#fullScreenModal");
|
||||||
|
|
||||||
|
myModal[0].addEventListener("shown.bs.modal", function () {
|
||||||
const modalIframe = window.$("#modal-iframe");
|
const modalIframe = window.$("#modal-iframe");
|
||||||
|
|
||||||
modalIframe.css("width", "100%");
|
modalIframe.css("width", "100%");
|
||||||
|
@ -39,22 +54,6 @@
|
||||||
modalIframe.css("border", "none");
|
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(() => {
|
|
||||||
console.log("Bootstrap loaded successfully");
|
|
||||||
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);
|
||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
|
|
Loading…
Reference in a new issue