Created
February 18, 2025 20:45
-
-
Save BlueFalconHD/0d146affd67f7f1d3aa79a5899016995 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name Quill.org Enhanced Interaction Script | |
// @namespace https://www.quill.org/ | |
// @version 1.5 | |
// @description Pressing Enter clicks "Next Question", "Submit", or "Recheck Work" buttons on quill.org. Adds a progress bar on completion and auto-focuses on input fields. | |
// @author | |
// @match *://*.quill.org/* | |
// @grant none | |
// ==/UserScript== | |
(function () { | |
'use strict'; | |
// Function to handle keydown events | |
function handleKeyDown(event) { | |
// Check if the Enter key is pressed without modifier keys | |
if (event.key === 'Enter' && !event.shiftKey && !event.ctrlKey && !event.altKey && !event.metaKey) { | |
// Prevent default action | |
event.preventDefault(); | |
// Find all button elements | |
const buttons = document.getElementsByTagName('button'); | |
// Function to find a button by text (case-insensitive) | |
function findButtonByText(text) { | |
text = text.toLowerCase(); | |
for (let button of buttons) { | |
if (button.innerText.trim().toLowerCase() === text) { | |
return button; | |
} | |
} | |
return null; | |
} | |
// Try to find the "Next Question" button first | |
let targetButton = findButtonByText('next question'); | |
// If "Next Question" button is not found, try to find the "Submit" button | |
if (!targetButton) { | |
targetButton = findButtonByText('submit'); | |
} | |
// If neither is found, try to find the "Recheck Work" button | |
if (!targetButton) { | |
targetButton = findButtonByText('recheck work'); | |
} | |
// If none are found, try to find the "Begin" button | |
if (!targetButton) { | |
targetButton = findButtonByText('begin'); | |
} | |
// Click the target button if found | |
if (targetButton) { | |
targetButton.click(); | |
focusFirstInputDelayed(); | |
} | |
} | |
} | |
// Function to auto-focus on the necessary input field after a delay | |
function focusFirstInputDelayed() { | |
setTimeout(function () { | |
// Try to focus on input elements with class 'fill-in-blank-input' or visible <input type="text"> | |
const inputElements = document.querySelectorAll('input.fill-in-blank-input, input[type="text"]:not([type="hidden"])'); | |
for (let input of inputElements) { | |
if (input.offsetParent !== null) { // Check if the input is visible | |
input.focus(); | |
return; // Stop after focusing the first visible input | |
} | |
} | |
// If no input found, fall back to 'div.input-field' | |
const firstInputField = document.querySelector('div.input-field'); | |
if (firstInputField) { | |
firstInputField.focus(); | |
} | |
}, 25); // Delay between 20-30ms | |
} | |
// Function to initialize the progress bar on activity completion | |
function initializeCompletionProgressBar() { | |
// Check for an <h1> element with the text "Activity Complete!" (case-insensitive) | |
const h1Elements = document.getElementsByTagName('h1'); | |
let activityCompleteHeader = null; | |
for (let h1 of h1Elements) { | |
if (h1.innerText.trim().toLowerCase() === 'activity complete!') { | |
activityCompleteHeader = h1; | |
break; | |
} | |
} | |
// If the "Activity Complete!" header exists | |
if (activityCompleteHeader) { | |
// Find the <a> element with the text "Return to Dashboard" (case-insensitive) | |
const aElements = document.getElementsByTagName('a'); | |
let returnToDashboardLink = null; | |
for (let a of aElements) { | |
if (a.innerText.trim().toLowerCase() === 'return to dashboard') { | |
returnToDashboardLink = a; | |
break; | |
} | |
} | |
// If the "Return to Dashboard" link is found | |
if (returnToDashboardLink) { | |
// Apply initial styling to the link | |
returnToDashboardLink.style.position = 'relative'; | |
returnToDashboardLink.style.display = 'inline-block'; | |
returnToDashboardLink.style.overflow = 'hidden'; | |
returnToDashboardLink.style.backgroundColor = '#06806b'; | |
returnToDashboardLink.style.color = 'white'; | |
// Create a progress bar overlay | |
const progressBar = document.createElement('div'); | |
progressBar.style.position = 'absolute'; | |
progressBar.style.top = '0'; | |
progressBar.style.left = '0'; | |
progressBar.style.height = '100%'; | |
progressBar.style.width = '0%'; | |
progressBar.style.backgroundColor = 'rgb(78, 165, 0)'; | |
progressBar.style.zIndex = '-1'; | |
progressBar.style.transition = 'width 1s linear'; | |
// Append the progress bar to the link | |
returnToDashboardLink.appendChild(progressBar); | |
// Force a reflow to ensure the progress bar is rendered before starting the animation | |
progressBar.offsetWidth; // eslint-disable-line no-unused-expressions | |
// Start the progress bar animation | |
requestAnimationFrame(function () { | |
progressBar.style.width = '100%'; | |
}); | |
// Redirect to the link's URL after 1 second | |
setTimeout(function () { | |
window.location.href = returnToDashboardLink.href; | |
}, 1000); | |
} | |
} | |
} | |
// Function to add click event listeners to buttons | |
function addButtonClickListeners() { | |
// Function to add the listener to a button if it exists | |
function addListenerToButton(text) { | |
const buttons = document.getElementsByTagName('button'); | |
for (let button of buttons) { | |
if (button.innerText.trim().toLowerCase() === text) { | |
button.addEventListener('click', function () { | |
focusFirstInputDelayed(); | |
}); | |
break; // Exit after adding listener to the first matched button | |
} | |
} | |
} | |
// Add listeners to the buttons | |
addListenerToButton('next question'); | |
addListenerToButton('submit'); | |
addListenerToButton('recheck work'); | |
addListenerToButton('begin'); | |
} | |
// Add event listeners | |
document.addEventListener('keydown', handleKeyDown); | |
// Run the completion progress bar initialization on page load | |
window.addEventListener('load', function () { | |
initializeCompletionProgressBar(); | |
addButtonClickListeners(); | |
}); | |
// Observe DOM mutations to handle dynamic content changes | |
const observer = new MutationObserver(function () { | |
addButtonClickListeners(); | |
}); | |
observer.observe(document.body, { childList: true, subtree: true }); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment