diff --git a/amd/build/spellcheck.min.js b/amd/build/spellcheck.min.js index cd1f8ea..f6c0d28 100644 --- a/amd/build/spellcheck.min.js +++ b/amd/build/spellcheck.min.js @@ -6,6 +6,6 @@ define("qtype_aitext/spellcheck",["exports","qtype_aitext/diff","core_form/modal * @copyright 2024, ISB Bayern * @author Dr. Peter Mayer * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */(Diff),_modalform=(obj=_modalform)&&obj.__esModule?obj:{default:obj};_exports.init=(cmid,readonlyareaselector,spellcheckeditbuttonselector)=>{renderDiff(readonlyareaselector),document.querySelector(spellcheckeditbuttonselector)&&document.querySelector(spellcheckeditbuttonselector).addEventListener("click",(async event=>{event.preventDefault(),await showModalForm(cmid,readonlyareaselector)}))};const renderDiff=readonlyareaselector=>{const studentanswer=document.querySelector(readonlyareaselector).innerHTML,spellcheck=document.querySelector(readonlyareaselector).dataset.spellcheck;let span=null;const diff=Diff.diffChars(studentanswer,spellcheck),fragment=document.createElement("div");let fullspellcheck="";diff.forEach((part=>{var cls=part.added?"qtype_aitext_spellcheck_new":part.removed?"qtype_aitext_spellcheck_wrong":"";part.added||part.removed?(span=document.createElement("span"),span.classList=cls,span.appendChild(document.createTextNode(part.value)),fullspellcheck+=span.outerHTML):fullspellcheck+=part.value})),fragment.innerHTML=fullspellcheck,document.querySelector(readonlyareaselector).replaceChildren(fragment)};_exports.renderDiff=renderDiff;const showModalForm=async(cmid,readonlyareaselector)=>{const attemptstepid=document.querySelector(readonlyareaselector).dataset.spellcheckattemptstepid,answerstepid=document.querySelector(readonlyareaselector).dataset.spellcheckattemptstepanswerid,title=await(0,_str.get_string)("spellcheckedit","qtype_aitext"),modalForm=new _modalform.default({formClass:"qtype_aitext\\form\\edit_spellchek",args:{attemptstepid:attemptstepid,answerstepid:answerstepid,cmid:cmid},modalConfig:{title:title}});modalForm.addEventListener(modalForm.events.FORM_SUBMITTED,reloadpage),await modalForm.show()};_exports.showModalForm=showModalForm;const reloadpage=()=>{location.reload()}})); + */(Diff),_modalform=(obj=_modalform)&&obj.__esModule?obj:{default:obj};_exports.init=(cmid,readonlyareaselector,spellcheckeditbuttonselector)=>{renderDiff(readonlyareaselector),document.querySelector(spellcheckeditbuttonselector)&&document.querySelector(spellcheckeditbuttonselector).addEventListener("click",(async event=>{event.preventDefault(),await showModalForm(cmid,readonlyareaselector)}))};const renderDiff=readonlyareaselector=>{const studentanswer=document.querySelector(readonlyareaselector).innerHTML,spellcheck=document.querySelector(readonlyareaselector).dataset.spellcheck;let span=null;const diff=Diff.diffChars(studentanswer,spellcheck),fragment=document.createElement("div");let fullspellcheck="";diff.forEach((part=>{part.value=part.value.replace(/ /g," ");const parser=new DOMParser;part.value=parser.parseFromString(part.value,"text/html");var cls=part.added?"qtype_aitext_spellcheck_new":part.removed?"qtype_aitext_spellcheck_wrong":"";part.added||part.removed?(span=document.createElement("span"),span.classList=cls,span.appendChild(part.value.documentElement),fullspellcheck+=span.outerHTML):fullspellcheck+=part.value.documentElement.textContent})),fragment.innerHTML=fullspellcheck,document.querySelector(readonlyareaselector).replaceChildren(fragment)};_exports.renderDiff=renderDiff;const showModalForm=async(cmid,readonlyareaselector)=>{const attemptstepid=document.querySelector(readonlyareaselector).dataset.spellcheckattemptstepid,answerstepid=document.querySelector(readonlyareaselector).dataset.spellcheckattemptstepanswerid,title=await(0,_str.get_string)("spellcheckedit","qtype_aitext"),modalForm=new _modalform.default({formClass:"qtype_aitext\\form\\edit_spellchek",args:{attemptstepid:attemptstepid,answerstepid:answerstepid,cmid:cmid},modalConfig:{title:title}});modalForm.addEventListener(modalForm.events.FORM_SUBMITTED,reloadpage),await modalForm.show()};_exports.showModalForm=showModalForm;const reloadpage=()=>{location.reload()}})); //# sourceMappingURL=spellcheck.min.js.map \ No newline at end of file diff --git a/amd/build/spellcheck.min.js.map b/amd/build/spellcheck.min.js.map index 1b3f5d5..9077c09 100644 --- a/amd/build/spellcheck.min.js.map +++ b/amd/build/spellcheck.min.js.map @@ -1 +1 @@ -{"version":3,"file":"spellcheck.min.js","sources":["../src/spellcheck.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Generates the spellcheck diff view.\n *\n * @module qtype_aitext/spellcheck\n * @copyright 2024, ISB Bayern\n * @author Dr. Peter Mayer\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport * as Diff from 'qtype_aitext/diff';\nimport ModalForm from 'core_form/modalform';\nimport {get_string as getString} from 'core/str';\n\n/**\n * Init the module.\n *\n * @param {int} cmid the course module id of the quiz.\n * @param {string} readonlyareaselector the selector for the readonly area to apply the spellchecking\n * @param {string} spellcheckeditbuttonselector the selector for the spell check edit button\n */\nexport const init = (cmid, readonlyareaselector, spellcheckeditbuttonselector) => {\n renderDiff(readonlyareaselector);\n\n if (!document.querySelector(spellcheckeditbuttonselector)) {\n return;\n }\n document.querySelector(spellcheckeditbuttonselector).addEventListener('click',\n async(event) => {\n event.preventDefault();\n await showModalForm(cmid, readonlyareaselector);\n });\n};\n\n/**\n * Render the spellcheckdiff.\n *\n * @param {string} readonlyareaselector The selector for the readonly area to apply the spell check diff to\n */\nexport const renderDiff = (readonlyareaselector) => {\n const studentanswer = document.querySelector(readonlyareaselector).innerHTML;\n const spellcheck = document.querySelector(readonlyareaselector).dataset.spellcheck;\n let span = null;\n\n const diff = Diff.diffChars(studentanswer, spellcheck);\n const fragment = document.createElement('div');\n\n let fullspellcheck = '';\n\n diff.forEach(part => {\n var cls = part.added ? 'qtype_aitext_spellcheck_new' :\n part.removed ? 'qtype_aitext_spellcheck_wrong' : '';\n if (part.added || part.removed) {\n span = document.createElement('span');\n span.classList = cls;\n span.appendChild(document.createTextNode(part.value));\n fullspellcheck += span.outerHTML;\n } else {\n fullspellcheck += part.value;\n }\n });\n\n fragment.innerHTML = fullspellcheck;\n document.querySelector(readonlyareaselector).replaceChildren(fragment);\n};\n\n/**\n * Show the dynamic spellcheck form.\n *\n * @param {int} cmid the course module id of the quiz\n * @param {string} readonlyareaselector the selector for the readonly area\n */\nexport const showModalForm = async(cmid, readonlyareaselector) => {\n const attemptstepid = document.querySelector(readonlyareaselector).dataset.spellcheckattemptstepid;\n const answerstepid = document.querySelector(readonlyareaselector).dataset.spellcheckattemptstepanswerid;\n const title = await getString('spellcheckedit', 'qtype_aitext');\n const modalForm = new ModalForm({\n formClass: \"qtype_aitext\\\\form\\\\edit_spellchek\",\n args: {\n attemptstepid,\n answerstepid,\n cmid\n },\n modalConfig: {title},\n });\n modalForm.addEventListener(modalForm.events.FORM_SUBMITTED, reloadpage);\n await modalForm.show();\n};\n\n/**\n * Reload the page. This is not nice, but easy :-)\n */\nconst reloadpage = () => {\n location.reload();\n};\n"],"names":["cmid","readonlyareaselector","spellcheckeditbuttonselector","renderDiff","document","querySelector","addEventListener","async","event","preventDefault","showModalForm","studentanswer","innerHTML","spellcheck","dataset","span","diff","Diff","diffChars","fragment","createElement","fullspellcheck","forEach","part","cls","added","removed","classList","appendChild","createTextNode","value","outerHTML","replaceChildren","attemptstepid","spellcheckattemptstepid","answerstepid","spellcheckattemptstepanswerid","title","modalForm","ModalForm","formClass","args","modalConfig","events","FORM_SUBMITTED","reloadpage","show","location","reload"],"mappings":";;;;;;;;wFAmCoB,CAACA,KAAMC,qBAAsBC,gCAC7CC,WAAWF,sBAENG,SAASC,cAAcH,+BAG5BE,SAASC,cAAcH,8BAA8BI,iBAAiB,SAClEC,MAAAA,QACIC,MAAMC,uBACAC,cAAcV,KAAMC,gCASzBE,WAAcF,6BACjBU,cAAgBP,SAASC,cAAcJ,sBAAsBW,UAC7DC,WAAaT,SAASC,cAAcJ,sBAAsBa,QAAQD,eACpEE,KAAO,WAELC,KAAOC,KAAKC,UAAUP,cAAeE,YACrCM,SAAWf,SAASgB,cAAc,WAEpCC,eAAiB,GAErBL,KAAKM,SAAQC,WACLC,IAAMD,KAAKE,MAAQ,8BACnBF,KAAKG,QAAU,gCAAkC,GACjDH,KAAKE,OAASF,KAAKG,SACnBX,KAAOX,SAASgB,cAAc,QAC9BL,KAAKY,UAAYH,IACjBT,KAAKa,YAAYxB,SAASyB,eAAeN,KAAKO,QAC9CT,gBAAkBN,KAAKgB,WAEvBV,gBAAkBE,KAAKO,SAI/BX,SAASP,UAAYS,eACrBjB,SAASC,cAAcJ,sBAAsB+B,gBAAgBb,gDASpDT,cAAgBH,MAAMP,KAAMC,8BAC/BgC,cAAgB7B,SAASC,cAAcJ,sBAAsBa,QAAQoB,wBACrEC,aAAe/B,SAASC,cAAcJ,sBAAsBa,QAAQsB,8BACpEC,YAAc,mBAAU,iBAAkB,gBAC1CC,UAAY,IAAIC,mBAAU,CAC5BC,UAAW,qCACXC,KAAM,CACFR,cAAAA,cACAE,aAAAA,aACAnC,KAAAA,MAEJ0C,YAAa,CAACL,MAAAA,SAElBC,UAAUhC,iBAAiBgC,UAAUK,OAAOC,eAAgBC,kBACtDP,UAAUQ,mDAMdD,WAAa,KACfE,SAASC"} \ No newline at end of file +{"version":3,"file":"spellcheck.min.js","sources":["../src/spellcheck.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Generates the spellcheck diff view.\n *\n * @module qtype_aitext/spellcheck\n * @copyright 2024, ISB Bayern\n * @author Dr. Peter Mayer\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport * as Diff from 'qtype_aitext/diff';\nimport ModalForm from 'core_form/modalform';\nimport {get_string as getString} from 'core/str';\n\n/**\n * Init the module.\n *\n * @param {int} cmid the course module id of the quiz.\n * @param {string} readonlyareaselector the selector for the readonly area to apply the spellchecking\n * @param {string} spellcheckeditbuttonselector the selector for the spell check edit button\n */\nexport const init = (cmid, readonlyareaselector, spellcheckeditbuttonselector) => {\n renderDiff(readonlyareaselector);\n\n if (!document.querySelector(spellcheckeditbuttonselector)) {\n return;\n }\n document.querySelector(spellcheckeditbuttonselector).addEventListener('click',\n async(event) => {\n event.preventDefault();\n await showModalForm(cmid, readonlyareaselector);\n });\n};\n\n/**\n * Render the spellcheckdiff.\n *\n * @param {string} readonlyareaselector The selector for the readonly area to apply the spell check diff to\n */\nexport const renderDiff = (readonlyareaselector) => {\n const studentanswer = document.querySelector(readonlyareaselector).innerHTML;\n const spellcheck = document.querySelector(readonlyareaselector).dataset.spellcheck;\n let span = null;\n\n const diff = Diff.diffChars(studentanswer, spellcheck);\n const fragment = document.createElement('div');\n\n let fullspellcheck = '';\n\n diff.forEach(part => {\n // We need to replace the whitespaces, because otherwise they will be removed by\n // calling parseFromString of the DOMParser.\n part.value = part.value.replace(/ /g, ' ');\n const parser = new DOMParser();\n part.value = parser.parseFromString(part.value, 'text/html');\n var cls = part.added ? 'qtype_aitext_spellcheck_new' :\n part.removed ? 'qtype_aitext_spellcheck_wrong' : '';\n if (part.added || part.removed) {\n span = document.createElement('span');\n span.classList = cls;\n span.appendChild(part.value.documentElement);\n fullspellcheck += span.outerHTML;\n } else {\n fullspellcheck += part.value.documentElement.textContent;\n }\n });\n\n fragment.innerHTML = fullspellcheck;\n document.querySelector(readonlyareaselector).replaceChildren(fragment);\n};\n\n/**\n * Show the dynamic spellcheck form.\n *\n * @param {int} cmid the course module id of the quiz\n * @param {string} readonlyareaselector the selector for the readonly area\n */\nexport const showModalForm = async(cmid, readonlyareaselector) => {\n const attemptstepid = document.querySelector(readonlyareaselector).dataset.spellcheckattemptstepid;\n const answerstepid = document.querySelector(readonlyareaselector).dataset.spellcheckattemptstepanswerid;\n const title = await getString('spellcheckedit', 'qtype_aitext');\n const modalForm = new ModalForm({\n formClass: \"qtype_aitext\\\\form\\\\edit_spellchek\",\n args: {\n attemptstepid,\n answerstepid,\n cmid\n },\n modalConfig: {title},\n });\n modalForm.addEventListener(modalForm.events.FORM_SUBMITTED, reloadpage);\n await modalForm.show();\n};\n\n/**\n * Reload the page. This is not nice, but easy :-)\n */\nconst reloadpage = () => {\n location.reload();\n};\n"],"names":["cmid","readonlyareaselector","spellcheckeditbuttonselector","renderDiff","document","querySelector","addEventListener","async","event","preventDefault","showModalForm","studentanswer","innerHTML","spellcheck","dataset","span","diff","Diff","diffChars","fragment","createElement","fullspellcheck","forEach","part","value","replace","parser","DOMParser","parseFromString","cls","added","removed","classList","appendChild","documentElement","outerHTML","textContent","replaceChildren","attemptstepid","spellcheckattemptstepid","answerstepid","spellcheckattemptstepanswerid","title","modalForm","ModalForm","formClass","args","modalConfig","events","FORM_SUBMITTED","reloadpage","show","location","reload"],"mappings":";;;;;;;;wFAmCoB,CAACA,KAAMC,qBAAsBC,gCAC7CC,WAAWF,sBAENG,SAASC,cAAcH,+BAG5BE,SAASC,cAAcH,8BAA8BI,iBAAiB,SAClEC,MAAAA,QACIC,MAAMC,uBACAC,cAAcV,KAAMC,gCASzBE,WAAcF,6BACjBU,cAAgBP,SAASC,cAAcJ,sBAAsBW,UAC7DC,WAAaT,SAASC,cAAcJ,sBAAsBa,QAAQD,eACpEE,KAAO,WAELC,KAAOC,KAAKC,UAAUP,cAAeE,YACrCM,SAAWf,SAASgB,cAAc,WAEpCC,eAAiB,GAErBL,KAAKM,SAAQC,OAGTA,KAAKC,MAAQD,KAAKC,MAAMC,QAAQ,KAAM,gBAChCC,OAAS,IAAIC,UACnBJ,KAAKC,MAAQE,OAAOE,gBAAgBL,KAAKC,MAAO,iBAC5CK,IAAMN,KAAKO,MAAQ,8BACnBP,KAAKQ,QAAU,gCAAkC,GACjDR,KAAKO,OAASP,KAAKQ,SACnBhB,KAAOX,SAASgB,cAAc,QAC9BL,KAAKiB,UAAYH,IACjBd,KAAKkB,YAAYV,KAAKC,MAAMU,iBAC5Bb,gBAAkBN,KAAKoB,WAEvBd,gBAAkBE,KAAKC,MAAMU,gBAAgBE,eAIrDjB,SAASP,UAAYS,eACrBjB,SAASC,cAAcJ,sBAAsBoC,gBAAgBlB,gDASpDT,cAAgBH,MAAMP,KAAMC,8BAC/BqC,cAAgBlC,SAASC,cAAcJ,sBAAsBa,QAAQyB,wBACrEC,aAAepC,SAASC,cAAcJ,sBAAsBa,QAAQ2B,8BACpEC,YAAc,mBAAU,iBAAkB,gBAC1CC,UAAY,IAAIC,mBAAU,CAC5BC,UAAW,qCACXC,KAAM,CACFR,cAAAA,cACAE,aAAAA,aACAxC,KAAAA,MAEJ+C,YAAa,CAACL,MAAAA,SAElBC,UAAUrC,iBAAiBqC,UAAUK,OAAOC,eAAgBC,kBACtDP,UAAUQ,mDAMdD,WAAa,KACfE,SAASC"} \ No newline at end of file diff --git a/amd/src/spellcheck.js b/amd/src/spellcheck.js index 32d8046..b4546b5 100644 --- a/amd/src/spellcheck.js +++ b/amd/src/spellcheck.js @@ -62,15 +62,20 @@ export const renderDiff = (readonlyareaselector) => { let fullspellcheck = ''; diff.forEach(part => { + // We need to replace the whitespaces, because otherwise they will be removed by + // calling parseFromString of the DOMParser. + part.value = part.value.replace(/ /g, ' '); + const parser = new DOMParser(); + part.value = parser.parseFromString(part.value, 'text/html'); var cls = part.added ? 'qtype_aitext_spellcheck_new' : part.removed ? 'qtype_aitext_spellcheck_wrong' : ''; if (part.added || part.removed) { span = document.createElement('span'); span.classList = cls; - span.appendChild(document.createTextNode(part.value)); + span.appendChild(part.value.documentElement); fullspellcheck += span.outerHTML; } else { - fullspellcheck += part.value; + fullspellcheck += part.value.documentElement.textContent; } }); diff --git a/renderer.php b/renderer.php index c8db606..4ebeac4 100755 --- a/renderer.php +++ b/renderer.php @@ -789,7 +789,7 @@ protected function prepare_response($name, question_attempt $qa, return ''; } - return format_text($step->get_qt_var($name), FORMAT_PLAIN); + return format_text($step->get_qt_var($name), $step->get_qt_var($name . 'format'), ['para' => false]); } }