Skip to content

Commit

Permalink
Merge pull request #36 from yoannchb-pro/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
yoannchb-pro authored May 5, 2024
2 parents 292d00e + 8303dff commit ea57a31
Show file tree
Hide file tree
Showing 18 changed files with 160 additions and 30 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# CHANGELOG

## v1.1.1

- Bugs correction
- Support for Atto editor

## v1.1.0

- Bugs correction
Expand Down
11 changes: 8 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
href="https://www.flaticon.com/free-icons/mortarboard" target="_blank" rel="noopener noreferrer"
title="Mortarboard icons created by itim2101 - Flaticon" ><img src="./extension/icon.png" alt="Mortarboard icons created by itim2101 - Flaticon" width="150" style="display:block; margin:auto;"></a></p>

# MoodleGPT 1.1.0
# MoodleGPT 1.1.1

This extension allows you to hide CHAT-GPT in a Moodle quiz. You just need to click on the question you want to solve, and CHAT-GPT will automatically provide the answer. However, one needs to be careful because as we know, CHAT-GPT can make errors especially in calculations.

Expand All @@ -12,7 +12,7 @@ Find the extension on the Chrome Webstore right [here](https://chrome.google.com

## Summary

- [MoodleGPT 1.1.0](#moodlegpt-110)
- [MoodleGPT 1.1.1](#moodlegpt-111)
- [Chrome Webstore](#chrome-webstore)
- [Summary](#summary)
- [Disclaimer !](#disclaimer-)
Expand All @@ -32,6 +32,7 @@ Find the extension on the Chrome Webstore right [here](https://chrome.google.com
- [True or false](#true-or-false)
- [Number](#number)
- [Text](#text)
- [Atto](#atto)
- [What about if the question can't be autocompleted ?](#what-about-if-the-question-cant-be-autocompleted-)
- [Test](#test)
- [Beta version with advanced features](#beta-version-with-advanced-features)
Expand Down Expand Up @@ -145,6 +146,10 @@ Person 2 | Yann  | 19/01/2000 | no

![Text](./assets/text.gif)

### Atto

![Atto](./assets/atto.gif)

## What about if the question can't be autocompleted ?

To know if the answer has been copied to the clipboard, you can look at the title of the page which will become <b>"Copied to clipboard"</b> for 3 seconds if `Title indication` is on.
Expand All @@ -153,7 +158,7 @@ To know if the answer has been copied to the clipboard, you can look at the titl

## Test

- <b>Solution 1</b>: Go on [this moodle test page](https://school.moodledemo.net/login/index.php) (username: `student`, password: `moodle`) and choose any quiz.
- <b>Solution 1</b>: Go on this [moodle demo page](https://moodle.org/demo).
- <b>Solution 2</b>: Run the `index.html` file located in the `test/fake-moodle` folder.

## Beta version with advanced features
Expand Down
Binary file added assets/atto.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion extension/MoodleGPT.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion extension/MoodleGPT.js.map

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion extension/manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"manifest_version": 3,
"name": "MoodleGPT",
"version": "1.1.0",
"version": "1.1.1",
"description": "Hidden chat-gpt for your moodle quiz",
"permissions": ["storage"],
"action": {
Expand Down
4 changes: 2 additions & 2 deletions extension/popup/js/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ saveBtn.addEventListener('click', function () {
return;
}

if (code.length > 0 && code.length < 3) {
if (code.length > 0 && code.length < 2) {
showMessage({
msg: 'The code should at least contain 3 characters',
msg: 'The code should at least contain 2 characters',
error: true
});
return;
Expand Down
2 changes: 1 addition & 1 deletion extension/popup/js/version.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use strict';

const CURRENT_VERSION = '1.1.0';
const CURRENT_VERSION = '1.1.1';
const versionDisplay = document.querySelector('#version');

/**
Expand Down
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
{
"name": "moodlegpt",
"version": "1.1.0",
"version": "1.1.1",
"description": "This extension allows you to hide CHAT-GPT in a Moodle quiz.",
"scripts": {
"build": "npm run prettier && npm run lint && rollup -c",
"build": "npm run prettier && npm run lint && npm run fastBuild",
"fastBuild": "rollup -c",
"lint": "eslint . --ext .ts",
"prettier": "prettier --write ."
},
Expand Down
2 changes: 1 addition & 1 deletion src/core/code-listener.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ function setUpMoodleGpt(config: Config) {
const inputTypeQuery = ['checkbox', 'radio', 'text', 'number']
.map(e => `input[type="${e}"]`)
.join(',');
const inputQuery = inputTypeQuery + ', textarea, select, [contenteditable]';
const inputQuery = inputTypeQuery + ', textarea, select, [contenteditable], .qtype_essay_editor';
const forms = document.querySelectorAll('.formulation');

// For each form we inject a function on the queqtion
Expand Down
4 changes: 4 additions & 0 deletions src/core/create-question.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ function createAndNormalizeQuestion(questionContainer: HTMLElement) {
for (const useless of accesshideElements) {
question = question.replace(useless.innerText, '');
}
const attoText = questionContainer.querySelector('.qtype_essay_editor');
if (attoText) {
question = question.replace((attoText as HTMLElement).innerText, '');
}

// Make tables more readable for chat-gpt
const tables: NodeListOf<HTMLTableElement> = questionContainer.querySelectorAll('.qtext table');
Expand Down
2 changes: 2 additions & 0 deletions src/core/modes/autocomplete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import handleRadio from '@core/questions/radio';
import handleCheckbox from '@core/questions/checkbox';
import handleSelect from '@core/questions/select';
import handleTextbox from '@core/questions/textbox';
import handleAtto from '@core/questions/atto';

type Props = {
config: Config;
Expand All @@ -26,6 +27,7 @@ function autoCompleteMode(props: Props) {
if (!props.config.infinite) props.removeListener();

const handlers = [
handleAtto,
handleContentEditable,
handleTextbox,
handleNumber,
Expand Down
67 changes: 67 additions & 0 deletions src/core/questions/atto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import type Config from '@typing/config';
import type GPTAnswer from '@typing/gpt-answer';

/**
* Hanlde atto editor
* See: https://docs.moodle.org/404/en/Atto_editor#Atto_accessibility
* @param config
* @param inputList
* @param gptAnswer
* @returns
*/
function handleAtto(
config: Config,
inputList: NodeListOf<HTMLElement>,
gptAnswer: GPTAnswer
): boolean {
const input = inputList[0];

if (!input.classList.contains('qtype_essay_editor')) {
return false;
}

const iframe = input.querySelector('iframe');
if (!iframe || !iframe.contentDocument || !iframe.contentDocument.body || !iframe.contentWindow) {
return false;
}
const iframeBody = iframe.contentDocument.body;

const textContainer = iframeBody.querySelector('p');
if (!textContainer) return false;

if (config.typing) {
let index = 0;
const eventHandler = function (event: KeyboardEvent) {
event.preventDefault();

if (event.key === 'Backspace' || index >= gptAnswer.response.length) {
iframe.contentWindow!.removeEventListener('keydown', eventHandler);
return;
}

// Append text one character at a time
const textNode = document.createTextNode(gptAnswer.response.charAt(index++));
textContainer.appendChild(textNode);

// Move the cursor after the last character
const range = iframe.contentDocument!.createRange();
range.selectNodeContents(textContainer);
range.collapse(false); // Collapse the range to the end point
const selection = iframe.contentWindow!.getSelection();
if (selection) {
selection.removeAllRanges();
selection.addRange(range);
}

iframe.contentWindow!.focus(); // Focus the iframe window to see cursor
};

iframe.contentWindow.addEventListener('keydown', eventHandler);
} else {
textContainer.textContent += gptAnswer.response;
}

return true;
}

export default handleAtto;
20 changes: 16 additions & 4 deletions src/core/questions/checkbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,25 +26,37 @@ function handleCheckbox(

const possibleAnswers = Array.from(inputList)
.map(inp => ({
element: inp,
element: inp as HTMLInputElement,
value: normalizeText(inp?.parentElement?.textContent ?? '')
}))
.filter(obj => obj.value !== '');

// Find the best answers elements
const correctElements: Set<HTMLInputElement> = new Set();
for (const correct of corrects) {
const bestAnswer = pickBestReponse(correct, possibleAnswers);

if (config.logs && bestAnswer.value) {
Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);
}

const correctInput = bestAnswer.element as HTMLInputElement;
correctElements.add(bestAnswer.element as HTMLInputElement);
}

// Check if it should be checked or not
for (const element of possibleAnswers.map(e => e.element)) {
const needAction =
(element.checked && !correctElements.has(element)) ||
(!element.checked && correctElements.has(element));

const action = () => needAction && element.click();

if (config.mouseover) {
correctInput.addEventListener('mouseover', () => correctInput.click(), {
element.addEventListener('mouseover', action, {
once: true
});
} else {
correctInput.click();
action();
}
}

Expand Down
22 changes: 17 additions & 5 deletions src/core/questions/contenteditable.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import type Config from '@typing/config';
import type GPTAnswer from '@typing/gpt-answer';

function isContentEditable(element: HTMLElement) {
const contenteditable = element.getAttribute('contenteditable');
return typeof contenteditable === 'string' && contenteditable !== 'false';
}

/**
* Hanlde contenteditable elements
* @param config
Expand All @@ -17,17 +22,22 @@ function handleContentEditable(

if (
inputList.length !== 1 || // for now we don't handle many input for editable textcontent
input.getAttribute('contenteditable') !== 'true'
!isContentEditable(input)
) {
return false;
}

if (config.typing) {
let index = 0;
input.addEventListener('keydown', function (event: KeyboardEvent) {
if (event.key === 'Backspace') index = gptAnswer.response.length + 1;
if (index > gptAnswer.response.length) return;

const eventHandler = function (event: KeyboardEvent) {
event.preventDefault();

if (event.key === 'Backspace' || index >= gptAnswer.response.length) {
input.removeEventListener('keydown', eventHandler);
return;
}

input.textContent = gptAnswer.response.slice(0, ++index);

// Put the cursor at the end of the typed text
Expand All @@ -40,7 +50,9 @@ function handleContentEditable(
selection.removeAllRanges();
selection.addRange(range);
}
});
};

input.addEventListener('keydown', eventHandler);
} else {
input.textContent = gptAnswer.response;
}
Expand Down
15 changes: 11 additions & 4 deletions src/core/questions/number.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,20 @@ function handleNumber(

if (config.typing) {
let index = 0;
input.addEventListener('keydown', function (event: Event) {

const eventHanlder = function (event: Event) {
event.preventDefault();
if ((<KeyboardEvent>event).key === 'Backspace') index = number.length + 1;
if (index > number.length) return;
if ((<KeyboardEvent>event).key === 'Backspace' || index >= number.length) {
input.removeEventListener('keydown', eventHanlder);
return;
}

if (number.slice(index, index + 1) === '.') ++index;

input.value = number.slice(0, ++index);
});
};

input.addEventListener('keydown', eventHanlder);
} else {
input.value = number;
}
Expand Down
15 changes: 10 additions & 5 deletions src/core/questions/textbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,19 @@ function handleTextbox(

if (config.typing) {
let index = 0;
input.addEventListener('keydown', function (event: Event) {

const eventHandler = function (event: Event) {
event.preventDefault();
if ((<KeyboardEvent>event).key === 'Backspace') {
index = gptAnswer.response.length + 1;

if ((<KeyboardEvent>event).key === 'Backspace' || index >= gptAnswer.response.length) {
input.removeEventListener('keydown', eventHandler);
return;
}
if (index > gptAnswer.response.length) return;

input.value = gptAnswer.response.slice(0, ++index);
});
};

input.addEventListener('keydown', eventHandler);
} else {
input.value = gptAnswer.response;
}
Expand Down
10 changes: 10 additions & 0 deletions test/fake-moodle/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,16 @@
</div>
</section>

<!-- Textbox -->
<section class="formulation">
<div class="qtext">
<p>What is the name of the USA president ?</p>
</div>
<div>
<input type="text" />
</div>
</section>

<!-- Select -->
<section class="formulation">
<div class="qtext">
Expand Down

0 comments on commit ea57a31

Please sign in to comment.