From a7368163bfaafbd16c9ba8e9b6cfdbdacbaab979 Mon Sep 17 00:00:00 2001 From: Kumi Date: Tue, 2 Jul 2024 16:20:55 +0200 Subject: [PATCH] feat: add scripts for dynamic content loading and embedding Introduce global.js to streamline script loading and URL parameter parsing, enabling conditional embedding of Moodle elements. When the `embed` parameter is set to `1`, specific interface elements are hidden, and necessary scripts (jQuery and Bootstrap) are loaded to enhance form interactions and AJAX handling. Add script.js to handle dynamic content presentation within a modal. This includes script loading, modal management, and transition between content items, ensuring seamless navigation and adherence to required fields. Fosters a clean, embedded viewing experience and improves content presentation and interaction. --- global.js | 123 +++++++++++++++++++++++++++++++++++++++++ script.js | 162 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 285 insertions(+) create mode 100644 global.js create mode 100644 script.js diff --git a/global.js b/global.js new file mode 100644 index 0000000..40c020f --- /dev/null +++ b/global.js @@ -0,0 +1,123 @@ +document.addEventListener("DOMContentLoaded", function () { + // Function to load a script into the DOM + function loadScript(url, integrity, crossorigin) { + return new Promise((resolve, reject) => { + const script = document.createElement("script"); + script.src = url; + script.integrity = integrity; + script.crossOrigin = crossorigin; + script.onload = () => resolve(script); + script.onerror = () => reject(new Error(`Failed to load script: ${url}`)); + document.head.appendChild(script); + }); + } + + // Function to get URL parameters + function getUrlParameter(name) { + name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]"); + var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"); + var results = regex.exec(location.search); + return results === null + ? "" + : decodeURIComponent(results[1].replace(/\+/g, " ")); + } + + // Check if the 'embed' parameter is set to '1' + if (getUrlParameter("embed") === "1") { + // Apply custom CSS to hide Moodle interface elements + var style = document.createElement("style"); + style.innerHTML = ` + body.path-mod { + #header, #footer, .breadcrumb, .navbar, .side-pre, .side-post, .drawer, .drawer-toggler, .footer-popover, .navigation { + display: none !important; + } + #region-main { + margin: 0; + padding: 0; + } + } + `; + document.head.appendChild(style); + + loadScript( + "https://code.jquery.com/jquery-3.7.1.min.js", + "sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=", + "anonymous" + ) + .then(() => { + console.log("jQuery loaded successfully"); + // Load Bootstrap after jQuery is loaded + 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"); + $(document).ready(function () { + // Set required attribute on inputs associated with labels containing + $('label:has(i[title="Required field"])').each(function () { + var inputId = $(this).attr("for"); + $("#" + inputId).attr("required", "required"); + }); + + // Hide the modal if the 'cancel' button is clicked + $("[name=cancel]").click(function () { + hideContent(); + }); + + $("form").each(function () { + var form = $(this); + + form.submit(function (event) { + event.preventDefault(); // Prevent the default form submission + + // Check if the form is valid + if (!form[0].checkValidity()) { + form[0].reportValidity(); + return; + } + + // Serialize the form data + var formData = form.serialize(); + + // Add the submit button's data to formData + var submitButton = form.find( + 'input[type="submit"][name="savevalues"]' + ); + if (submitButton.length) { + formData += + "&" + + encodeURIComponent(submitButton.attr("name")) + + "=" + + encodeURIComponent(submitButton.val()); + } + + console.log(formData); + + // Perform the AJAX request + $.ajax({ + url: form.attr("action"), // Use the form's action attribute + type: form.attr("method"), // Use the form's method attribute + data: formData, + success: function (response) { + // Call the nextContent function upon successful submission + window.top.nextContent(); + }, + error: function (xhr, status, error) { + // Handle any errors that occur during the AJAX request + console.error( + "Form submission failed: " + status + " - " + error + ); + }, + }); + }); + }); + }); + }) + .catch((error) => { + console.error(error); + }); + } +}); diff --git a/script.js b/script.js new file mode 100644 index 0000000..4250b55 --- /dev/null +++ b/script.js @@ -0,0 +1,162 @@ +function loadScript(url, integrity, crossorigin) { + return new Promise((resolve, reject) => { + const script = document.createElement("script"); + script.src = url; + script.integrity = integrity; + script.crossOrigin = crossorigin; + script.onload = () => resolve(script); + script.onerror = () => reject(new Error(`Failed to load script: ${url}`)); + document.head.appendChild(script); + }); +} + +function getFeedbackLinks() { + // Select all elements with the class "stretched-link" + const links = document.querySelectorAll("a.stretched-link"); + + // Initialize an array to store the href attributes + const feedbackLinks = []; + + // Iterate through the selected links + links.forEach((link) => { + const href = link.getAttribute("href"); + // Check if the href includes "/feedback/" + if (href && href.includes("/feedback/")) { + feedbackLinks.push(href); + } + }); + + // Return the 1-indexed list of href attributes + return feedbackLinks.map((href, index) => ({ index: index + 1, href })); +} + +var currentScript = document.currentScript; + +var myModal = document.getElementById("fullScreenModal"); + +myModal.addEventListener("shown.bs.modal", function () { + var modalContent = myModal.querySelector(".modal-content"); + var modalWidth = modalContent.offsetWidth; + var modalHeight = modalContent.offsetHeight; + + 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(() => { + console.log("Bootstrap loaded successfully"); + var scriptId = "script-" + Math.random().toString(36).substring(2, 9); + currentScript.id = scriptId; + + contentUrl = $(currentScript).attr("data-content-url"); + + function openInModal(url, block) { + $("#modal-iframe").attr("src", url); + if (block) { + $("#fullScreenModal").attr("data-block", block); + } else { + $("#fullScreenModal").removeAttr("data-block"); + } + } + + function showContent(url, block) { + bootstrap.Modal.getOrCreateInstance( + document.getElementById("fullScreenModal") + ).show(); + if (url) { + openInModal(url, block); + } + } + + function hideContent() { + bootstrap.Modal.getOrCreateInstance( + document.getElementById("fullScreenModal") + ).hide(); + openInModal("about:blank"); + } + + function nextContent() { + // Get the currently executing