Fixed bug and added atto handler

This commit is contained in:
yoannchb-pro
2024-05-05 14:00:47 -04:00
parent 3dcc6dc6eb
commit ac2ca56a54
8 changed files with 93 additions and 5 deletions
+1 -1
View File
@@ -58,7 +58,7 @@ function setUpMoodleGpt(config: Config) {
const inputTypeQuery = ['checkbox', 'radio', 'text', 'number'] const inputTypeQuery = ['checkbox', 'radio', 'text', 'number']
.map(e => `input[type="${e}"]`) .map(e => `input[type="${e}"]`)
.join(','); .join(',');
const inputQuery = inputTypeQuery + ', textarea, select, [contenteditable]'; const inputQuery = inputTypeQuery + ', textarea, select, [contenteditable], .qtype_essay_editor';
const forms = document.querySelectorAll('.formulation'); const forms = document.querySelectorAll('.formulation');
// For each form we inject a function on the queqtion // For each form we inject a function on the queqtion
+4
View File
@@ -16,6 +16,10 @@ function createAndNormalizeQuestion(questionContainer: HTMLElement) {
for (const useless of accesshideElements) { for (const useless of accesshideElements) {
question = question.replace(useless.innerText, ''); 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 // Make tables more readable for chat-gpt
const tables: NodeListOf<HTMLTableElement> = questionContainer.querySelectorAll('.qtext table'); const tables: NodeListOf<HTMLTableElement> = questionContainer.querySelectorAll('.qtext table');
+2
View File
@@ -7,6 +7,7 @@ import handleRadio from '@core/questions/radio';
import handleCheckbox from '@core/questions/checkbox'; import handleCheckbox from '@core/questions/checkbox';
import handleSelect from '@core/questions/select'; import handleSelect from '@core/questions/select';
import handleTextbox from '@core/questions/textbox'; import handleTextbox from '@core/questions/textbox';
import handleAtto from '@core/questions/atto';
type Props = { type Props = {
config: Config; config: Config;
@@ -26,6 +27,7 @@ function autoCompleteMode(props: Props) {
if (!props.config.infinite) props.removeListener(); if (!props.config.infinite) props.removeListener();
const handlers = [ const handlers = [
handleAtto,
handleContentEditable, handleContentEditable,
handleTextbox, handleTextbox,
handleNumber, handleNumber,
+67
View File
@@ -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;
+7 -2
View File
@@ -1,6 +1,11 @@
import type Config from '@typing/config'; import type Config from '@typing/config';
import type GPTAnswer from '@typing/gpt-answer'; 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 * Hanlde contenteditable elements
* @param config * @param config
@@ -17,7 +22,7 @@ function handleContentEditable(
if ( if (
inputList.length !== 1 || // for now we don't handle many input for editable textcontent inputList.length !== 1 || // for now we don't handle many input for editable textcontent
typeof input.getAttribute('contenteditable') !== 'string' !isContentEditable(input)
) { ) {
return false; return false;
} }
@@ -28,7 +33,7 @@ function handleContentEditable(
const eventHandler = function (event: KeyboardEvent) { const eventHandler = function (event: KeyboardEvent) {
event.preventDefault(); event.preventDefault();
if (event.key === 'Backspace' || index > gptAnswer.response.length) { if (event.key === 'Backspace' || index >= gptAnswer.response.length) {
input.removeEventListener('keydown', eventHandler); input.removeEventListener('keydown', eventHandler);
return; return;
} }
+1 -1
View File
@@ -31,7 +31,7 @@ function handleNumber(
const eventHanlder = function (event: Event) { const eventHanlder = function (event: Event) {
event.preventDefault(); event.preventDefault();
if ((<KeyboardEvent>event).key === 'Backspace' || index > number.length) { if ((<KeyboardEvent>event).key === 'Backspace' || index >= number.length) {
input.removeEventListener('keydown', eventHanlder); input.removeEventListener('keydown', eventHanlder);
return; return;
} }
+1 -1
View File
@@ -28,7 +28,7 @@ function handleTextbox(
const eventHandler = function (event: Event) { const eventHandler = function (event: Event) {
event.preventDefault(); event.preventDefault();
if ((<KeyboardEvent>event).key === 'Backspace' || index > gptAnswer.response.length) { if ((<KeyboardEvent>event).key === 'Backspace' || index >= gptAnswer.response.length) {
input.removeEventListener('keydown', eventHandler); input.removeEventListener('keydown', eventHandler);
return; return;
} }
+10
View File
@@ -104,6 +104,16 @@
</div> </div>
</section> </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 --> <!-- Select -->
<section class="formulation"> <section class="formulation">
<div class="qtext"> <div class="qtext">