This commit is contained in:
yoannchb-pro
2023-06-12 22:36:34 -04:00
parent f581bc2788
commit 8292ae42a4
17 changed files with 216 additions and 30 deletions
+4
View File
@@ -1,5 +1,9 @@
# CHANGELOG
## v1.0.2
- Added `mode`
## v1.0.1
- Removed langage
+20 -2
View File
@@ -10,6 +10,10 @@ This extension allows you to hide CHAT-GPT in a Moodle quiz. You just need to en
I hereby declare that I am not responsible for any misuse or illegal activities carried out using my program. The code is provided for educational and research purposes only, and any use of it outside of these purposes is at the user's own risk.
## Support
Will be a pleasure if you want to supprot this project :). Just right [here](example.com)
## Update
See [changelog](./CHANGELOG.md)
@@ -22,6 +26,10 @@ If MoodleGPT cannot complete one of your moodle quiz please provide the html cod
> NOTE: This extension only works on Chromium-based browsers like Edge, Chrome, etc. Unfortunately, Firefox requires a click on the extension, which is not very discreet.
<p align="center">
<img src="./assets/setup.png" alt="Popup" width="300">
</p>
Go to <b>"Manage my extensions"</b> on your browser, then click on <b>"Load unpacked extension"</b> and select the <b>"extension"</b> folder. Afterwards, click on the extension icon and enter the apiKey obtained from [openai](https://platform.openai.com/) and enter a <b>code</b> that will activate the extension on your moodle page. Finally, click on the <b>reload button</b> next to model (it should give you the last ChatGPT version, otherwise enter it by your self) and click on the save button (The extension need to be configured before entering the moodle quiz).
## Inject the code into the moodle
@@ -32,10 +40,20 @@ You just need to enter on the keyboard the <b>code</b> you have set into the ext
Type back the <b>code</b> on the keyboard and the code will be removed from the current page.
## Options
## Mode
<p align="center">
<img src="./assets/popup.png" alt="Popup" height="300">
<img src="./assets/mode.png" alt="Popup" width="300">
</p>
- <b>Autocomplete:</b> The extension will complete the question for you.
- <b>Clipboard:</b> The response is copied into the clipboard.
- <b>Question to answer:</b> The question is converted to the answer and you can click on it to show back the question (or show back the answer).
## Settings
<p align="center">
<img src="./assets/settings.png" alt="Popup" width="300">
</p>
- <b>Api key</b>: the openai api key.
+2
View File
@@ -2,3 +2,5 @@
- [ ] Support multiple input type in a question
- [ ] Support drag and drop quiz
- [ ] Summary
- [ ] Publish on chrome
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

+16
View File
@@ -382,6 +382,21 @@
Logs.question(question);
Logs.response(response);
}
if (config.mode === "clipboard") {
return handleClipboard(config, response);
}
if (config.mode === "question-to-answer") {
const questionBackup = form.textContent;
const questionContainer = form.querySelector(".qtext");
questionContainer.textContent = response;
questionContainer.addEventListener("click", function () {
questionContainer.textContent =
questionContainer.textContent === questionBackup
? response
: questionBackup;
});
return;
}
const handlers = [
handleContentEditable,
handleTextbox,
@@ -393,6 +408,7 @@
if (handler(config, inputList, response))
return;
}
/** In the case we can't auto complete the question */
handleClipboard(config, response);
});
}
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1,7 +1,7 @@
{
"manifest_version": 3,
"name": "MoodleGPT",
"version": "1.0.1",
"version": "1.0.2",
"description": "Hidden chat-gpt for your moodle quiz",
"permissions": ["activeTab", "tabs", "storage"],
"action": {
+22 -1
View File
@@ -48,7 +48,28 @@
title="Provide an api key first"
></i>
</div>
<div class="line center" style="margin-top: 1rem">
<div class="line mt">
<i class="fa-solid fa-robot"></i>
<p>Mode:</p>
</div>
<div class="line">
<ul id="mode" class="line center">
<li><button value="autocomplete">autocomplete</button></li>
<li>
<button value="clipboard" class="not-selected">clipboard</button>
</li>
<li>
<button value="question-to-answer" class="not-selected">
question to answer
</button>
</li>
</ul>
</div>
<div class="line mt">
<i class="fa-solid fa-gear"></i>
<p>Settings:</p>
</div>
<div class="line center">
<div class="col">
<div class="line">
<input id="typing" type="checkbox" />
+87 -23
View File
@@ -1,6 +1,7 @@
const saveBtn = document.querySelector(".save");
const message = document.querySelector("#message");
/* inputs id */
const inputsText = ["apiKey", "code", "model"];
const inputsCheckbox = [
"logs",
@@ -13,6 +14,21 @@ const inputsCheckbox = [
"timeout",
];
const mode = document.querySelector("#mode");
const modes = mode.querySelectorAll("button");
let actualMode = "autocomplete";
/* inputs id that need to be disabled for a specific mode */
const disabledForThisMode = {
autocomplete: [],
clipboard: ["typing", "mouseover"],
"question-to-answer": ["typing", "infinite", "mouseover"],
};
/**
* Show message into the popup
* @param {string} messageTxt
* @param {boolean} valide
*/
function showMessage(messageTxt, valide) {
message.style.color = valide ? "limegreen" : "red";
message.textContent = messageTxt;
@@ -20,15 +36,48 @@ function showMessage(messageTxt, valide) {
setTimeout(() => (message.style.display = "none"), 5000);
}
//save the configuration
/**
* Handle when a mode change to show specific input
*/
function handleModeChange() {
const needDisable = disabledForThisMode[actualMode];
const dontNeedDisable = inputsCheckbox.filter(
(input) => !needDisable.includes(input)
);
for (const id of needDisable) {
document.querySelector("#" + id).parentElement.style.display = "none";
}
for (const id of dontNeedDisable) {
document.querySelector("#" + id).parentElement.style.display = null;
}
}
/* Mode handler */
modes.forEach((button) => {
button.addEventListener("click", function () {
const value = button.value;
actualMode = value;
for (const mode of modes) {
if (mode.value !== value) {
mode.classList.add("not-selected");
} else {
mode.classList.remove("not-selected");
}
}
handleModeChange();
});
});
/* Save the configuration */
saveBtn.addEventListener("click", function () {
const [apiKey, code, model] = inputsText.map((selector) =>
document.querySelector("#" + selector).value.trim()
);
const [logs, title, cursor, typing, mouseover, infinite, table, timeout] =
inputsCheckbox.map(
(selector) => document.querySelector("#" + selector).checked
);
inputsCheckbox.map((selector) => {
const element = document.querySelector("#" + selector);
return element.checked && element.parentElement.style.display !== "none";
});
if (!apiKey || !code || !model) {
showMessage("Please complete all the form");
@@ -53,31 +102,16 @@ saveBtn.addEventListener("click", function () {
infinite,
table,
timeout,
mode: actualMode,
},
});
showMessage("Configuration saved", true);
});
//we load back the configuration
chrome.storage.sync.get(["moodleGPT"]).then(function (storage) {
const config = storage.moodleGPT;
if (config) {
inputsText.forEach((key) =>
config[key]
? (document.querySelector("#" + key).value = config[key])
: null
);
inputsCheckbox.forEach(
(key) => (document.querySelector("#" + key).checked = config[key] || "")
);
}
getLastChatGPTVersion();
});
//getting the last chatgpt version
/**
* Get the last ChatGPT version
*/
function getLastChatGPTVersion() {
const apiKeySelector = document.querySelector("#apiKey");
const reloadModel = document.querySelector("#reloadModel");
@@ -119,3 +153,33 @@ function getLastChatGPTVersion() {
}
});
}
/* we load back the configuration */
chrome.storage.sync.get(["moodleGPT"]).then(function (storage) {
const config = storage.moodleGPT;
if (config) {
if (config.mode) {
actualMode = config.mode;
for (const mode of modes) {
if (mode.value === config.mode) {
mode.classList.remove("not-selected");
} else {
mode.classList.add("not-selected");
}
}
}
inputsText.forEach((key) =>
config[key]
? (document.querySelector("#" + key).value = config[key])
: null
);
inputsCheckbox.forEach(
(key) => (document.querySelector("#" + key).checked = config[key] || "")
);
}
handleModeChange();
getLastChatGPTVersion();
});
+14 -1
View File
@@ -1,6 +1,10 @@
const currentVersion = "1.0.1";
const currentVersion = "1.0.2";
const versionDisplay = document.querySelector("#version");
/**
* Get the last version from the github
* @returns
*/
async function getLastVersion() {
const req = await fetch(
"https://raw.githubusercontent.com/yoannchb-pro/MoodleGPT/main/package.json"
@@ -9,6 +13,12 @@ async function getLastVersion() {
return rep.version;
}
/**
* Display the version or an update message
* @param {string} version
* @param {boolean} isCurrent
* @returns
*/
function setVersion(version, isCurrent = true) {
if (isCurrent) {
versionDisplay.textContent = "v" + version;
@@ -24,6 +34,9 @@ function setVersion(version, isCurrent = true) {
versionDisplay.appendChild(document.createTextNode(" is now available !"));
}
/**
* Check the extension neeed an update or no
*/
async function notifyUpdate() {
const lastVersion = await getLastVersion().catch((err) => {
console.error(err);
+29
View File
@@ -52,6 +52,7 @@ a {
.line {
display: flex;
flex-direction: row;
width: 100%;
gap: 0.5rem;
}
@@ -98,6 +99,34 @@ a {
margin-bottom: 0.75rem;
}
.mt {
margin-top: 1rem;
}
.not-selected {
opacity: 0.4;
}
#mode li {
list-style: none;
flex-grow: 1;
}
#mode {
flex-wrap: wrap;
}
#mode button {
background-color: var(--btn-color);
border: none;
text-align: center;
padding: 0.3rem 0.75rem;
cursor: pointer;
width: 100%;
border-radius: 0.5rem;
text-transform: uppercase;
}
#version {
font-size: 0.75rem;
}
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "moodlegpt",
"version": "1.0.1",
"version": "1.0.2",
"description": "This extension allows you to hide CHAT-GPT in a Moodle quiz.",
"scripts": {
"build": "rollup -c"
+18
View File
@@ -49,6 +49,23 @@ async function reply(
Logs.response(response);
}
if (config.mode === "clipboard") {
return handleClipboard(config, response);
}
if (config.mode === "question-to-answer") {
const questionBackup = form.textContent;
const questionContainer = form.querySelector(".qtext");
questionContainer.textContent = response;
questionContainer.addEventListener("click", function () {
questionContainer.textContent =
questionContainer.textContent === questionBackup
? response
: questionBackup;
});
return;
}
const handlers = [
handleContentEditable,
handleTextbox,
@@ -61,6 +78,7 @@ async function reply(
if (handler(config, inputList, response)) return;
}
/** In the case we can't auto complete the question */
handleClipboard(config, response);
}
+1
View File
@@ -10,6 +10,7 @@ type Config = {
title?: boolean;
table?: boolean;
timeout?: boolean;
mode?: "autocomplete" | "question-to-answer" | "clipboard";
};
export default Config;