v1.0.2
This commit is contained in:
@@ -1,5 +1,9 @@
|
||||
# CHANGELOG
|
||||
|
||||
## v1.0.2
|
||||
|
||||
- Added `mode`
|
||||
|
||||
## v1.0.1
|
||||
|
||||
- Removed langage
|
||||
|
||||
@@ -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,3 +2,5 @@
|
||||
|
||||
- [ ] Support multiple input type in a question
|
||||
- [ ] Support drag and drop quiz
|
||||
- [ ] Summary
|
||||
- [ ] Publish on chrome
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
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 |
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
@@ -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,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": {
|
||||
|
||||
@@ -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
@@ -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();
|
||||
});
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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"
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
Vendored
+1
@@ -10,6 +10,7 @@ type Config = {
|
||||
title?: boolean;
|
||||
table?: boolean;
|
||||
timeout?: boolean;
|
||||
mode?: "autocomplete" | "question-to-answer" | "clipboard";
|
||||
};
|
||||
|
||||
export default Config;
|
||||
|
||||
Reference in New Issue
Block a user