Fixed bug and added atto handler
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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');
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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;
|
||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|||||||
Reference in New Issue
Block a user