diff --git a/src/core/code-listener.ts b/src/core/code-listener.ts index 688a7ac..5d13218 100644 --- a/src/core/code-listener.ts +++ b/src/core/code-listener.ts @@ -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 diff --git a/src/core/create-question.ts b/src/core/create-question.ts index a765410..42e3f3e 100644 --- a/src/core/create-question.ts +++ b/src/core/create-question.ts @@ -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 = questionContainer.querySelectorAll('.qtext table'); diff --git a/src/core/modes/autocomplete.ts b/src/core/modes/autocomplete.ts index 5f8f9a2..5e93340 100644 --- a/src/core/modes/autocomplete.ts +++ b/src/core/modes/autocomplete.ts @@ -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; @@ -26,6 +27,7 @@ function autoCompleteMode(props: Props) { if (!props.config.infinite) props.removeListener(); const handlers = [ + handleAtto, handleContentEditable, handleTextbox, handleNumber, diff --git a/src/core/questions/atto.ts b/src/core/questions/atto.ts new file mode 100644 index 0000000..de71aea --- /dev/null +++ b/src/core/questions/atto.ts @@ -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, + 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; diff --git a/src/core/questions/contenteditable.ts b/src/core/questions/contenteditable.ts index 609677d..14ca160 100644 --- a/src/core/questions/contenteditable.ts +++ b/src/core/questions/contenteditable.ts @@ -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 @@ -17,7 +22,7 @@ function handleContentEditable( if ( inputList.length !== 1 || // for now we don't handle many input for editable textcontent - typeof input.getAttribute('contenteditable') !== 'string' + !isContentEditable(input) ) { return false; } @@ -28,7 +33,7 @@ function handleContentEditable( const eventHandler = function (event: KeyboardEvent) { event.preventDefault(); - if (event.key === 'Backspace' || index > gptAnswer.response.length) { + if (event.key === 'Backspace' || index >= gptAnswer.response.length) { input.removeEventListener('keydown', eventHandler); return; } diff --git a/src/core/questions/number.ts b/src/core/questions/number.ts index 4dfe9d9..251c3b3 100644 --- a/src/core/questions/number.ts +++ b/src/core/questions/number.ts @@ -31,7 +31,7 @@ function handleNumber( const eventHanlder = function (event: Event) { event.preventDefault(); - if ((event).key === 'Backspace' || index > number.length) { + if ((event).key === 'Backspace' || index >= number.length) { input.removeEventListener('keydown', eventHanlder); return; } diff --git a/src/core/questions/textbox.ts b/src/core/questions/textbox.ts index afb419c..846d3d7 100644 --- a/src/core/questions/textbox.ts +++ b/src/core/questions/textbox.ts @@ -28,7 +28,7 @@ function handleTextbox( const eventHandler = function (event: Event) { event.preventDefault(); - if ((event).key === 'Backspace' || index > gptAnswer.response.length) { + if ((event).key === 'Backspace' || index >= gptAnswer.response.length) { input.removeEventListener('keydown', eventHandler); return; } diff --git a/test/fake-moodle/index.html b/test/fake-moodle/index.html index 6053122..44fb601 100644 --- a/test/fake-moodle/index.html +++ b/test/fake-moodle/index.html @@ -104,6 +104,16 @@ + +
+
+

What is the name of the USA president ?

+
+
+ +
+
+