Greasy Fork is available in English.
Khan Academy Answer Hack
// ==UserScript== // @name KhanHack // @version 3.9 // @description Here is a Khan Academy Solver! // @author Logzilla6 // @match https://www.khanacademy.org/* // @grant none // @namespace https://greasyfork.org/users/783447 // ==/UserScript==
(function () {
const overlayHTML =
<div id="hackOverlay" style="position: fixed; top: 10px; right: 10px; background: #fff; padding: 15px; border: 2px solid #000; z-index: 9999;">
<button id="toggleBtn">Toggle</button>
<h3>KhanHack</h3>
<button id="resetAnswersBtn">Reset Answer List</button>
<div id="ansBreak" style="max-height: 300px; overflow-y: auto;">
<h4>- Answers -</h4>
</div>
<small>Press 'M' to toggle menu visibility.</small>
</div>
;
// Utility function to get elements by ID
function get(x) { return document.getElementById(x); }
// Reset the list of answers
function resetAnswers() {
document.getElementById('ansBreak').innerHTML = ''; // Clear the answer list
curAns = 1; // Reset the answer counter
console.log('Answer list has been reset.');
}
// Error handling function
function handleFetchError(error) {
console.error('An error occurred:', error);
alert('An error occurred. Please check the console for details.');
}
// Add the overlay HTML to the page
let overlay = document.createElement("div");
overlay.innerHTML = overlayHTML;
document.body.appendChild(overlay);
// Toggle the visibility of the answer panel
let toggleBtn = get('toggleBtn');
let ansPanel = get('hackOverlay');
toggleBtn.onclick = function () {
ansPanel.style.display = ansPanel.style.display === 'none' ? 'block' : 'none';
};
// Toggle panel visibility when pressing 'M' key
document.addEventListener('keydown', (event) => {
if (event.key === 'm' || event.key === 'M') {
ansPanel.style.display = ansPanel.style.display === 'none' ? 'block' : 'none';
}
});
// Add the reset answers button functionality
let resetBtn = get('resetAnswersBtn');
resetBtn.onclick = resetAnswers;
'use strict';
window.loaded = false;
// Class to handle different types of answers
class Answer {
constructor(answer, type) {
this.body = answer;
this.type = type;
}
// Check if the answer is multiple choice
get isMultiChoice() {
return this.type === "multiple_choice";
}
// Check if the answer is free response
get isFreeResponse() {
return this.type === "free_response";
}
// Check if the answer is an expression
get isExpression() {
return this.type === "expression";
}
// Check if the answer is a dropdown
get isDropdown() {
return this.type === "dropdown";
}
log() {
try {
const answer = this.body;
answer.forEach(ans => {
if (typeof ans === "string") {
// Handle potential "web+graphie" strings by replacing them or processing
if (ans.includes("web+graphie")) {
this.body[this.body.indexOf(ans)] = ""; // Clear the value
this.printImage(ans); // You may need to define `printImage`
} else {
answer[answer.indexOf(ans)] = ans.replace(/\$/g, ''); // Replace '$' signs
}
}
});
} catch (error) {
handleFetchError(error);
}
}
}
const originalFetch = window.fetch;
// Overriding the window.fetch method
window.fetch = function () {
return originalFetch.apply(this, arguments).then(async (res) => {
try {
if (res.url.includes("/getAssessmentItem")) {
const clone = res.clone();
const json = await clone.json();
let item, question;
item = json.data.assessmentItem.item.itemData;
question = JSON.parse(item).question;
// Debugging: Log question structure
console.log('Question structure:', question);
Object.keys(question.widgets).forEach(widgetName => {
console.log('Processing widget:', widgetName); // Log widget name
switch (widgetName.split(" ")[0]) {
case "numeric-input":
freeResponseAnswerFrom(question).log();
break;
case "radio":
multipleChoiceAnswerFrom(question).log();
break;
case "expression":
expressionAnswerFrom(question).log();
break;
case "dropdown":
dropdownAnswerFrom(question).log();
break;
default:
console.warn('Unhandled widget type:', widgetName);
}
});
}
if (!window.loaded) {
console.clear();
window.loaded = true;
}
return res;
} catch (error) {
handleFetchError(error);
return res;
}
});
}
let curAns = 1;
// Extract free response answers from the question
function freeResponseAnswerFrom(question) {
const answer = Object.values(question.widgets).flatMap((widget) => {
if (widget.options?.answers) {
console.log('Free response widget:', widget); // Log widget data
return widget.options.answers
.filter(answer => answer.status === "correct")
.map(answer => {
let createPar = document.createElement('section');
createPar.innerHTML = answer.value;
document.getElementById('ansBreak').append(createPar);
curAns++;
return answer.value;
});
}
return [];
});
return new Answer(answer, "free_response");
}
// Extract multiple choice answers from the question
function multipleChoiceAnswerFrom(question) {
const answer = Object.values(question.widgets).flatMap((widget) => {
if (widget.options?.choices) {
console.log('Multiple choice widget:', widget); // Log widget data
return widget.options.choices
.filter(choice => choice.correct)
.map(choice => {
let createPar = document.createElement('section');
createPar.innerHTML = choice.content;
document.getElementById('ansBreak').append(createPar);
curAns++;
return choice.content;
});
}
return [];
});
return new Answer(answer, "multiple_choice");
}
// Extract expression answers from the question
function expressionAnswerFrom(question) {
const answer = Object.values(question.widgets).flatMap((widget) => {
if (widget.options?.answerForms) {
console.log('Expression widget:', widget); // Log widget data
return widget.options.answerForms
.filter(answer => Object.values(answer).includes("correct"))
.map(answer => {
let createPar = document.createElement('section');
createPar.innerHTML = answer.value;
document.getElementById('ansBreak').append(createPar);
curAns++;
return answer.value;
});
}
return [];
});
return new Answer(answer, "expression");
}
// Extract dropdown answers from the question
function dropdownAnswerFrom(question) {
const answer = Object.values(question.widgets).flatMap((widget) => {
if (widget.options?.choices) {
console.log('Dropdown widget:', widget); // Log widget data
return widget.options.choices
.filter(choice => choice.correct)
.map(choice => {
let createPar = document.createElement('section');
createPar.innerHTML = choice.content;
document.getElementById('ansBreak').append(createPar);
curAns++;
return choice.content;
});
}
return [];
});
return new Answer(answer, "dropdown");
}
})();
its me here uhmm i am working to fix the userscript so it shows it again but i need some more bugs to fix and others after i make this because im using chatgpt and some old userscripts so it may be buggy and im still in school so im going to make a project on this.