diff --git a/amd/build/append_pdfannotator.min.js b/amd/build/append_pdfannotator.min.js new file mode 100644 index 00000000..c1578298 --- /dev/null +++ b/amd/build/append_pdfannotator.min.js @@ -0,0 +1,10 @@ +define("tiny_cursive/append_pdfannotator",["exports","core/ajax","tiny_cursive/analytic_button","tiny_cursive/replay_button","tiny_cursive/analytic_events","core/templates","tiny_cursive/replay"],(function(_exports,_ajax,_analytic_button,_replay_button,_analytic_events,_templates,_replay){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}} +/** + * Module for handling PDF annotator functionality, + * + * @module tiny_cursive/append_pdfannotator + * @copyright 2025 Cursive Technology, Inc. + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_analytic_button=_interopRequireDefault(_analytic_button),_replay_button=_interopRequireDefault(_replay_button),_analytic_events=_interopRequireDefault(_analytic_events),_templates=_interopRequireDefault(_templates),_replay=_interopRequireDefault(_replay);_exports.init=(scoreSetting,comments,hasApiKey,userid)=>{const replayInstances={};window.video_playback=function(mid,filepath){if(""!==filepath){const replay=new _replay.default("content"+mid,filepath,10,!1,"player_"+mid);replayInstances[mid]=replay}else _templates.default.render("tiny_cursive/no_submission").then((html=>(document.getElementById("content"+mid).innerHTML=html,!0))).catch((e=>window.console.error(e)));return!1};let container=document.querySelector(".comment-list-container");const overviewTable=document.querySelector('table[id^="mod-pdfannotator-"]');document.addEventListener("click",(function(e){"commentSubmit"===e.target.id&&(localStorage.removeItem("isEditing"),buttonElement=e.target.value,pendingSubmit=!0);"commentCancel"===e.target.id&&(localStorage.removeItem("isEditing"),pendingSubmit=!1)}));const moduleName=document.body.id.split("-")[2];var pendingSubmit=!1,buttonElement="";if(container){new MutationObserver((()=>{var _container$lastChild;null!=container&&null!==(_container$lastChild=container.lastChild)&&void 0!==_container$lastChild&&_container$lastChild.id&&function(id){if("Save"===buttonElement)return void(pendingSubmit=!1);let resourceId=parseInt(null==id?void 0:id.split("_")[1]);if(resourceId&&pendingSubmit){pendingSubmit=!1,(async(methodname,args)=>{try{await(0,_ajax.call)([{methodname:methodname,args:args}])[0]}catch(error){throw window.console.error("updating Entries:",error),error}})("cursive_update_pdf_annote_id",{cmid:M.cfg.contextInstanceId,userid:M.cfg.userId??0,courseid:M.cfg.courseId,modulename:moduleName,resourceid:resourceId})}}(container.lastChild.id)})).observe(container,{subtree:!0,childList:!0})}if(overviewTable){let newChild=document.createElement("th");newChild.textContent="Analytics",overviewTable.querySelector("thead>tr>th:first-child").insertAdjacentElement("afterend",newChild),function(overviewTable){const rows=overviewTable.querySelectorAll("tbody > tr"),action=new URL(window.location.href).searchParams.get("action");rows.forEach((row=>{var _cols$col,_cols$col2,_cols$col3,_links$link,_links$link2,_userLink;const cols={col1:row.querySelector("td:nth-child(1)"),col2:row.querySelector("td:nth-child(2)"),col3:row.querySelector("td:nth-child(3)")},links={link1:null===(_cols$col=cols.col1)||void 0===_cols$col?void 0:_cols$col.querySelector("a"),link2:null===(_cols$col2=cols.col2)||void 0===_cols$col2?void 0:_cols$col2.querySelector("a"),link3:null===(_cols$col3=cols.col3)||void 0===_cols$col3?void 0:_cols$col3.querySelector("a")},commentId=null!==(_links$link=links.link1)&&void 0!==_links$link&&_links$link.href?new URL(links.link1.href).searchParams.get("commid"):null,cmid=null!==(_links$link2=links.link1)&&void 0!==_links$link2&&_links$link2.href?new URL(links.link1.href).searchParams.get("id"):M.cfg.contextInstanceId;let userId=null,userLink=null;switch(action){case"overviewquestions":userLink=links.link2;break;case"overviewanswers":userLink=links.link3;break;default:userId=userid}if(null!==(_userLink=userLink)&&void 0!==_userLink&&_userLink.href)try{userId=new URL(userLink.href).searchParams.get("id")}catch(e){window.console.warn("Error parsing user URL:",e)}!function(userid,resourceid,cmid,place){let args={id:resourceid,modulename:"pdfannotator",cmid:cmid},methodname="cursive_get_forum_comment_link",com=(0,_ajax.call)([{methodname:methodname,args:args}]);com[0].done((function(json){var data=JSON.parse(json),filepath="";data.data.filename&&(filepath=data.data.filename);let analyticButtonDiv=document.createElement("div"),analyticsColumn=document.createElement("td");hasApiKey?analyticButtonDiv.append((0,_analytic_button.default)(data.data.effort_ratio,resourceid)):analyticButtonDiv.append((0,_replay_button.default)(resourceid)),analyticButtonDiv.dataset.region="analytic-div"+userid,analyticsColumn.append(analyticButtonDiv),place.insertAdjacentElement("afterend",analyticsColumn);let myEvents=new _analytic_events.default;var context={tabledata:data.data,formattime:myEvents.formatedTime(data.data),page:scoreSetting,userid:resourceid,apikey:hasApiKey};let authIcon=myEvents.authorshipStatus(data.data.first_file,data.data.score,scoreSetting);myEvents.createModal(resourceid,context,"",replayInstances,authIcon),myEvents.analytics(resourceid,_templates.default,context,"",replayInstances,authIcon),myEvents.checkDiff(resourceid,data.data.file_id,"",replayInstances),myEvents.replyWriting(resourceid,filepath,"",replayInstances)})),com[0].fail((error=>{window.console.error("Error getting cursive config:",error)}))}(userId,commentId,cmid,cols.col1)}))}(overviewTable)}}})); + +//# sourceMappingURL=append_pdfannotator.min.js.map \ No newline at end of file diff --git a/amd/build/append_pdfannotator.min.js.map b/amd/build/append_pdfannotator.min.js.map new file mode 100644 index 00000000..efbbc64c --- /dev/null +++ b/amd/build/append_pdfannotator.min.js.map @@ -0,0 +1 @@ +{"version":3,"file":"append_pdfannotator.min.js","sources":["../src/append_pdfannotator.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 * Module for handling PDF annotator functionality,\n *\n * @module tiny_cursive/append_pdfannotator\n * @copyright 2025 Cursive Technology, Inc. \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport {call} from 'core/ajax';\nimport analyticButton from 'tiny_cursive/analytic_button';\nimport replayButton from 'tiny_cursive/replay_button';\nimport AnalyticEvents from 'tiny_cursive/analytic_events';\nimport templates from 'core/templates';\nimport Replay from 'tiny_cursive/replay';\nexport const init = (scoreSetting, comments, hasApiKey, userid) => {\n const replayInstances = {};\n // eslint-disable-next-line camelcase\n window.video_playback = function(mid, filepath) {\n if (filepath !== '') {\n const replay = new Replay(\n 'content' + mid,\n filepath,\n 10,\n false,\n 'player_' + mid\n );\n replayInstances[mid] = replay;\n } else {\n templates.render('tiny_cursive/no_submission').then(html => {\n document.getElementById('content' + mid).innerHTML = html;\n return true;\n }).catch(e => window.console.error(e));\n }\n return false;\n };\n\n let container = document.querySelector('.comment-list-container');\n const overviewTable = document.querySelector('table[id^=\"mod-pdfannotator-\"]');\n\n document.addEventListener('click', handleSubmit);\n const moduleName = document.body.id.split('-')[2];\n var pendingSubmit = false;\n var buttonElement = \"\";\n\n if (container) {\n const observer = new MutationObserver(() => {\n if (container?.lastChild?.id) {\n extractResourceId(container.lastChild.id);\n }\n });\n\n observer.observe(container, {\n subtree: true,\n childList: true\n });\n }\n\n if (overviewTable) {\n let newChild = document.createElement('th');\n newChild.textContent = 'Analytics';\n let header = overviewTable.querySelector('thead>tr>th:first-child');\n header.insertAdjacentElement('afterend', newChild);\n setReplayButton(overviewTable);\n }\n\n /**\n * Sets up replay buttons and analytics for each row in the overview table\n * @param {HTMLTableElement} overviewTable - The table element containing the overview data\n * @description This function:\n * 1. Gets all rows from the table\n * 2. For each row:\n * - Extracts comment ID and user ID from relevant links\n * - Adds analytics column with replay/analytics buttons\n * - Sets up cursive analytics functionality\n */\n function setReplayButton(overviewTable) {\n const rows = overviewTable.querySelectorAll('tbody > tr');\n const action = new URL(window.location.href).searchParams.get('action');\n\n rows.forEach(row => {\n const cols = {\n col1: row.querySelector('td:nth-child(1)'),\n col2: row.querySelector('td:nth-child(2)'),\n col3: row.querySelector('td:nth-child(3)')\n };\n\n const links = {\n link1: cols.col1?.querySelector('a'),\n link2: cols.col2?.querySelector('a'),\n link3: cols.col3?.querySelector('a')\n };\n\n // Extract comment ID safely\n const commentId = links.link1?.href ?\n new URL(links.link1.href).searchParams.get('commid') : null;\n const cmid = links.link1?.href ?\n new URL(links.link1.href).searchParams.get('id') : M.cfg.contextInstanceId;\n // Extract user ID based on action\n let userId = null;\n let userLink = null;\n\n switch (action) {\n case 'overviewquestions':\n userLink = links.link2;\n break;\n case 'overviewanswers':\n userLink = links.link3;\n break;\n default:\n userId = userid;\n }\n\n if (userLink?.href) {\n try {\n userId = new URL(userLink.href).searchParams.get('id');\n } catch (e) {\n window.console.warn('Error parsing user URL:', e);\n }\n }\n\n getCursiveAnalytics(userId, commentId, cmid, cols.col1);\n });\n }\n\n /**\n * Handles the submission and cancellation of comments\n * @param {Event} e - The click event object\n * @description When comment is submitted or cancelled:\n * - Removes 'isEditing' flag from localStorage\n * - Sets pendingSubmit flag appropriately (true for submit, false for cancel)\n */\n function handleSubmit(e) {\n if (e.target.id === 'commentSubmit') {\n localStorage.removeItem('isEditing');\n buttonElement = e.target.value;\n pendingSubmit = true;\n }\n if (e.target.id === 'commentCancel') {\n localStorage.removeItem('isEditing');\n pendingSubmit = false;\n }\n }\n\n const updateEntries = async(methodname, args) => {\n try {\n const response = await call([{\n methodname,\n args,\n }])[0];\n return response;\n } catch (error) {\n window.console.error('updating Entries:', error);\n throw error;\n }\n };\n\n /**\n * Extracts the resource ID from a comment ID and updates entries if submission is pending\n * @param {string} id - The ID string to extract resource ID from, expected format: 'prefix_number'\n * @description This function:\n * 1. Parses the resource ID from the given ID string\n * 2. If resource ID exists and there's a pending submission:\n * - Resets the pending submission flag\n * - Constructs arguments with context info\n * - Calls updateEntries to process the PDF annotation\n */\n function extractResourceId(id) {\n\n // Prevent updating ID while editing a existing entry.\n if (buttonElement === 'Save') {\n\n pendingSubmit = false;\n return;\n }\n\n let resourceId = parseInt(id?.split('_')[1]);\n if (resourceId && pendingSubmit) {\n pendingSubmit = false;\n let args = {\n cmid: M.cfg.contextInstanceId,\n userid: M.cfg.userId ?? 0,\n courseid: M.cfg.courseId,\n modulename: moduleName,\n resourceid: resourceId\n };\n updateEntries('cursive_update_pdf_annote_id', args);\n }\n }\n\n /**\n * Retrieves and displays cursive analytics for a given resource\n * @param {number} userid - The ID of the user\n * @param {number} resourceid - The ID of the resource to get analytics for\n * @param {number} cmid - The course module ID\n * @param {HTMLElement} place - The DOM element where analytics should be placed\n * @description This function:\n * 1. Makes an AJAX call to get forum comment data\n * 2. Creates and inserts analytics/replay buttons\n * 3. Sets up analytics events and modal functionality\n * 4. Handles both API key and non-API key scenarios\n */\n function getCursiveAnalytics(userid, resourceid, cmid, place) {\n let args = {id: resourceid, modulename: \"pdfannotator\", cmid: cmid};\n let methodname = 'cursive_get_forum_comment_link';\n let com = call([{methodname, args}]);\n com[0].done(function(json) {\n var data = JSON.parse(json);\n\n var filepath = '';\n if (data.data.filename) {\n filepath = data.data.filename;\n }\n\n let analyticButtonDiv = document.createElement('div');\n let analyticsColumn = document.createElement('td');\n\n if (!hasApiKey) {\n analyticButtonDiv.append(replayButton(resourceid));\n } else {\n analyticButtonDiv.append(analyticButton(data.data.effort_ratio, resourceid));\n }\n\n analyticButtonDiv.dataset.region = \"analytic-div\" + userid;\n analyticsColumn.append(analyticButtonDiv);\n place.insertAdjacentElement('afterend', analyticsColumn);\n\n let myEvents = new AnalyticEvents();\n var context = {\n tabledata: data.data,\n formattime: myEvents.formatedTime(data.data),\n page: scoreSetting,\n userid: resourceid,\n apikey: hasApiKey\n };\n\n let authIcon = myEvents.authorshipStatus(data.data.first_file, data.data.score, scoreSetting);\n myEvents.createModal(resourceid, context, '', replayInstances, authIcon);\n myEvents.analytics(resourceid, templates, context, '', replayInstances, authIcon);\n myEvents.checkDiff(resourceid, data.data.file_id, '', replayInstances);\n myEvents.replyWriting(resourceid, filepath, '', replayInstances);\n\n });\n com[0].fail((error) => {\n window.console.error('Error getting cursive config:', error);\n });\n }\n};"],"names":["scoreSetting","comments","hasApiKey","userid","replayInstances","window","video_playback","mid","filepath","replay","Replay","render","then","html","document","getElementById","innerHTML","catch","e","console","error","container","querySelector","overviewTable","addEventListener","target","id","localStorage","removeItem","buttonElement","value","pendingSubmit","moduleName","body","split","MutationObserver","lastChild","_container$lastChild","resourceId","parseInt","async","methodname","args","updateEntries","cmid","M","cfg","contextInstanceId","userId","courseid","courseId","modulename","resourceid","extractResourceId","observe","subtree","childList","newChild","createElement","textContent","insertAdjacentElement","rows","querySelectorAll","action","URL","location","href","searchParams","get","forEach","row","cols","col1","col2","col3","links","link1","_cols$col","link2","_cols$col2","link3","_cols$col3","commentId","userLink","_userLink","warn","place","com","done","json","data","JSON","parse","filename","analyticButtonDiv","analyticsColumn","append","effort_ratio","dataset","region","myEvents","AnalyticEvents","context","tabledata","formattime","formatedTime","page","apikey","authIcon","authorshipStatus","first_file","score","createModal","analytics","templates","checkDiff","file_id","replyWriting","fail","getCursiveAnalytics","setReplayButton"],"mappings":"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"} \ No newline at end of file diff --git a/amd/build/autosaver.min.js b/amd/build/autosaver.min.js index 13940655..5c4badae 100644 --- a/amd/build/autosaver.min.js +++ b/amd/build/autosaver.min.js @@ -1,3 +1,3 @@ -define("tiny_cursive/autosaver",["exports","core/ajax","core/modal_factory","core/str","core/modal_events","jquery","tiny_cursive/common","tiny_cursive/cursive_autosave","tiny_cursive/document_view"],(function(_exports,_ajax,_modal_factory,_str,_modal_events,_jquery,_common,_cursive_autosave,_document_view){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.register=void 0,_jquery=_interopRequireDefault(_jquery),_cursive_autosave=_interopRequireDefault(_cursive_autosave),_document_view=_interopRequireDefault(_document_view);_exports.register=(editor,interval,userId,hasApiKey,MODULES,Rubrics,submission,quizInfo,pasteSetting)=>{var isStudent=!(0,_jquery.default)("#body").hasClass("teacher_admin"),intervention=(0,_jquery.default)("#body").hasClass("intervention"),host=M.cfg.wwwroot,userid=userId,courseid=M.cfg.courseId,editorid=null==editor?void 0:editor.id,cmid=M.cfg.contextInstanceId,ed="",event="",filename="",questionid=0,quizSubmit=(0,_jquery.default)("#mod_quiz-next-nav");let assignSubmit=(0,_jquery.default)("#id_submitbutton");var syncInterval=interval?1e3*interval:1e4,lastCaretPos=1;let aiContents=[];var isFullScreen=!1,user=null;let ur=window.location.href,modulesInfo=function(ur,parm,MODULES){if(function(){localStorage.getItem("sbTitle")||Promise.all([(0,_str.get_string)("assignment","tiny_cursive"),(0,_str.get_string)("discussion","tiny_cursive"),(0,_str.get_string)("pluginname","mod_quiz"),(0,_str.get_string)("pluginname","mod_lesson"),(0,_str.get_string)("description","tiny_cursive")]).then((function(strings){return localStorage.setItem("sbTitle",JSON.stringify(strings))})).catch((error=>window.console.error(error)));localStorage.getItem("docSideBar")||Promise.all([(0,_str.get_string)("details","tiny_cursive"),(0,_str.get_string)("student_info","tiny_cursive"),(0,_str.get_string)("progress","tiny_cursive"),(0,_str.get_string)("description","tiny_cursive"),(0,_str.get_string)("replyingto","tiny_cursive"),(0,_str.get_string)("answeringto","tiny_cursive"),(0,_str.get_string)("importantdates","tiny_cursive"),(0,_str.get_string)("rubrics","tiny_cursive"),(0,_str.get_string)("submission_status","tiny_cursive"),(0,_str.get_string)("status","tiny_cursive"),(0,_str.get_string)("draft","tiny_cursive"),(0,_str.get_string)("draftnot","tiny_cursive"),(0,_str.get_string)("last_modified","tiny_cursive"),(0,_str.get_string)("gradings","tiny_cursive"),(0,_str.get_string)("gradenot","tiny_cursive"),(0,_str.get_string)("word_count","tiny_cursive"),(0,_str.get_string)("timeleft","tiny_cursive"),(0,_str.get_string)("nolimit","tiny_cursive"),(0,_str.get_string)("name","tiny_cursive"),(0,_str.get_string)("userename","tiny_cursive"),(0,_str.get_string)("course","tiny_cursive"),(0,_str.get_string)("opened","tiny_cursive"),(0,_str.get_string)("due","tiny_cursive"),(0,_str.get_string)("overdue","tiny_cursive"),(0,_str.get_string)("remaining","tiny_cursive"),(0,_str.get_string)("savechanges","tiny_cursive"),(0,_str.get_string)("subjectnot","tiny_cursive"),(0,_str.get_string)("remaining","tiny_cursive")]).then((function(strings){return localStorage.setItem("docSideBar",JSON.stringify(strings))})).catch((error=>window.console.error(error)))}(),!MODULES.some((module=>ur.includes(module))))return!1;resourceId=ur.includes("forum")&&!ur.includes("assign")?parm.searchParams.get("edit"):parm.searchParams.get("attempt");null===resourceId&&(resourceId=0);for(const module of MODULES)if(ur.includes(module)){modulename=module,"lesson"===module||"assign"===module?resourceId=cmid:"oublog"===module&&(resourceId=0);break}return{resourceId:resourceId,name:modulename}}(ur,new URL(ur),MODULES);var resourceId=modulesInfo.resourceId,modulename=modulesInfo.name,errorAlert=!0;let PASTE_SETTING=pasteSetting||"allow",shouldBlockPaste=!1,isPasteAllowed=!1;"assign"!==modulename&&(PASTE_SETTING="cite_source");const postOne=async(methodname,args)=>{try{const response=await(0,_ajax.call)([{methodname:methodname,args:args}])[0];return response&&setTimeout((()=>{_cursive_autosave.default.updateSavingState("saved")}),1e3),response}catch(error){throw _cursive_autosave.default.updateSavingState("offline"),window.console.error("Error in postOne:",error),error}};(0,_ajax.call)([{methodname:"core_user_get_users_by_field",args:{field:"id",values:[userid]}}])[0].done((response=>{user=response[0]})).fail((ex=>{window.console.error("Error fetching user data:",ex)})),assignSubmit.on("click",(async function(e){e.preventDefault(),filename?syncData().then((()=>{assignSubmit.off("click").click()})):assignSubmit.off("click").click(),localStorage.removeItem("lastCopyCutContent")})),quizSubmit.on("click",(async function(e){e.preventDefault(),filename?syncData().then((()=>{quizSubmit.off("click").click()})):quizSubmit.off("click").click(),localStorage.removeItem("lastCopyCutContent")}));const getModal=()=>{Promise.all([(0,_str.get_string)("tiny_cursive_srcurl","tiny_cursive"),(0,_str.get_string)("tiny_cursive_srcurl_des","tiny_cursive"),(0,_str.get_string)("tiny_cursive_placeholder","tiny_cursive")]).then((function(_ref){let[title,titledes,placeholder]=_ref;return(0,_modal_factory.create)({type:"SAVE_CANCEL",title:`
${title}
\n ${titledes}
`,body:``,removeOnClose:!0}).done((modal=>{modal.getRoot().addClass("tiny-cursive-modal"),modal.show();var lastEvent="";return modal.getRoot().on(_modal_events.save,(function(){var number=document.getElementById("inputUrl").value.trim();""===number||null==number?(editor.execCommand("Undo"),(0,_str.get_string)("pastewarning","tiny_cursive").then((str=>alert(str)))):editor.execCommand("Paste"),postOne("cursive_user_comments",{modulename:modulename,cmid:cmid,resourceid:resourceId,courseid:courseid,usercomment:number,timemodified:Date.now(),editorid:editorid||""}),lastEvent="save",modal.destroy()})),modal.getRoot().on(_modal_events.cancel,(function(){editor.execCommand("Undo"),lastEvent="cancel"})),modal.getRoot().on(_modal_events.hidden,(function(){"cancel"!=lastEvent&&"save"!=lastEvent&&editor.execCommand("Undo")})),modal}))})).catch((error=>window.console.error(error)))},sendKeyEvent=(events,editor)=>{if(ed=editor,event=events,filename=`${userid}_${resourceId}_${cmid}_${modulename}_attempt`,"quiz"===modulename&&(questionid=editorid.split(":")[1].split("_")[0],filename=`${userid}_${resourceId}_${cmid}_${questionid}_${modulename}_attempt`),localStorage.getItem(filename)){let data=JSON.parse(localStorage.getItem(filename));data.push({resourceId:resourceId,key:editor.key,keyCode:editor.keyCode,event:event,courseId:courseid,unixTimestamp:Date.now(),clientId:host,personId:userid,position:ed.caretPosition,rePosition:ed.rePosition,pastedContent:editor.pastedContent,aiContent:editor.aiContent}),localStorage.setItem(filename,JSON.stringify(data))}else{let data=[{resourceId:resourceId,key:editor.key,keyCode:editor.keyCode,event:event,courseId:courseid,unixTimestamp:Date.now(),clientId:host,personId:userid,position:ed.caretPosition,rePosition:ed.rePosition,pastedContent:editor.pastedContent,aiContent:editor.aiContent}];localStorage.setItem(filename,JSON.stringify(data))}};function constructMouseEvent(editor){let position=getCaretPosition(!1);editor.caretPosition=position.caretPosition,editor.rePosition=position.rePosition,editor.key=function(editor){switch(editor.button){case 0:return"left";case 1:return"middle";case 2:return"right"}return null}(editor),editor.keyCode=editor.button}function getCaretPosition(){let skip=arguments.length>0&&void 0!==arguments[0]&&arguments[0];try{if(!editor||!editor.selection)return{caretPosition:0,rePosition:0};const range=editor.selection.getRng(),body=editor.getBody(),preCaretRange=range.cloneRange();preCaretRange.selectNodeContents(body),preCaretRange.setEnd(range.endContainer,range.endOffset);const fragment=preCaretRange.cloneContents(),tempDiv=document.createElement("div");tempDiv.appendChild(fragment);let textBeforeCursor=tempDiv.innerText||"";const endContainer=range.endContainer;0===range.endOffset&&endContainer.nodeType===Node.ELEMENT_NODE&&editor.dom.isBlock(endContainer)&&endContainer.previousSibling&&(textBeforeCursor+="\n");const blockElements=tempDiv.querySelectorAll("p, div, h1, h2, h3, h4, h5, h6, li");let emptyBlockCount=0;blockElements.forEach((block=>{""===(block.innerText||block.textContent||"").trim()&&1===block.childNodes.length&&"BR"===block.childNodes[0].nodeName&&emptyBlockCount++})),emptyBlockCount>0&&(textBeforeCursor+="\n".repeat(emptyBlockCount));const absolutePosition=textBeforeCursor.length;if(skip)return{caretPosition:lastCaretPos,rePosition:absolutePosition};const storageKey=`${userid}_${resourceId}_${cmid}_position`;let storedPos=parseInt(sessionStorage.getItem(storageKey),10);return isNaN(storedPos)&&(storedPos=0),storedPos++,lastCaretPos=storedPos,sessionStorage.setItem(storageKey,storedPos),{caretPosition:storedPos,rePosition:absolutePosition}}catch(e){return window.console.warn("Error getting caret position:",e),{caretPosition:lastCaretPos||1,rePosition:0}}}async function syncData(){let data=localStorage.getItem(filename);if(data&&0!==data.length){localStorage.removeItem(filename);let originalText=editor.getContent({format:"text"});try{return _cursive_autosave.default.updateSavingState("saving"),await postOne("cursive_write_local_to_json",{key:ed.key,event:event,keyCode:ed.keyCode,resourceId:resourceId,cmid:cmid,modulename:modulename,editorid:editorid,json_data:data,originalText:originalText})}catch(error){window.console.error("Error submitting data:",error)}}}function customTooltip(){try{const tooltipText=async function(){const[buttonTitle,buttonDes]=await Promise.all([(0,_str.get_string)("cursive:state:active","tiny_cursive"),(0,_str.get_string)("cursive:state:active:des","tiny_cursive")]);return{buttonTitle:buttonTitle,buttonDes:buttonDes}}(),menubarDiv=document.querySelectorAll('div[role="menubar"].tox-menubar');let classArray=[];menubarDiv.length&&menubarDiv.forEach((function(element,index){let className="cursive-menu-"+(index+=1);element.classList.add(className),classArray.push(className)}));const cursiveIcon=document.createElement("img");cursiveIcon.src=hasApiKey?_common.iconUrl:_common.iconGrayUrl,cursiveIcon.setAttribute("class","tiny_cursive_StateButton"),cursiveIcon.style.display="inline-block",function(cursiveIcon,menubarDiv,classArray){if(!menubarDiv)return;for(let index in classArray){const rightWrapper=document.createElement("div"),imgWrapper=document.createElement("span"),iconClone=cursiveIcon.cloneNode(!0),targetMenu=document.querySelector("."+classArray[index]);let elementId="tiny_cursive_StateIcon"+index;rightWrapper.style.cssText="\n margin-left: auto;\n display: flex;\n align-items: center;\n ",imgWrapper.id=elementId,imgWrapper.style.marginLeft=".2rem",imgWrapper.appendChild(iconClone),rightWrapper.appendChild(imgWrapper);let moduleIds={resourceId:resourceId,cmid:cmid,modulename:modulename,questionid:questionid,userid:userid,courseid:courseid};if(!isFullScreen||"assign"!==modulename&&"forum"!==modulename&&"lesson"!==modulename)if(isFullScreen&&"quiz"===modulename){var _editor$container,_editor$container$chi,_editor$container$chi2,_editor$container$chi3,_editor$container2;let existingElement=null===(_editor$container=editor.container)||void 0===_editor$container||null===(_editor$container$chi=_editor$container.childNodes[1])||void 0===_editor$container$chi||null===(_editor$container$chi2=_editor$container$chi.childNodes[0])||void 0===_editor$container$chi2||null===(_editor$container$chi3=_editor$container$chi2.childNodes[0])||void 0===_editor$container$chi3?void 0:_editor$container$chi3.childNodes[7],newHeader=null===(_editor$container2=editor.container)||void 0===_editor$container2?void 0:_editor$container2.childNodes[0];existingElement&&existingElement.remove(),newHeader&&!newHeader.querySelector("span[id*=tiny_cursive_StateIcon]")&&(rightWrapper.style.marginTop="3px",document.querySelector("#tiny_cursive-fullpage-right-wrapper").prepend(rightWrapper)),_cursive_autosave.default.destroyInstance(),_cursive_autosave.default.getInstance(editor,rightWrapper,moduleIds,isFullScreen)}else{var _editor$container3,_editor$container3$ch,_editor$container3$ch2;let menubar=null==editor||null===(_editor$container3=editor.container)||void 0===_editor$container3||null===(_editor$container3$ch=_editor$container3.children[0])||void 0===_editor$container3$ch||null===(_editor$container3$ch2=_editor$container3$ch.childNodes[0])||void 0===_editor$container3$ch2?void 0:_editor$container3$ch2.childNodes[0];if(targetMenu&&!targetMenu.querySelector(`#${elementId}`)&&targetMenu.appendChild(rightWrapper),"quiz"===modulename&&menubar){let wrapper=menubar.querySelector('span[id*="tiny_cursive_StateIcon"]');wrapper&&(_cursive_autosave.default.destroyInstance(),_cursive_autosave.default.getInstance(editor,null==wrapper?void 0:wrapper.parentElement,moduleIds,isFullScreen))}else _cursive_autosave.default.destroyInstance(),_cursive_autosave.default.getInstance(editor,rightWrapper,moduleIds,isFullScreen)}else{let existsElement=document.querySelector('.tox-menubar[class*="cursive-menu-"] > div');existsElement&&existsElement.remove(),document.querySelector(`#${elementId}`)||(rightWrapper.style.marginTop="3px",document.querySelector("#tiny_cursive-fullpage-right-wrapper").prepend(rightWrapper)),_cursive_autosave.default.destroyInstance(),_cursive_autosave.default.getInstance(editor,rightWrapper,moduleIds,isFullScreen)}}}(cursiveIcon,menubarDiv,classArray);for(let index in classArray){const elementId="tiny_cursive_StateIcon"+index,tooltipId=`tiny_cursive_tooltip${index}`;tooltipText.then((text=>setTooltip(text,document.querySelector(`#${elementId}`),tooltipId))).catch((error=>window.console.error(error))),(0,_jquery.default)(`#${elementId}`).on("mouseenter",(function(){(0,_jquery.default)(this).css("position","relative"),(0,_jquery.default)(`#${tooltipId}`).css(_common.tooltipCss)})),(0,_jquery.default)(`#${elementId}`).on("mouseleave",(function(){(0,_jquery.default)(`#${tooltipId}`).css("display","none")}))}}catch(error){window.console.error("Error setting up custom tooltip:",error)}}function setTooltip(text,cursiveIcon,tooltipId){if(!document.querySelector(`#${tooltipId}`)&&cursiveIcon){const tooltipSpan=document.createElement("span"),description=document.createElement("span"),linebreak=document.createElement("br"),tooltipTitle=document.createElement("strong");tooltipSpan.style.display="none",tooltipTitle.textContent=text.buttonTitle,tooltipTitle.style.fontSize="16px",tooltipTitle.style.fontWeight="bold",description.textContent=text.buttonDes,description.style.fontSize="14px",tooltipSpan.id=tooltipId,tooltipSpan.classList.add("shadow"),tooltipSpan.appendChild(tooltipTitle),tooltipSpan.appendChild(linebreak),tooltipSpan.appendChild(description),cursiveIcon.appendChild(tooltipSpan)}}editor.on("keyUp",(editor=>{customTooltip();let position=getCaretPosition(!1);editor.caretPosition=position.caretPosition,editor.rePosition=position.rePosition,sendKeyEvent("keyUp",editor)})),editor.on("Paste",(async e=>{customTooltip();const pastedContent=(e.clipboardData||e.originalEvent.clipboardData).getData("text");if(!pastedContent)return;const trimmedPastedContent=pastedContent.trim(),lastCopyCutContent=localStorage.getItem("lastCopyCutContent"),isFromOwnEditor=lastCopyCutContent&&trimmedPastedContent===lastCopyCutContent;if(isStudent&&intervention){if("block"===PASTE_SETTING)return isFromOwnEditor?(shouldBlockPaste=!1,void(isPasteAllowed=!0)):(e.preventDefault(),shouldBlockPaste=!0,isPasteAllowed=!1,e.stopPropagation(),e.stopImmediatePropagation(),(0,_str.get_string)("paste_blocked","tiny_cursive").then((str=>editor.windowManager.alert(str))).catch((error=>window.console.error(error))),void setTimeout((()=>{isPasteAllowed=!0,shouldBlockPaste=!1}),100));if("cite_source"===PASTE_SETTING)return isFromOwnEditor||(e.preventDefault(),e.stopPropagation(),e.stopImmediatePropagation(),getModal()),void(isPasteAllowed=!0)}isPasteAllowed=!0})),editor.on("Redo",(async e=>{customTooltip(),isStudent&&intervention&&getModal()})),editor.on("keyDown",(editor=>{customTooltip();if(("v"===editor.key||"V"===editor.key)&&(editor.ctrlKey||editor.metaKey)&&isStudent&&intervention&&"block"===PASTE_SETTING&&!isPasteAllowed)return void setTimeout((()=>{isPasteAllowed=!0}),100);let position=getCaretPosition();editor.caretPosition=position.caretPosition,editor.rePosition=position.rePosition,sendKeyEvent("keyDown",editor)})),editor.on("Cut",(()=>{const selectedContent=editor.selection.getContent({format:"text"});localStorage.setItem("lastCopyCutContent",selectedContent.trim())})),editor.on("Copy",(()=>{const selectedContent=editor.selection.getContent({format:"text"});localStorage.setItem("lastCopyCutContent",selectedContent.trim())})),editor.on("mouseDown",(async editor=>{setTimeout((()=>{constructMouseEvent(editor),sendKeyEvent("mouseDown",editor)}),0)})),editor.on("mouseUp",(async editor=>{setTimeout((()=>{constructMouseEvent(editor),sendKeyEvent("mouseUp",editor)}),10)})),editor.on("init",(()=>{customTooltip(),localStorage.removeItem("lastCopyCutContent")})),editor.on("SetContent",(()=>{customTooltip()})),editor.on("FullscreenStateChanged",(e=>{let view=new _document_view.default(user,Rubrics,submission,modulename,editor,quizInfo);isFullScreen=e.state;try{e.state?view.fullPageMode():view.normalMode()}catch(error){errorAlert&&(errorAlert=!1,(0,_str.get_string)("fullmodeerror","tiny_cursive").then((str=>editor.windowManager.alert(str))).catch((error=>window.console.error(error)))),view.normalMode(),window.console.error("Error ResizeEditor event:",error)}})),editor.on("execcommand",(function(e){if("mceInsertContent"===e.command){const contentObj=e.value,isPaste=contentObj&&"object"==typeof contentObj&&!0===contentObj.paste;let insertedContent=contentObj.content||contentObj,tempDiv=document.createElement("div");tempDiv.innerHTML=insertedContent;let text=tempDiv.textContent||tempDiv.innerText||"",pastedText=tempDiv.textContent||tempDiv.innerText||"",position=getCaretPosition(!0);if(editor.caretPosition=position.caretPosition,editor.rePosition=position.rePosition,isPaste){if(shouldBlockPaste)return shouldBlockPaste=!1,e.preventDefault(),void editor.undoManager.undo();const lastCopyCutContent=localStorage.getItem("lastCopyCutContent"),isFromOwnEditor=lastCopyCutContent&&pastedText.trim()===lastCopyCutContent;if(isStudent&&intervention&&"block"===PASTE_SETTING&&!isFromOwnEditor)return isPasteAllowed=!1,void editor.undoManager.undo();sendKeyEvent("Paste",{key:"v",keyCode:86,caretPosition:editor.caretPosition,rePosition:editor.rePosition,pastedContent:pastedText,srcElement:{baseURI:window.location.href}})}else aiContents.push(text),sendKeyEvent("aiInsert",{key:"ai",keyCode:0,caretPosition:editor.caretPosition,rePosition:editor.rePosition,aiContent:text,srcElement:{baseURI:window.location.href}})}})),editor.on("input",(function(e){let position=getCaretPosition(!0);editor.caretPosition=position.caretPosition,editor.rePosition=position.rePosition;let aiContent=e.data;("insertReplacementText"===e.inputType||"insertText"===e.inputType&&aiContent&&aiContent.length>1)&&(aiContents.push(aiContent),e.key="ai",e.keyCode=0,e.caretPosition=position.caretPosition,e.rePosition=position.rePosition,e.aiContent=aiContent,sendKeyEvent("aiInsert",e))})),window.addEventListener("unload",(()=>{syncData()})),setInterval(syncData,syncInterval)}})); +define("tiny_cursive/autosaver",["exports","core/ajax","core/modal_factory","core/str","core/modal_events","jquery","tiny_cursive/common","tiny_cursive/cursive_autosave","tiny_cursive/document_view"],(function(_exports,_ajax,_modal_factory,_str,_modal_events,_jquery,_common,_cursive_autosave,_document_view){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.register=void 0,_jquery=_interopRequireDefault(_jquery),_cursive_autosave=_interopRequireDefault(_cursive_autosave),_document_view=_interopRequireDefault(_document_view);_exports.register=(editor,interval,userId,hasApiKey,MODULES,Rubrics,submission,quizInfo,pasteSetting)=>{var isStudent=!(0,_jquery.default)("#body").hasClass("teacher_admin"),intervention=(0,_jquery.default)("#body").hasClass("intervention"),host=M.cfg.wwwroot,userid=userId,courseid=M.cfg.courseId,editorid=null==editor?void 0:editor.id,cmid=M.cfg.contextInstanceId,ed="",event="",filename="",questionid=0,quizSubmit=(0,_jquery.default)("#mod_quiz-next-nav");let assignSubmit=(0,_jquery.default)("#id_submitbutton");var syncInterval=interval?1e3*interval:1e4,lastCaretPos=1;let aiContents=[];var isFullScreen=!1,user=null;let ur=window.location.href,parm=new URL(ur),modulesInfo=function(ur,parm,MODULES){if(function(){localStorage.getItem("sbTitle")||Promise.all([(0,_str.get_string)("assignment","tiny_cursive"),(0,_str.get_string)("discussion","tiny_cursive"),(0,_str.get_string)("pluginname","mod_quiz"),(0,_str.get_string)("pluginname","mod_lesson"),(0,_str.get_string)("description","tiny_cursive")]).then((function(strings){return localStorage.setItem("sbTitle",JSON.stringify(strings))})).catch((error=>window.console.error(error)));localStorage.getItem("docSideBar")||Promise.all([(0,_str.get_string)("details","tiny_cursive"),(0,_str.get_string)("student_info","tiny_cursive"),(0,_str.get_string)("progress","tiny_cursive"),(0,_str.get_string)("description","tiny_cursive"),(0,_str.get_string)("replyingto","tiny_cursive"),(0,_str.get_string)("answeringto","tiny_cursive"),(0,_str.get_string)("importantdates","tiny_cursive"),(0,_str.get_string)("rubrics","tiny_cursive"),(0,_str.get_string)("submission_status","tiny_cursive"),(0,_str.get_string)("status","tiny_cursive"),(0,_str.get_string)("draft","tiny_cursive"),(0,_str.get_string)("draftnot","tiny_cursive"),(0,_str.get_string)("last_modified","tiny_cursive"),(0,_str.get_string)("gradings","tiny_cursive"),(0,_str.get_string)("gradenot","tiny_cursive"),(0,_str.get_string)("word_count","tiny_cursive"),(0,_str.get_string)("timeleft","tiny_cursive"),(0,_str.get_string)("nolimit","tiny_cursive"),(0,_str.get_string)("name","tiny_cursive"),(0,_str.get_string)("userename","tiny_cursive"),(0,_str.get_string)("course","tiny_cursive"),(0,_str.get_string)("opened","tiny_cursive"),(0,_str.get_string)("due","tiny_cursive"),(0,_str.get_string)("overdue","tiny_cursive"),(0,_str.get_string)("remaining","tiny_cursive"),(0,_str.get_string)("savechanges","tiny_cursive"),(0,_str.get_string)("subjectnot","tiny_cursive"),(0,_str.get_string)("remaining","tiny_cursive")]).then((function(strings){return localStorage.setItem("docSideBar",JSON.stringify(strings))})).catch((error=>window.console.error(error)))}(),!MODULES.some((module=>ur.includes(module))))return!1;resourceId=ur.includes("forum")&&!ur.includes("assign")?parm.searchParams.get("edit"):parm.searchParams.get("attempt");null===resourceId&&(resourceId=0);for(const module of MODULES)if(ur.includes(module)){modulename=module,"lesson"===module||"assign"===module?resourceId=cmid:"oublog"===module&&(resourceId=0);break}return checkIsPdfAnnotator(),{resourceId:resourceId,name:modulename}}(ur,parm,MODULES);var resourceId=modulesInfo.resourceId,modulename=modulesInfo.name,errorAlert=!0;let PASTE_SETTING=pasteSetting||"allow",shouldBlockPaste=!1,isPasteAllowed=!1;ur.includes("pdfannotator")&&document.addEventListener("click",(e=>{if("dropdown-item comment-edit-a"===e.target.className){let id=e.target.id;resourceId=id.replace("editButton",""),localStorage.setItem("isEditing","1")}"commentSubmit"===e.target.id&&syncData()}));const postOne=async(methodname,args)=>{try{const response=await(0,_ajax.call)([{methodname:methodname,args:args}])[0];return response&&setTimeout((()=>{_cursive_autosave.default.updateSavingState("saved")}),1e3),response}catch(error){throw _cursive_autosave.default.updateSavingState("offline"),window.console.error("Error in postOne:",error),error}};(0,_ajax.call)([{methodname:"core_user_get_users_by_field",args:{field:"id",values:[userid]}}])[0].done((response=>{user=response[0]})).fail((ex=>{window.console.error("Error fetching user data:",ex)})),assignSubmit.on("click",(async function(e){e.preventDefault(),filename?syncData().then((()=>{assignSubmit.off("click").click()})):assignSubmit.off("click").click(),localStorage.removeItem("lastCopyCutContent")})),quizSubmit.on("click",(async function(e){e.preventDefault(),filename?syncData().then((()=>{quizSubmit.off("click").click()})):quizSubmit.off("click").click(),localStorage.removeItem("lastCopyCutContent")}));const getModal=()=>{Promise.all([(0,_str.get_string)("tiny_cursive_srcurl","tiny_cursive"),(0,_str.get_string)("tiny_cursive_srcurl_des","tiny_cursive"),(0,_str.get_string)("tiny_cursive_placeholder","tiny_cursive")]).then((function(_ref){let[title,titledes,placeholder]=_ref;return(0,_modal_factory.create)({type:"SAVE_CANCEL",title:`
${title}
\n ${titledes}
`,body:``,removeOnClose:!0}).done((modal=>{modal.getRoot().addClass("tiny-cursive-modal"),modal.show();var lastEvent="";return modal.getRoot().on(_modal_events.save,(function(){var number=document.getElementById("inputUrl").value.trim();""===number||null==number?(editor.execCommand("Undo"),(0,_str.get_string)("pastewarning","tiny_cursive").then((str=>alert(str)))):editor.execCommand("Paste"),postOne("cursive_user_comments",{modulename:modulename,cmid:cmid,resourceid:resourceId,courseid:courseid,usercomment:number,timemodified:Date.now(),editorid:editorid||""}),lastEvent="save",modal.destroy()})),modal.getRoot().on(_modal_events.cancel,(function(){editor.execCommand("Undo"),lastEvent="cancel"})),modal.getRoot().on(_modal_events.hidden,(function(){"cancel"!=lastEvent&&"save"!=lastEvent&&editor.execCommand("Undo")})),modal}))})).catch((error=>window.console.error(error)))},sendKeyEvent=(events,editor)=>{if(ed=editor,event=events,filename=`${userid}_${resourceId}_${cmid}_${modulename}_attempt`,"quiz"===modulename&&(questionid=editorid.split(":")[1].split("_")[0],filename=`${userid}_${resourceId}_${cmid}_${questionid}_${modulename}_attempt`),localStorage.getItem(filename)){let data=JSON.parse(localStorage.getItem(filename));data.push({resourceId:resourceId,key:editor.key,keyCode:editor.keyCode,event:event,courseId:courseid,unixTimestamp:Date.now(),clientId:host,personId:userid,position:ed.caretPosition,rePosition:ed.rePosition,pastedContent:editor.pastedContent,aiContent:editor.aiContent}),localStorage.setItem(filename,JSON.stringify(data))}else{let data=[{resourceId:resourceId,key:editor.key,keyCode:editor.keyCode,event:event,courseId:courseid,unixTimestamp:Date.now(),clientId:host,personId:userid,position:ed.caretPosition,rePosition:ed.rePosition,pastedContent:editor.pastedContent,aiContent:editor.aiContent}];localStorage.setItem(filename,JSON.stringify(data))}};function constructMouseEvent(editor){let position=getCaretPosition(!1);editor.caretPosition=position.caretPosition,editor.rePosition=position.rePosition,editor.key=function(editor){switch(editor.button){case 0:return"left";case 1:return"middle";case 2:return"right"}return null}(editor),editor.keyCode=editor.button}function getCaretPosition(){let skip=arguments.length>0&&void 0!==arguments[0]&&arguments[0];try{if(!editor||!editor.selection)return{caretPosition:0,rePosition:0};const range=editor.selection.getRng(),body=editor.getBody(),preCaretRange=range.cloneRange();preCaretRange.selectNodeContents(body),preCaretRange.setEnd(range.endContainer,range.endOffset);const fragment=preCaretRange.cloneContents(),tempDiv=document.createElement("div");tempDiv.appendChild(fragment);let textBeforeCursor=tempDiv.innerText||"";const endContainer=range.endContainer;0===range.endOffset&&endContainer.nodeType===Node.ELEMENT_NODE&&editor.dom.isBlock(endContainer)&&endContainer.previousSibling&&(textBeforeCursor+="\n");const blockElements=tempDiv.querySelectorAll("p, div, h1, h2, h3, h4, h5, h6, li");let emptyBlockCount=0;blockElements.forEach((block=>{""===(block.innerText||block.textContent||"").trim()&&1===block.childNodes.length&&"BR"===block.childNodes[0].nodeName&&emptyBlockCount++})),emptyBlockCount>0&&(textBeforeCursor+="\n".repeat(emptyBlockCount));const absolutePosition=textBeforeCursor.length;if(skip)return{caretPosition:lastCaretPos,rePosition:absolutePosition};const storageKey=`${userid}_${resourceId}_${cmid}_position`;let storedPos=parseInt(sessionStorage.getItem(storageKey),10);return isNaN(storedPos)&&(storedPos=0),storedPos++,lastCaretPos=storedPos,sessionStorage.setItem(storageKey,storedPos),{caretPosition:storedPos,rePosition:absolutePosition}}catch(e){return window.console.warn("Error getting caret position:",e),{caretPosition:lastCaretPos||1,rePosition:0}}}async function syncData(){checkIsPdfAnnotator();let data=localStorage.getItem(filename);if(data&&0!==data.length){localStorage.removeItem(filename),editor.fire("change");let originalText=editor.getContent({format:"text"});originalText||(originalText=function(editor){let editorId=null==editor?void 0:editor.id;if(editorId){var _iframe$contentDocume,_iframe$contentWindow,_iframe$contentWindow2;let iframe=document.querySelector(`#${editorId}_ifr`),iframeBody=(null===(_iframe$contentDocume=iframe.contentDocument)||void 0===_iframe$contentDocume?void 0:_iframe$contentDocume.body)||(null===(_iframe$contentWindow=iframe.contentWindow)||void 0===_iframe$contentWindow||null===(_iframe$contentWindow2=_iframe$contentWindow.document)||void 0===_iframe$contentWindow2?void 0:_iframe$contentWindow2.body);return null==iframeBody?void 0:iframeBody.textContent}return""}(editor));try{return _cursive_autosave.default.updateSavingState("saving"),await postOne("cursive_write_local_to_json",{key:ed.key,event:event,keyCode:ed.keyCode,resourceId:resourceId,cmid:cmid,modulename:modulename,editorid:editorid,json_data:data,originalText:originalText})}catch(error){window.console.error("Error submitting data:",error)}}}function customTooltip(){try{const tooltipText=async function(){const[buttonTitle,buttonDes]=await Promise.all([(0,_str.get_string)("cursive:state:active","tiny_cursive"),(0,_str.get_string)("cursive:state:active:des","tiny_cursive")]);return{buttonTitle:buttonTitle,buttonDes:buttonDes}}(),menubarDiv=document.querySelectorAll('div[role="menubar"].tox-menubar');let classArray=[];menubarDiv.length&&menubarDiv.forEach((function(element,index){let className="cursive-menu-"+(index+=1);element.classList.add(className),classArray.push(className)}));const cursiveIcon=document.createElement("img");cursiveIcon.src=hasApiKey?_common.iconUrl:_common.iconGrayUrl,cursiveIcon.setAttribute("class","tiny_cursive_StateButton"),cursiveIcon.style.display="inline-block",function(cursiveIcon,menubarDiv,classArray){if(!menubarDiv)return;for(let index in classArray){const rightWrapper=document.createElement("div"),imgWrapper=document.createElement("span"),iconClone=cursiveIcon.cloneNode(!0),targetMenu=document.querySelector("."+classArray[index]);let elementId="tiny_cursive_StateIcon"+index;rightWrapper.style.cssText="\n margin-left: auto;\n display: flex;\n align-items: center;\n ",imgWrapper.id=elementId,imgWrapper.style.marginLeft=".2rem",imgWrapper.appendChild(iconClone),rightWrapper.appendChild(imgWrapper);let moduleIds={resourceId:resourceId,cmid:cmid,modulename:modulename,questionid:questionid,userid:userid,courseid:courseid};if(!isFullScreen||"assign"!==modulename&&"forum"!==modulename&&"lesson"!==modulename)if(isFullScreen&&"quiz"===modulename){var _editor$container,_editor$container$chi,_editor$container$chi2,_editor$container$chi3,_editor$container2;let existingElement=null===(_editor$container=editor.container)||void 0===_editor$container||null===(_editor$container$chi=_editor$container.childNodes[1])||void 0===_editor$container$chi||null===(_editor$container$chi2=_editor$container$chi.childNodes[0])||void 0===_editor$container$chi2||null===(_editor$container$chi3=_editor$container$chi2.childNodes[0])||void 0===_editor$container$chi3?void 0:_editor$container$chi3.childNodes[7],newHeader=null===(_editor$container2=editor.container)||void 0===_editor$container2?void 0:_editor$container2.childNodes[0];existingElement&&existingElement.remove(),newHeader&&!newHeader.querySelector("span[id*=tiny_cursive_StateIcon]")&&(rightWrapper.style.marginTop="3px",document.querySelector("#tiny_cursive-fullpage-right-wrapper").prepend(rightWrapper)),_cursive_autosave.default.destroyInstance(),_cursive_autosave.default.getInstance(editor,rightWrapper,moduleIds,isFullScreen)}else{var _editor$container3,_editor$container3$ch,_editor$container3$ch2;let menubar=null==editor||null===(_editor$container3=editor.container)||void 0===_editor$container3||null===(_editor$container3$ch=_editor$container3.children[0])||void 0===_editor$container3$ch||null===(_editor$container3$ch2=_editor$container3$ch.childNodes[0])||void 0===_editor$container3$ch2?void 0:_editor$container3$ch2.childNodes[0];if(targetMenu&&!targetMenu.querySelector(`#${elementId}`)&&targetMenu.appendChild(rightWrapper),"quiz"===modulename&&menubar){let wrapper=menubar.querySelector('span[id*="tiny_cursive_StateIcon"]');wrapper&&(_cursive_autosave.default.destroyInstance(),_cursive_autosave.default.getInstance(editor,null==wrapper?void 0:wrapper.parentElement,moduleIds,isFullScreen))}else _cursive_autosave.default.destroyInstance(),_cursive_autosave.default.getInstance(editor,rightWrapper,moduleIds,isFullScreen)}else{let existsElement=document.querySelector('.tox-menubar[class*="cursive-menu-"] > div');existsElement&&existsElement.remove(),document.querySelector(`#${elementId}`)||(rightWrapper.style.marginTop="3px",document.querySelector("#tiny_cursive-fullpage-right-wrapper").prepend(rightWrapper)),_cursive_autosave.default.destroyInstance(),_cursive_autosave.default.getInstance(editor,rightWrapper,moduleIds,isFullScreen)}}}(cursiveIcon,menubarDiv,classArray);for(let index in classArray){const elementId="tiny_cursive_StateIcon"+index,tooltipId=`tiny_cursive_tooltip${index}`;tooltipText.then((text=>setTooltip(text,document.querySelector(`#${elementId}`),tooltipId))).catch((error=>window.console.error(error))),(0,_jquery.default)(`#${elementId}`).on("mouseenter",(function(){(0,_jquery.default)(this).css("position","relative"),(0,_jquery.default)(`#${tooltipId}`).css(_common.tooltipCss)})),(0,_jquery.default)(`#${elementId}`).on("mouseleave",(function(){(0,_jquery.default)(`#${tooltipId}`).css("display","none")}))}}catch(error){window.console.error("Error setting up custom tooltip:",error)}}function setTooltip(text,cursiveIcon,tooltipId){if(!document.querySelector(`#${tooltipId}`)&&cursiveIcon){const tooltipSpan=document.createElement("span"),description=document.createElement("span"),linebreak=document.createElement("br"),tooltipTitle=document.createElement("strong");tooltipSpan.style.display="none",tooltipTitle.textContent=text.buttonTitle,tooltipTitle.style.fontSize="16px",tooltipTitle.style.fontWeight="bold",description.textContent=text.buttonDes,description.style.fontSize="14px",tooltipSpan.id=tooltipId,tooltipSpan.classList.add("shadow"),tooltipSpan.appendChild(tooltipTitle),tooltipSpan.appendChild(linebreak),tooltipSpan.appendChild(description),cursiveIcon.appendChild(tooltipSpan)}}function checkIsPdfAnnotator(){ur.includes("pdfannotator")&&(resourceId="id_pdfannotator_content"!==editor.id&&parseInt(localStorage.getItem("isEditing"))?parseInt(null==editor?void 0:editor.id.replace("editarea","")):0)}editor.on("keyUp",(editor=>{customTooltip();let position=getCaretPosition(!1);editor.caretPosition=position.caretPosition,editor.rePosition=position.rePosition,sendKeyEvent("keyUp",editor)})),editor.on("Paste",(async e=>{customTooltip();const pastedContent=(e.clipboardData||e.originalEvent.clipboardData).getData("text");if(!pastedContent)return;const trimmedPastedContent=pastedContent.trim(),lastCopyCutContent=localStorage.getItem("lastCopyCutContent"),isFromOwnEditor=lastCopyCutContent&&trimmedPastedContent===lastCopyCutContent;if(isStudent&&intervention){if("block"===PASTE_SETTING)return isFromOwnEditor?(shouldBlockPaste=!1,void(isPasteAllowed=!0)):(e.preventDefault(),shouldBlockPaste=!0,isPasteAllowed=!1,e.stopPropagation(),e.stopImmediatePropagation(),(0,_str.get_string)("paste_blocked","tiny_cursive").then((str=>editor.windowManager.alert(str))).catch((error=>window.console.error(error))),void setTimeout((()=>{isPasteAllowed=!0,shouldBlockPaste=!1}),100));if("cite_source"===PASTE_SETTING)return isFromOwnEditor||(e.preventDefault(),e.stopPropagation(),e.stopImmediatePropagation(),getModal()),void(isPasteAllowed=!0)}isPasteAllowed=!0})),editor.on("Redo",(async e=>{customTooltip(),isStudent&&intervention&&getModal()})),editor.on("keyDown",(editor=>{customTooltip();if(("v"===editor.key||"V"===editor.key)&&(editor.ctrlKey||editor.metaKey)&&isStudent&&intervention&&"block"===PASTE_SETTING&&!isPasteAllowed)return void setTimeout((()=>{isPasteAllowed=!0}),100);let position=getCaretPosition();editor.caretPosition=position.caretPosition,editor.rePosition=position.rePosition,sendKeyEvent("keyDown",editor)})),editor.on("Cut",(()=>{const selectedContent=editor.selection.getContent({format:"text"});localStorage.setItem("lastCopyCutContent",selectedContent.trim())})),editor.on("Copy",(()=>{const selectedContent=editor.selection.getContent({format:"text"});localStorage.setItem("lastCopyCutContent",selectedContent.trim())})),editor.on("mouseDown",(async editor=>{setTimeout((()=>{constructMouseEvent(editor),sendKeyEvent("mouseDown",editor)}),0)})),editor.on("mouseUp",(async editor=>{setTimeout((()=>{constructMouseEvent(editor),sendKeyEvent("mouseUp",editor)}),10)})),editor.on("init",(()=>{customTooltip(),localStorage.removeItem("lastCopyCutContent")})),editor.on("SetContent",(()=>{customTooltip()})),editor.on("FullscreenStateChanged",(e=>{let view=new _document_view.default(user,Rubrics,submission,modulename,editor,quizInfo);isFullScreen=e.state;try{e.state?view.fullPageMode():view.normalMode()}catch(error){errorAlert&&(errorAlert=!1,(0,_str.get_string)("fullmodeerror","tiny_cursive").then((str=>editor.windowManager.alert(str))).catch((error=>window.console.error(error)))),view.normalMode(),window.console.error("Error ResizeEditor event:",error)}})),editor.on("execcommand",(function(e){if("mceInsertContent"===e.command){const contentObj=e.value,isPaste=contentObj&&"object"==typeof contentObj&&!0===contentObj.paste;let insertedContent=contentObj.content||contentObj,tempDiv=document.createElement("div");tempDiv.innerHTML=insertedContent;let text=tempDiv.textContent||tempDiv.innerText||"",pastedText=tempDiv.textContent||tempDiv.innerText||"",position=getCaretPosition(!0);if(editor.caretPosition=position.caretPosition,editor.rePosition=position.rePosition,isPaste){if(shouldBlockPaste)return shouldBlockPaste=!1,e.preventDefault(),void editor.undoManager.undo();const lastCopyCutContent=localStorage.getItem("lastCopyCutContent"),isFromOwnEditor=lastCopyCutContent&&pastedText.trim()===lastCopyCutContent;if(isStudent&&intervention&&"block"===PASTE_SETTING&&!isFromOwnEditor)return isPasteAllowed=!1,void editor.undoManager.undo();sendKeyEvent("Paste",{key:"v",keyCode:86,caretPosition:editor.caretPosition,rePosition:editor.rePosition,pastedContent:pastedText,srcElement:{baseURI:window.location.href}})}else aiContents.push(text),sendKeyEvent("aiInsert",{key:"ai",keyCode:0,caretPosition:editor.caretPosition,rePosition:editor.rePosition,aiContent:text,srcElement:{baseURI:window.location.href}})}})),editor.on("input",(function(e){let position=getCaretPosition(!0);editor.caretPosition=position.caretPosition,editor.rePosition=position.rePosition;let aiContent=e.data;("insertReplacementText"===e.inputType||"insertText"===e.inputType&&aiContent&&aiContent.length>1)&&(aiContents.push(aiContent),e.key="ai",e.keyCode=0,e.caretPosition=position.caretPosition,e.rePosition=position.rePosition,e.aiContent=aiContent,sendKeyEvent("aiInsert",e))})),window.addEventListener("unload",(()=>{syncData()})),setInterval(syncData,syncInterval)}})); //# sourceMappingURL=autosaver.min.js.map \ No newline at end of file diff --git a/amd/build/autosaver.min.js.map b/amd/build/autosaver.min.js.map index 3282341f..e0c9b4de 100644 --- a/amd/build/autosaver.min.js.map +++ b/amd/build/autosaver.min.js.map @@ -1 +1 @@ -{"version":3,"file":"autosaver.min.js","sources":["../src/autosaver.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 * @module tiny_cursive/autosaver\n * @category TinyMCE Editor\n * @copyright CTI \n * @author Brain Station 23 \n */\n\nimport {call} from 'core/ajax';\nimport {create} from 'core/modal_factory';\nimport {get_string as getString} from 'core/str';\nimport {save, cancel, hidden} from 'core/modal_events';\nimport $ from 'jquery';\nimport {iconUrl, iconGrayUrl, tooltipCss} from 'tiny_cursive/common';\nimport Autosave from 'tiny_cursive/cursive_autosave';\nimport DocumentView from 'tiny_cursive/document_view';\nimport {call as getUser} from \"core/ajax\";\n\nexport const register = (editor, interval, userId, hasApiKey, MODULES, Rubrics, submission, quizInfo, pasteSetting) => {\n\n var isStudent = !($('#body').hasClass('teacher_admin'));\n var intervention = $('#body').hasClass('intervention');\n var host = M.cfg.wwwroot;\n var userid = userId;\n var courseid = M.cfg.courseId;\n var editorid = editor?.id;\n var cmid = M.cfg.contextInstanceId;\n var ed = \"\";\n var event = \"\";\n var filename = \"\";\n var questionid = 0;\n var quizSubmit = $('#mod_quiz-next-nav');\n let assignSubmit = $('#id_submitbutton');\n var syncInterval = interval ? interval * 1000 : 10000; // Default: Sync Every 10s.\n var lastCaretPos = 1;\n let aiContents = [];\n var isFullScreen = false;\n var user = null;\n let ur = window.location.href;\n let parm = new URL(ur);\n let modulesInfo = getModulesInfo(ur, parm, MODULES);\n var resourceId = modulesInfo.resourceId;\n var modulename = modulesInfo.name;\n var errorAlert = true;\n let PASTE_SETTING = pasteSetting || 'allow';\n let shouldBlockPaste = false;\n let isPasteAllowed = false;\n\n if (modulename !== 'assign') {\n PASTE_SETTING = 'cite_source';\n }\n const postOne = async(methodname, args) => {\n try {\n const response = await call([{\n methodname,\n args,\n }])[0];\n if (response) {\n setTimeout(() => {\n Autosave.updateSavingState('saved');\n }, 1000);\n }\n return response;\n } catch (error) {\n Autosave.updateSavingState('offline');\n window.console.error('Error in postOne:', error);\n throw error;\n }\n };\n\n getUser([{\n methodname: 'core_user_get_users_by_field',\n args: {field: 'id', values: [userid]},\n }])[0].done(response => {\n user = response[0];\n }).fail((ex) => {\n window.console.error('Error fetching user data:', ex);\n });\n\n assignSubmit.on('click', async function(e) {\n e.preventDefault();\n if (filename) {\n // eslint-disable-next-line\n syncData().then(() => {\n assignSubmit.off('click').click();\n });\n } else {\n assignSubmit.off('click').click();\n }\n localStorage.removeItem('lastCopyCutContent');\n });\n\n quizSubmit.on('click', async function(e) {\n e.preventDefault();\n if (filename) {\n // eslint-disable-next-line\n syncData().then(() => {\n quizSubmit.off('click').click();\n });\n } else {\n quizSubmit.off('click').click();\n }\n localStorage.removeItem('lastCopyCutContent');\n });\n\n const getModal = () => {\n\n Promise.all([\n getString('tiny_cursive_srcurl', 'tiny_cursive'),\n getString('tiny_cursive_srcurl_des', 'tiny_cursive'),\n getString('tiny_cursive_placeholder', 'tiny_cursive')\n ]).then(function([title, titledes, placeholder]) {\n\n return create({\n type: 'SAVE_CANCEL',\n title: `
${title}
\n ${titledes}
`,\n body: ``,\n removeOnClose: true,\n })\n .done(modal => {\n modal.getRoot().addClass('tiny-cursive-modal');\n modal.show();\n var lastEvent = '';\n\n modal.getRoot().on(save, function() {\n\n var number = document.getElementById(\"inputUrl\").value.trim();\n\n if (number === \"\" || number === null || number === undefined) {\n editor.execCommand('Undo');\n // eslint-disable-next-line\n getString('pastewarning', 'tiny_cursive').then(str => alert(str));\n } else {\n editor.execCommand('Paste');\n }\n\n postOne('cursive_user_comments', {\n modulename: modulename,\n cmid: cmid,\n resourceid: resourceId,\n courseid: courseid,\n usercomment: number,\n timemodified: Date.now(),\n editorid: editorid ? editorid : \"\"\n });\n\n lastEvent = 'save';\n modal.destroy();\n });\n modal.getRoot().on(cancel, function() {\n editor.execCommand('Undo');\n lastEvent = 'cancel';\n });\n\n modal.getRoot().on(hidden, function() {\n if (lastEvent != 'cancel' && lastEvent != 'save') {\n editor.execCommand('Undo');\n }\n });\n return modal;\n });\n }).catch(error => window.console.error(error));\n\n };\n\n const sendKeyEvent = (events, editor) => {\n ed = editor;\n event = events;\n\n filename = `${userid}_${resourceId}_${cmid}_${modulename}_attempt`;\n\n if (modulename === 'quiz') {\n questionid = editorid.split(':')[1].split('_')[0];\n filename = `${userid}_${resourceId}_${cmid}_${questionid}_${modulename}_attempt`;\n }\n\n if (localStorage.getItem(filename)) {\n let data = JSON.parse(localStorage.getItem(filename));\n data.push({\n resourceId: resourceId,\n key: editor.key,\n keyCode: editor.keyCode,\n event: event,\n courseId: courseid,\n unixTimestamp: Date.now(),\n clientId: host,\n personId: userid,\n position: ed.caretPosition,\n rePosition: ed.rePosition,\n pastedContent: editor.pastedContent,\n aiContent: editor.aiContent\n });\n localStorage.setItem(filename, JSON.stringify(data));\n } else {\n let data = [{\n resourceId: resourceId,\n key: editor.key,\n keyCode: editor.keyCode,\n event: event,\n courseId: courseid,\n unixTimestamp: Date.now(),\n clientId: host,\n personId: userid,\n position: ed.caretPosition,\n rePosition: ed.rePosition,\n pastedContent: editor.pastedContent,\n aiContent: editor.aiContent\n }];\n localStorage.setItem(filename, JSON.stringify(data));\n }\n };\n\n editor.on('keyUp', (editor) => {\n customTooltip();\n let position = getCaretPosition(false);\n editor.caretPosition = position.caretPosition;\n editor.rePosition = position.rePosition;\n sendKeyEvent(\"keyUp\", editor);\n });\n editor.on('Paste', async(e) => {\n customTooltip();\n const pastedContent = (e.clipboardData || e.originalEvent.clipboardData).getData('text');\n if (!pastedContent) {\n return;\n }\n // Trim both values for consistent comparison\n const trimmedPastedContent = pastedContent.trim();\n const lastCopyCutContent = localStorage.getItem('lastCopyCutContent');\n const isFromOwnEditor = lastCopyCutContent && trimmedPastedContent === lastCopyCutContent;\n\n if (isStudent && intervention) {\n\n if (PASTE_SETTING === 'block') {\n if (!isFromOwnEditor) {\n e.preventDefault();\n shouldBlockPaste = true;\n isPasteAllowed = false;\n e.stopPropagation();\n e.stopImmediatePropagation();\n getString('paste_blocked', 'tiny_cursive').then(str => {\n return editor.windowManager.alert(str);\n }).catch(error => window.console.error(error));\n setTimeout(() => {\n isPasteAllowed = true;\n shouldBlockPaste = false;\n }, 100);\n return;\n }\n shouldBlockPaste = false;\n isPasteAllowed = true;\n return;\n }\n if (PASTE_SETTING === 'cite_source') {\n if (!isFromOwnEditor) {\n e.preventDefault();\n e.stopPropagation();\n e.stopImmediatePropagation();\n getModal(e);\n }\n isPasteAllowed = true;\n return;\n }\n }\n isPasteAllowed = true;\n });\n editor.on('Redo', async(e) => {\n customTooltip();\n if (isStudent && intervention) {\n getModal(e);\n }\n });\n editor.on('keyDown', (editor) => {\n customTooltip();\n const isPasteAttempt = (editor.key === 'v' || editor.key === 'V') &&\n (editor.ctrlKey || editor.metaKey);\n if (isPasteAttempt && isStudent && intervention && PASTE_SETTING === 'block' && !isPasteAllowed) {\n setTimeout(() => {\n isPasteAllowed = true;\n }, 100);\n return;\n }\n let position = getCaretPosition();\n editor.caretPosition = position.caretPosition;\n editor.rePosition = position.rePosition;\n sendKeyEvent(\"keyDown\", editor);\n });\n editor.on('Cut', () => {\n const selectedContent = editor.selection.getContent({format: 'text'});\n localStorage.setItem('lastCopyCutContent', selectedContent.trim());\n });\n editor.on('Copy', () => {\n const selectedContent = editor.selection.getContent({format: 'text'});\n localStorage.setItem('lastCopyCutContent', selectedContent.trim());\n });\n editor.on('mouseDown', async(editor) => {\n setTimeout(() => {\n constructMouseEvent(editor);\n sendKeyEvent(\"mouseDown\", editor);\n }, 0);\n });\n editor.on('mouseUp', async(editor) => {\n setTimeout(() => {\n constructMouseEvent(editor);\n sendKeyEvent(\"mouseUp\", editor);\n }, 10);\n });\n editor.on('init', () => {\n customTooltip();\n localStorage.removeItem('lastCopyCutContent');\n });\n editor.on('SetContent', () => {\n customTooltip();\n });\n editor.on('FullscreenStateChanged', (e) => {\n let view = new DocumentView(user, Rubrics, submission, modulename, editor, quizInfo);\n isFullScreen = e.state;\n try {\n if (!e.state) {\n view.normalMode();\n } else {\n view.fullPageMode();\n }\n } catch (error) {\n if (errorAlert) {\n errorAlert = false;\n getString('fullmodeerror', 'tiny_cursive').then(str => {\n return editor.windowManager.alert(str);\n }).catch(error => window.console.error(error));\n }\n view.normalMode();\n window.console.error('Error ResizeEditor event:', error);\n }\n });\n\n editor.on('execcommand', function(e) {\n if (e.command === \"mceInsertContent\") {\n const contentObj = e.value;\n\n const isPaste = contentObj && typeof contentObj === 'object' && contentObj.paste === true;\n\n let insertedContent = contentObj.content || contentObj;\n let tempDiv = document.createElement('div');\n tempDiv.innerHTML = insertedContent;\n let text = tempDiv.textContent || tempDiv.innerText || '';\n let pastedText = tempDiv.textContent || tempDiv.innerText || '';\n\n let position = getCaretPosition(true);\n editor.caretPosition = position.caretPosition;\n editor.rePosition = position.rePosition;\n\n if (isPaste) {\n if (shouldBlockPaste) {\n shouldBlockPaste = false;\n e.preventDefault();\n editor.undoManager.undo();\n return;\n }\n const lastCopyCutContent = localStorage.getItem('lastCopyCutContent');\n const isFromOwnEditor = lastCopyCutContent && pastedText.trim() === lastCopyCutContent;\n\n if (isStudent && intervention && PASTE_SETTING === 'block' && !isFromOwnEditor) {\n isPasteAllowed = false;\n editor.undoManager.undo();\n return;\n }\n\n sendKeyEvent(\"Paste\", {\n key: \"v\",\n keyCode: 86,\n caretPosition: editor.caretPosition,\n rePosition: editor.rePosition,\n pastedContent: pastedText,\n srcElement: {baseURI: window.location.href}\n });\n } else {\n aiContents.push(text);\n\n sendKeyEvent(\"aiInsert\", {\n key: \"ai\",\n keyCode: 0,\n caretPosition: editor.caretPosition,\n rePosition: editor.rePosition,\n aiContent: text,\n srcElement: {baseURI: window.location.href}\n });\n }\n }\n });\n\n editor.on('input', function(e) {\n let position = getCaretPosition(true);\n editor.caretPosition = position.caretPosition;\n editor.rePosition = position.rePosition;\n let aiContent = e.data;\n\n if (e.inputType === 'insertReplacementText' || (e.inputType === 'insertText' && aiContent && aiContent.length > 1)) {\n\n aiContents.push(aiContent);\n\n e.key = \"ai\";\n e.keyCode = 0;\n e.caretPosition = position.caretPosition;\n e.rePosition = position.rePosition;\n e.aiContent = aiContent;\n\n sendKeyEvent(\"aiInsert\", e);\n }\n });\n\n\n /**\n * Constructs a mouse event object with caret position and button information\n * @param {Object} editor - The TinyMCE editor instance\n * @function constructMouseEvent\n * @description Sets caret position, reposition, key and keyCode properties on the editor object based on current mouse state\n */\n function constructMouseEvent(editor) {\n let position = getCaretPosition(false);\n editor.caretPosition = position.caretPosition;\n editor.rePosition = position.rePosition;\n editor.key = getMouseButton(editor);\n editor.keyCode = editor.button;\n }\n\n /**\n * Gets the string representation of a mouse button based on its numeric value\n * @param {Object} editor - The editor object containing button information\n * @returns {string} The string representation of the mouse button ('left', 'middle', or 'right')\n */\n function getMouseButton(editor) {\n\n switch (editor.button) {\n case 0:\n return 'left';\n case 1:\n return 'middle';\n case 2:\n return 'right';\n }\n return null;\n }\n\n /**\n * Gets the current caret position in the editor\n * @param {boolean} skip - If true, returns the last known caret position instead of calculating a new one\n * @returns {Object} Object containing:\n * - caretPosition: Sequential position number stored in session\n * - rePosition: Absolute character offset from start of content\n * @throws {Error} Logs warning to console if error occurs during calculation\n */\n function getCaretPosition(skip = false) {\n try {\n if (!editor || !editor.selection) {\n return {caretPosition: 0, rePosition: 0};\n }\n\n const range = editor.selection.getRng();\n const body = editor.getBody();\n\n // Create a range from start of document to current caret\n const preCaretRange = range.cloneRange();\n preCaretRange.selectNodeContents(body);\n preCaretRange.setEnd(range.endContainer, range.endOffset);\n\n const fragment = preCaretRange.cloneContents();\n const tempDiv = document.createElement('div');\n tempDiv.appendChild(fragment);\n let textBeforeCursor = tempDiv.innerText || '';\n\n const endContainer = range.endContainer;\n const endOffset = range.endOffset;\n\n if (endOffset === 0 &&\n endContainer.nodeType === Node.ELEMENT_NODE &&\n editor.dom.isBlock(endContainer) &&\n endContainer.previousSibling) {\n textBeforeCursor += '\\n';\n }\n const blockElements = tempDiv.querySelectorAll('p, div, h1, h2, h3, h4, h5, h6, li');\n let emptyBlockCount = 0;\n blockElements.forEach(block => {\n const text = block.innerText || block.textContent || '';\n if (text.trim() === '' && block.childNodes.length === 1 &&\n block.childNodes[0].nodeName === 'BR') {\n emptyBlockCount++;\n }\n });\n\n // Add newlines for empty blocks (these represent Enter presses that created empty lines)\n if (emptyBlockCount > 0) {\n textBeforeCursor += '\\n'.repeat(emptyBlockCount);\n }\n\n const absolutePosition = textBeforeCursor.length;\n\n if (skip) {\n return {\n caretPosition: lastCaretPos,\n rePosition: absolutePosition\n };\n }\n // Increment sequential caretPosition\n const storageKey = `${userid}_${resourceId}_${cmid}_position`;\n let storedPos = parseInt(sessionStorage.getItem(storageKey), 10);\n if (isNaN(storedPos)) {\n storedPos = 0;\n }\n storedPos++;\n lastCaretPos = storedPos;\n sessionStorage.setItem(storageKey, storedPos);\n\n return {\n caretPosition: storedPos,\n rePosition: absolutePosition\n };\n\n } catch (e) {\n window.console.warn('Error getting caret position:', e);\n return {caretPosition: lastCaretPos || 1, rePosition: 0};\n }\n }\n\n\n /**\n * Synchronizes data from localStorage to server\n * @async\n * @function SyncData\n * @description Retrieves stored keypress data from localStorage and sends it to server\n * @returns {Promise} Returns response from server if data exists and is successfully sent\n * @throws {Error} Logs error to console if data submission fails\n */\n async function syncData() {\n\n let data = localStorage.getItem(filename);\n\n if (!data || data.length === 0) {\n return;\n } else {\n localStorage.removeItem(filename);\n let originalText = editor.getContent({format: 'text'});\n try {\n Autosave.updateSavingState('saving');\n // eslint-disable-next-line\n return await postOne('cursive_write_local_to_json', {\n key: ed.key,\n event: event,\n keyCode: ed.keyCode,\n resourceId: resourceId,\n cmid: cmid,\n modulename: modulename,\n editorid: editorid,\n \"json_data\": data,\n originalText: originalText\n });\n } catch (error) {\n window.console.error('Error submitting data:', error);\n }\n }\n }\n /**\n * Sets up custom tooltip functionality for the Cursive icon\n * Initializes tooltip text, positions the icon in the menubar,\n * and sets up mouse event handlers for showing/hiding the tooltip\n * @function customTooltip\n */\n function customTooltip() {\n try {\n const tooltipText = getTooltipText();\n const menubarDiv = document.querySelectorAll('div[role=\"menubar\"].tox-menubar');\n let classArray = [];\n\n if (menubarDiv.length) {\n menubarDiv.forEach(function(element, index) {\n index += 1;\n let className = 'cursive-menu-' + index;\n element.classList.add(className);\n classArray.push(className);\n });\n }\n\n const cursiveIcon = document.createElement('img');\n cursiveIcon.src = hasApiKey ? iconUrl : iconGrayUrl;\n\n cursiveIcon.setAttribute('class', 'tiny_cursive_StateButton');\n cursiveIcon.style.display = 'inline-block';\n\n cursiveState(cursiveIcon, menubarDiv, classArray);\n\n for (let index in classArray) {\n const elementId = \"tiny_cursive_StateIcon\" + index;\n const tooltipId = `tiny_cursive_tooltip${index}`;\n\n tooltipText.then((text) => {\n return setTooltip(text, document.querySelector(`#${elementId}`), tooltipId);\n }).catch(error => window.console.error(error));\n\n $(`#${elementId}`).on('mouseenter', function() {\n $(this).css('position', 'relative');\n $(`#${tooltipId}`).css(tooltipCss);\n });\n\n $(`#${elementId}`).on('mouseleave', function() {\n $(`#${tooltipId}`).css('display', 'none');\n });\n }\n } catch (error) {\n window.console.error('Error setting up custom tooltip:', error);\n }\n }\n\n /**\n * Retrieves tooltip text strings from language files\n * @async\n * @function getTooltipText\n * @returns {Promise} Object containing buttonTitle and buttonDes strings\n */\n async function getTooltipText() {\n const [\n buttonTitle,\n buttonDes,\n ] = await Promise.all([\n getString('cursive:state:active', 'tiny_cursive'),\n getString('cursive:state:active:des', 'tiny_cursive'),\n ]);\n return {buttonTitle, buttonDes};\n }\n\n /**\n * Updates the Cursive icon state and positions it in the menubar\n * @param {HTMLElement} cursiveIcon - The Cursive icon element to modify\n * @param {HTMLElement} menubarDiv - The menubar div element\n * @param {Array} classArray - Array of class names for the menubar div elements\n */\n function cursiveState(cursiveIcon, menubarDiv, classArray) {\n if (!menubarDiv) {\n return;\n }\n\n for (let index in classArray) {\n const rightWrapper = document.createElement('div');\n const imgWrapper = document.createElement('span');\n const iconClone = cursiveIcon.cloneNode(true);\n const targetMenu = document.querySelector('.' + classArray[index]);\n let elementId = \"tiny_cursive_StateIcon\" + index;\n\n rightWrapper.style.cssText = `\n margin-left: auto;\n display: flex;\n align-items: center;\n `;\n\n imgWrapper.id = elementId;\n imgWrapper.style.marginLeft = '.2rem';\n imgWrapper.appendChild(iconClone);\n rightWrapper.appendChild(imgWrapper);\n\n let moduleIds = {\n resourceId: resourceId,\n cmid: cmid,\n modulename: modulename,\n questionid: questionid,\n userid: userid,\n courseid: courseid};\n // Document mode, other modules single editor instances\n if (isFullScreen && (modulename === 'assign' || modulename === 'forum'\n || modulename === 'lesson')) {\n let existsElement = document.querySelector('.tox-menubar[class*=\"cursive-menu-\"] > div');\n if (existsElement) {\n existsElement.remove();\n }\n\n if (!document.querySelector(`#${elementId}`)) {\n rightWrapper.style.marginTop = '3px';\n document.querySelector('#tiny_cursive-fullpage-right-wrapper').prepend(rightWrapper);\n }\n\n Autosave.destroyInstance();\n Autosave.getInstance(editor, rightWrapper, moduleIds, isFullScreen);\n } else if (isFullScreen && modulename === 'quiz') { // Document mode, quiz multiple editor instances\n let existingElement = editor.container?.childNodes[1]?.childNodes[0]?.childNodes[0]?.childNodes[7];\n let newHeader = editor.container?.childNodes[0];\n if (existingElement) {\n existingElement.remove();\n }\n\n if (newHeader && !newHeader.querySelector(`span[id*=tiny_cursive_StateIcon]`)) {\n rightWrapper.style.marginTop = '3px';\n document.querySelector('#tiny_cursive-fullpage-right-wrapper').prepend(rightWrapper);\n }\n Autosave.destroyInstance();\n Autosave.getInstance(editor, rightWrapper, moduleIds, isFullScreen);\n } else { // Regular view\n let menubar = editor?.container?.children[0]?.childNodes[0]?.childNodes[0];\n\n if (targetMenu && !targetMenu.querySelector(`#${elementId}`)) {\n targetMenu.appendChild(rightWrapper);\n }\n // Regular view, multiple editor instances\n if (modulename === 'quiz' && menubar) {\n let wrapper = menubar.querySelector('span[id*=\"tiny_cursive_StateIcon\"]');\n\n if (wrapper) {\n Autosave.destroyInstance();\n Autosave.getInstance(editor, wrapper?.parentElement, moduleIds, isFullScreen);\n }\n } else {\n Autosave.destroyInstance();\n Autosave.getInstance(editor, rightWrapper, moduleIds, isFullScreen);\n }\n }\n }\n }\n\n /**\n * Sets up tooltip content and styling for the Cursive icon\n * @param {Object} text - Object containing tooltip text strings\n * @param {string} text.buttonTitle - Title text for the tooltip\n * @param {string} text.buttonDes - Description text for the tooltip\n * @param {HTMLElement} cursiveIcon - The Cursive icon element to attach tooltip to\n * @param {string} tooltipId - ID for the tooltip element\n */\n function setTooltip(text, cursiveIcon, tooltipId) {\n\n if (document.querySelector(`#${tooltipId}`)) {\n return;\n }\n if (cursiveIcon) {\n\n const tooltipSpan = document.createElement('span');\n const description = document.createElement('span');\n const linebreak = document.createElement('br');\n const tooltipTitle = document.createElement('strong');\n\n tooltipSpan.style.display = 'none';\n tooltipTitle.textContent = text.buttonTitle;\n tooltipTitle.style.fontSize = '16px';\n tooltipTitle.style.fontWeight = 'bold';\n description.textContent = text.buttonDes;\n description.style.fontSize = '14px';\n\n tooltipSpan.id = tooltipId;\n tooltipSpan.classList.add(`shadow`);\n tooltipSpan.appendChild(tooltipTitle);\n tooltipSpan.appendChild(linebreak);\n tooltipSpan.appendChild(description);\n cursiveIcon.appendChild(tooltipSpan);\n }\n }\n\n /**\n * Extracts module information from URL parameters\n * @param {string} ur - The base URL to analyze\n * @param {URL} parm - URL object containing search parameters\n * @param {Array} MODULES - Array of valid module names to check against\n * @returns {Object|boolean} Object containing resourceId and module name if found, false if no valid module\n */\n function getModulesInfo(ur, parm, MODULES) {\n fetchStrings();\n if (!MODULES.some(module => ur.includes(module))) {\n return false;\n }\n\n if (ur.includes(\"forum\") && !ur.includes(\"assign\")) {\n resourceId = parm.searchParams.get('edit');\n } else {\n resourceId = parm.searchParams.get('attempt');\n }\n\n if (resourceId === null) {\n resourceId = 0;\n }\n\n for (const module of MODULES) {\n if (ur.includes(module)) {\n modulename = module;\n if (module === \"lesson\" || module === \"assign\") {\n resourceId = cmid;\n } else if (module === \"oublog\") {\n resourceId = 0;\n }\n break;\n }\n }\n\n return {resourceId: resourceId, name: modulename};\n }\n\n /**\n * Fetches and caches localized strings used in the UI\n * @function fetchStrings\n * @description Retrieves strings for sidebar titles and document sidebar elements if not already cached in localStorage\n * Uses Promise.all to fetch multiple strings in parallel for better performance\n * Stores the fetched strings in localStorage under 'sbTitle' and 'docSideBar' keys\n */\n function fetchStrings() {\n if (!localStorage.getItem('sbTitle')) {\n Promise.all([\n getString('assignment', 'tiny_cursive'),\n getString('discussion', 'tiny_cursive'),\n getString('pluginname', 'mod_quiz'),\n getString('pluginname', 'mod_lesson'),\n getString('description', 'tiny_cursive'),\n ]).then(function(strings) {\n return localStorage.setItem('sbTitle', JSON.stringify(strings));\n }).catch(error => window.console.error(error));\n }\n if (!localStorage.getItem('docSideBar')) {\n Promise.all([\n getString('details', 'tiny_cursive'),\n getString('student_info', 'tiny_cursive'),\n getString('progress', 'tiny_cursive'),\n getString('description', 'tiny_cursive'),\n getString('replyingto', 'tiny_cursive'),\n getString('answeringto', 'tiny_cursive'),\n getString('importantdates', 'tiny_cursive'),\n getString('rubrics', 'tiny_cursive'),\n getString('submission_status', 'tiny_cursive'),\n getString('status', 'tiny_cursive'),\n getString('draft', 'tiny_cursive'),\n getString('draftnot', 'tiny_cursive'),\n getString('last_modified', 'tiny_cursive'),\n getString('gradings', 'tiny_cursive'),\n getString('gradenot', 'tiny_cursive'),\n getString('word_count', 'tiny_cursive'),\n getString('timeleft', 'tiny_cursive'),\n getString('nolimit', 'tiny_cursive'),\n getString('name', 'tiny_cursive'),\n getString('userename', 'tiny_cursive'),\n getString('course', 'tiny_cursive'),\n getString('opened', 'tiny_cursive'),\n getString('due', 'tiny_cursive'),\n getString('overdue', 'tiny_cursive'),\n getString('remaining', 'tiny_cursive'),\n getString('savechanges', 'tiny_cursive'),\n getString('subjectnot', 'tiny_cursive'),\n getString('remaining', 'tiny_cursive'),\n ]).then(function(strings) {\n return localStorage.setItem('docSideBar', JSON.stringify(strings));\n }).catch(error => window.console.error(error));\n }\n\n }\n\n window.addEventListener('unload', () => {\n syncData();\n });\n\n setInterval(syncData, syncInterval);\n};\n"],"names":["editor","interval","userId","hasApiKey","MODULES","Rubrics","submission","quizInfo","pasteSetting","isStudent","hasClass","intervention","host","M","cfg","wwwroot","userid","courseid","courseId","editorid","id","cmid","contextInstanceId","ed","event","filename","questionid","quizSubmit","assignSubmit","syncInterval","lastCaretPos","aiContents","isFullScreen","user","ur","window","location","href","modulesInfo","parm","localStorage","getItem","Promise","all","then","strings","setItem","JSON","stringify","catch","error","console","fetchStrings","some","module","includes","resourceId","searchParams","get","modulename","name","getModulesInfo","URL","errorAlert","PASTE_SETTING","shouldBlockPaste","isPasteAllowed","postOne","async","methodname","args","response","setTimeout","updateSavingState","field","values","done","fail","ex","on","e","preventDefault","syncData","off","click","removeItem","getModal","title","titledes","placeholder","type","body","removeOnClose","modal","getRoot","addClass","show","lastEvent","save","number","document","getElementById","value","trim","execCommand","str","alert","resourceid","usercomment","timemodified","Date","now","destroy","cancel","hidden","sendKeyEvent","events","split","data","parse","push","key","keyCode","unixTimestamp","clientId","personId","position","caretPosition","rePosition","pastedContent","aiContent","constructMouseEvent","getCaretPosition","button","getMouseButton","skip","selection","range","getRng","getBody","preCaretRange","cloneRange","selectNodeContents","setEnd","endContainer","endOffset","fragment","cloneContents","tempDiv","createElement","appendChild","textBeforeCursor","innerText","nodeType","Node","ELEMENT_NODE","dom","isBlock","previousSibling","blockElements","querySelectorAll","emptyBlockCount","forEach","block","textContent","childNodes","length","nodeName","repeat","absolutePosition","storageKey","storedPos","parseInt","sessionStorage","isNaN","warn","originalText","getContent","format","customTooltip","tooltipText","buttonTitle","buttonDes","getTooltipText","menubarDiv","classArray","element","index","className","classList","add","cursiveIcon","src","iconUrl","iconGrayUrl","setAttribute","style","display","rightWrapper","imgWrapper","iconClone","cloneNode","targetMenu","querySelector","elementId","cssText","marginLeft","moduleIds","existingElement","container","_editor$container","_editor$container$chi","_editor$container$chi2","_editor$container$chi3","newHeader","_editor$container2","remove","marginTop","prepend","destroyInstance","getInstance","menubar","_editor$container3","children","_editor$container3$ch","_editor$container3$ch2","wrapper","parentElement","existsElement","cursiveState","tooltipId","text","setTooltip","this","css","tooltipCss","tooltipSpan","description","linebreak","tooltipTitle","fontSize","fontWeight","clipboardData","originalEvent","getData","trimmedPastedContent","lastCopyCutContent","isFromOwnEditor","stopPropagation","stopImmediatePropagation","windowManager","ctrlKey","metaKey","selectedContent","view","DocumentView","state","fullPageMode","normalMode","command","contentObj","isPaste","paste","insertedContent","content","innerHTML","pastedText","undoManager","undo","srcElement","baseURI","inputType","addEventListener","setInterval"],"mappings":"ooBAgCwB,CAACA,OAAQC,SAAUC,OAAQC,UAAWC,QAASC,QAASC,WAAYC,SAAUC,oBAE9FC,YAAc,mBAAE,SAASC,SAAS,iBAClCC,cAAe,mBAAE,SAASD,SAAS,gBACnCE,KAAOC,EAAEC,IAAIC,QACbC,OAASd,OACTe,SAAWJ,EAAEC,IAAII,SACjBC,SAAWnB,MAAAA,cAAAA,OAAQoB,GACnBC,KAAOR,EAAEC,IAAIQ,kBACbC,GAAK,GACLC,MAAQ,GACRC,SAAW,GACXC,WAAa,EACbC,YAAa,mBAAE,0BACfC,cAAe,mBAAE,wBACjBC,aAAe5B,SAAsB,IAAXA,SAAkB,IAC5C6B,aAAe,MACfC,WAAa,OACbC,cAAe,EACfC,KAAO,SACPC,GAAKC,OAAOC,SAASC,KAErBC,qBA6sBoBJ,GAAIK,KAAMnC,uBAuCzBoC,aAAaC,QAAQ,YACtBC,QAAQC,IAAI,EACR,mBAAU,aAAc,iBACxB,mBAAU,aAAc,iBACxB,mBAAU,aAAc,aACxB,mBAAU,aAAc,eACxB,mBAAU,cAAe,kBAC1BC,MAAK,SAASC,gBACNL,aAAaM,QAAQ,UAAWC,KAAKC,UAAUH,aACvDI,OAAMC,OAASf,OAAOgB,QAAQD,MAAMA,SAEtCV,aAAaC,QAAQ,eACtBC,QAAQC,IAAI,EACR,mBAAU,UAAW,iBACrB,mBAAU,eAAgB,iBAC1B,mBAAU,WAAY,iBACtB,mBAAU,cAAe,iBACzB,mBAAU,aAAc,iBACxB,mBAAU,cAAe,iBACzB,mBAAU,iBAAkB,iBAC5B,mBAAU,UAAW,iBACrB,mBAAU,oBAAqB,iBAC/B,mBAAU,SAAU,iBACpB,mBAAU,QAAS,iBACnB,mBAAU,WAAY,iBACtB,mBAAU,gBAAiB,iBAC3B,mBAAU,WAAY,iBACtB,mBAAU,WAAY,iBACtB,mBAAU,aAAc,iBACxB,mBAAU,WAAY,iBACtB,mBAAU,UAAW,iBACrB,mBAAU,OAAQ,iBAClB,mBAAU,YAAa,iBACvB,mBAAU,SAAU,iBACpB,mBAAU,SAAU,iBACpB,mBAAU,MAAO,iBACjB,mBAAU,UAAW,iBACrB,mBAAU,YAAa,iBACvB,mBAAU,cAAe,iBACzB,mBAAU,aAAc,iBACxB,mBAAU,YAAa,kBACxBC,MAAK,SAASC,gBACNL,aAAaM,QAAQ,aAAcC,KAAKC,UAAUH,aAC1DI,OAAMC,OAASf,OAAOgB,QAAQD,MAAMA,SAjF3CE,IACKhD,QAAQiD,MAAKC,QAAUpB,GAAGqB,SAASD,iBAC7B,EAIPE,WADAtB,GAAGqB,SAAS,WAAarB,GAAGqB,SAAS,UACxBhB,KAAKkB,aAAaC,IAAI,QAEtBnB,KAAKkB,aAAaC,IAAI,WAGpB,OAAfF,aACAA,WAAa,OAGZ,MAAMF,UAAUlD,WACb8B,GAAGqB,SAASD,QAAS,CACrBK,WAAaL,OACE,WAAXA,QAAkC,WAAXA,OACvBE,WAAanC,KACK,WAAXiC,SACPE,WAAa,eAMlB,CAACA,WAAYA,WAAYI,KAAMD,YAzuBxBE,CAAe3B,GADtB,IAAI4B,IAAI5B,IACwB9B,aACvCoD,WAAalB,YAAYkB,WACzBG,WAAarB,YAAYsB,KACzBG,YAAa,MACbC,cAAgBxD,cAAgB,QAChCyD,kBAAmB,EACnBC,gBAAiB,EAEF,WAAfP,aACAK,cAAgB,qBAEdG,QAAUC,MAAMC,WAAYC,kBAEpBC,eAAiB,cAAK,CAAC,CACzBF,WAAAA,WACAC,KAAAA,QACA,UACAC,UACAC,YAAW,+BACEC,kBAAkB,WAC5B,KAEAF,SACT,MAAOrB,uCACIuB,kBAAkB,WAC3BtC,OAAOgB,QAAQD,MAAM,oBAAqBA,OACpCA,uBAIN,CAAC,CACDmB,WAAY,+BACZC,KAAM,CAACI,MAAO,KAAMC,OAAQ,CAAC3D,YAC7B,GAAG4D,MAAKL,WACRtC,KAAOsC,SAAS,MACjBM,MAAMC,KACL3C,OAAOgB,QAAQD,MAAM,4BAA6B4B,OAG1DlD,aAAamD,GAAG,SAASX,eAAeY,GACpCA,EAAEC,iBACExD,SAEAyD,WAAWtC,MAAK,KACZhB,aAAauD,IAAI,SAASC,WAG9BxD,aAAauD,IAAI,SAASC,QAE9B5C,aAAa6C,WAAW,yBAG5B1D,WAAWoD,GAAG,SAASX,eAAeY,GAClCA,EAAEC,iBACExD,SAEAyD,WAAWtC,MAAK,KACZjB,WAAWwD,IAAI,SAASC,WAG5BzD,WAAWwD,IAAI,SAASC,QAE5B5C,aAAa6C,WAAW,+BAGtBC,SAAW,KAEb5C,QAAQC,IAAI,EACR,mBAAU,sBAAuB,iBACjC,mBAAU,0BAA2B,iBACrC,mBAAU,2BAA4B,kBACvCC,MAAK,mBAAU2C,MAAOC,SAAUC,yBAExB,yBAAO,CACVC,KAAM,cACNH,MAAQ,6CAA4CA,8EACJC,wBAChDG,KAAO,gFAA+EF,2BACtFG,eAAe,IAEdhB,MAAKiB,QACFA,MAAMC,UAAUC,SAAS,sBACzBF,MAAMG,WACFC,UAAY,UAEhBJ,MAAMC,UAAUf,GAAGmB,oBAAM,eAEjBC,OAASC,SAASC,eAAe,YAAYC,MAAMC,OAExC,KAAXJ,QAAAA,MAAiBA,QACjBnG,OAAOwG,YAAY,4BAET,eAAgB,gBAAgB5D,MAAK6D,KAAOC,MAAMD,QAE5DzG,OAAOwG,YAAY,SAGvBrC,QAAQ,wBAAyB,CAC7BR,WAAYA,WACZtC,KAAMA,KACNsF,WAAYnD,WACZvC,SAAUA,SACV2F,YAAaT,OACbU,aAAcC,KAAKC,MACnB5F,SAAUA,UAAsB,KAGpC8E,UAAY,OACZJ,MAAMmB,aAEVnB,MAAMC,UAAUf,GAAGkC,sBAAQ,WACvBjH,OAAOwG,YAAY,QACnBP,UAAY,YAGhBJ,MAAMC,UAAUf,GAAGmC,sBAAQ,WACN,UAAbjB,WAAsC,QAAbA,WACzBjG,OAAOwG,YAAY,WAGpBX,YAEhB5C,OAAMC,OAASf,OAAOgB,QAAQD,MAAMA,UAIrCiE,aAAe,CAACC,OAAQpH,aAC1BuB,GAAKvB,OACLwB,MAAQ4F,OAER3F,SAAY,GAAET,UAAUwC,cAAcnC,QAAQsC,qBAE3B,SAAfA,aACAjC,WAAaP,SAASkG,MAAM,KAAK,GAAGA,MAAM,KAAK,GAC/C5F,SAAY,GAAET,UAAUwC,cAAcnC,QAAQK,cAAciC,sBAG5DnB,aAAaC,QAAQhB,UAAW,KAC5B6F,KAAOvE,KAAKwE,MAAM/E,aAAaC,QAAQhB,WAC3C6F,KAAKE,KAAK,CACNhE,WAAYA,WACZiE,IAAKzH,OAAOyH,IACZC,QAAS1H,OAAO0H,QAChBlG,MAAOA,MACPN,SAAUD,SACV0G,cAAeb,KAAKC,MACpBa,SAAUhH,KACViH,SAAU7G,OACV8G,SAAUvG,GAAGwG,cACbC,WAAYzG,GAAGyG,WACfC,cAAejI,OAAOiI,cACtBC,UAAWlI,OAAOkI,YAEtB1F,aAAaM,QAAQrB,SAAUsB,KAAKC,UAAUsE,WAC3C,KACCA,KAAO,CAAC,CACR9D,WAAYA,WACZiE,IAAKzH,OAAOyH,IACZC,QAAS1H,OAAO0H,QAChBlG,MAAOA,MACPN,SAAUD,SACV0G,cAAeb,KAAKC,MACpBa,SAAUhH,KACViH,SAAU7G,OACV8G,SAAUvG,GAAGwG,cACbC,WAAYzG,GAAGyG,WACfC,cAAejI,OAAOiI,cACtBC,UAAWlI,OAAOkI,YAEtB1F,aAAaM,QAAQrB,SAAUsB,KAAKC,UAAUsE,kBAgN7Ca,oBAAoBnI,YACrB8H,SAAWM,kBAAiB,GAChCpI,OAAO+H,cAAgBD,SAASC,cAChC/H,OAAOgI,WAAaF,SAASE,WAC7BhI,OAAOyH,aASazH,eAEZA,OAAOqI,aACN,QACM,YACN,QACM,cACN,QACM,eAER,KAnBMC,CAAetI,QAC5BA,OAAO0H,QAAU1H,OAAOqI,gBA6BnBD,uBAAiBG,qEAEfvI,SAAWA,OAAOwI,gBACd,CAACT,cAAe,EAAGC,WAAY,SAGlCS,MAAQzI,OAAOwI,UAAUE,SACzB/C,KAAO3F,OAAO2I,UAGdC,cAAgBH,MAAMI,aAC5BD,cAAcE,mBAAmBnD,MACjCiD,cAAcG,OAAON,MAAMO,aAAcP,MAAMQ,iBAEzCC,SAAWN,cAAcO,gBACzBC,QAAUhD,SAASiD,cAAc,OACvCD,QAAQE,YAAYJ,cAChBK,iBAAmBH,QAAQI,WAAa,SAEtCR,aAAeP,MAAMO,aAGT,IAFAP,MAAMQ,WAGpBD,aAAaS,WAAaC,KAAKC,cAC/B3J,OAAO4J,IAAIC,QAAQb,eACnBA,aAAac,kBACbP,kBAAoB,YAElBQ,cAAgBX,QAAQY,iBAAiB,0CAC3CC,gBAAkB,EACtBF,cAAcG,SAAQC,QAEA,MADPA,MAAMX,WAAaW,MAAMC,aAAe,IAC5C7D,QAA6C,IAA5B4D,MAAME,WAAWC,QACN,OAAjCH,MAAME,WAAW,GAAGE,UACtBN,qBAKAA,gBAAkB,IACpBV,kBAAoB,KAAKiB,OAAOP,wBAG5BQ,iBAAmBlB,iBAAiBe,UAEtC/B,WACK,CACLR,cAAejG,aACfkG,WAAYyC,wBAIVC,WAAc,GAAE1J,UAAUwC,cAAcnC,oBAC1CsJ,UAAYC,SAASC,eAAepI,QAAQiI,YAAa,WACzDI,MAAMH,aACRA,UAAY,GAEdA,YACA7I,aAAe6I,UACfE,eAAe/H,QAAQ4H,WAAYC,WAE5B,CACL5C,cAAe4C,UACf3C,WAAYyC,kBAGd,MAAOzF,UACL7C,OAAOgB,QAAQ4H,KAAK,gCAAiC/F,GAC9C,CAAC+C,cAAejG,cAAgB,EAAGkG,WAAY,mBAa/C9C,eAEPoC,KAAO9E,aAAaC,QAAQhB,aAE3B6F,MAAwB,IAAhBA,KAAKgD,OAEX,CACH9H,aAAa6C,WAAW5D,cACpBuJ,aAAehL,OAAOiL,WAAW,CAACC,OAAQ,8CAEjCzG,kBAAkB,gBAEdN,QAAQ,8BAA+B,CAChDsD,IAAKlG,GAAGkG,IACRjG,MAAOA,MACPkG,QAASnG,GAAGmG,QACZlE,WAAYA,WACZnC,KAAMA,KACNsC,WAAYA,WACZxC,SAAUA,mBACGmG,KACb0D,aAAcA,eAEpB,MAAO9H,OACLf,OAAOgB,QAAQD,MAAM,yBAA0BA,kBAUlDiI,0BAEKC,mCAmDNC,YACAC,iBACM5I,QAAQC,IAAI,EAClB,mBAAU,uBAAwB,iBAClC,mBAAU,2BAA4B,wBAEnC,CAAC0I,YAAAA,YAAaC,UAAAA,WAzDGC,GACdC,WAAapF,SAAS4D,iBAAiB,uCACzCyB,WAAa,GAEbD,WAAWlB,QACXkB,WAAWtB,SAAQ,SAASwB,QAASC,WAE7BC,UAAY,iBADhBD,OAAS,GAETD,QAAQG,UAAUC,IAAIF,WACtBH,WAAWjE,KAAKoE,oBAIlBG,YAAc3F,SAASiD,cAAc,OAC3C0C,YAAYC,IAAM7L,UAAY8L,gBAAUC,oBAExCH,YAAYI,aAAa,QAAS,4BAClCJ,YAAYK,MAAMC,QAAU,wBAiDdN,YAAaP,WAAYC,gBACtCD,sBAIA,IAAIG,SAASF,WAAY,OACpBa,aAAelG,SAASiD,cAAc,OACtCkD,WAAanG,SAASiD,cAAc,QACpCmD,UAAYT,YAAYU,WAAU,GAClCC,WAAatG,SAASuG,cAAc,IAAMlB,WAAWE,YACvDiB,UAAY,yBAA2BjB,MAE3CW,aAAaF,MAAMS,QAAW,2JAM9BN,WAAWnL,GAAKwL,UAChBL,WAAWH,MAAMU,WAAa,QAC9BP,WAAWjD,YAAYkD,WACvBF,aAAahD,YAAYiD,gBAErBQ,UAAY,CACZvJ,WAAYA,WACZnC,KAAMA,KACNsC,WAAYA,WACZjC,WAAYA,WACZV,OAAQA,OACRC,SAAUA,cAEVe,cAAgC,WAAf2B,YAA0C,UAAfA,YAC1B,WAAfA,WAaA,GAAI3B,cAA+B,SAAf2B,WAAuB,kHAC1CqJ,0CAAkBhN,OAAOiN,sEAAPC,kBAAkB7C,WAAW,oEAA7B8C,sBAAiC9C,WAAW,qEAA5C+C,uBAAgD/C,WAAW,4CAA3DgD,uBAA+DhD,WAAW,GAC5FiD,qCAAYtN,OAAOiN,+CAAPM,mBAAkBlD,WAAW,GACzC2C,iBACAA,gBAAgBQ,SAGhBF,YAAcA,UAAUX,cAAe,sCACvCL,aAAaF,MAAMqB,UAAY,MAC/BrH,SAASuG,cAAc,wCAAwCe,QAAQpB,yCAElEqB,4CACAC,YAAY5N,OAAQsM,aAAcS,UAAW/K,kBACnD,yEACC6L,QAAU7N,MAAAA,mCAAAA,OAAQiN,uEAARa,mBAAmBC,SAAS,oEAA5BC,sBAAgC3D,WAAW,4CAA3C4D,uBAA+C5D,WAAW,MAEpEqC,aAAeA,WAAWC,cAAe,IAAGC,cAC5CF,WAAWpD,YAAYgD,cAGR,SAAf3I,YAAyBkK,QAAS,KAC9BK,QAAUL,QAAQlB,cAAc,sCAEhCuB,oCACSP,4CACAC,YAAY5N,OAAQkO,MAAAA,eAAAA,QAASC,cAAepB,UAAW/K,8CAG3D2L,4CACAC,YAAY5N,OAAQsM,aAAcS,UAAW/K,kBA1C7B,KACzBoM,cAAgBhI,SAASuG,cAAc,8CACvCyB,eACAA,cAAcZ,SAGbpH,SAASuG,cAAe,IAAGC,eAC5BN,aAAaF,MAAMqB,UAAY,MAC/BrH,SAASuG,cAAc,wCAAwCe,QAAQpB,yCAGlEqB,4CACAC,YAAY5N,OAAQsM,aAAcS,UAAW/K,gBA3F1DqM,CAAatC,YAAaP,WAAYC,gBAEjC,IAAIE,SAASF,WAAY,OACpBmB,UAAY,yBAA2BjB,MACvC2C,UAAa,uBAAsB3C,QAEzCP,YAAYxI,MAAM2L,MACPC,WAAWD,KAAMnI,SAASuG,cAAe,IAAGC,aAAc0B,aAClErL,OAAMC,OAASf,OAAOgB,QAAQD,MAAMA,6BAEpC,IAAG0J,aAAa7H,GAAG,cAAc,+BAC9B0J,MAAMC,IAAI,WAAY,gCACrB,IAAGJ,aAAaI,IAAIC,2CAGxB,IAAG/B,aAAa7H,GAAG,cAAc,+BAC7B,IAAGuJ,aAAaI,IAAI,UAAW,YAG5C,MAAOxL,OACLf,OAAOgB,QAAQD,MAAM,mCAAoCA,iBAmHxDsL,WAAWD,KAAMxC,YAAauC,eAE/BlI,SAASuG,cAAe,IAAG2B,cAG3BvC,YAAa,OAEP6C,YAAcxI,SAASiD,cAAc,QACrCwF,YAAczI,SAASiD,cAAc,QACrCyF,UAAY1I,SAASiD,cAAc,MACnC0F,aAAe3I,SAASiD,cAAc,UAE5CuF,YAAYxC,MAAMC,QAAU,OAC5B0C,aAAa3E,YAAcmE,KAAKlD,YAChC0D,aAAa3C,MAAM4C,SAAW,OAC9BD,aAAa3C,MAAM6C,WAAa,OAChCJ,YAAYzE,YAAcmE,KAAKjD,UAC/BuD,YAAYzC,MAAM4C,SAAW,OAE7BJ,YAAYxN,GAAKkN,UACjBM,YAAY/C,UAAUC,IAAK,UAC3B8C,YAAYtF,YAAYyF,cACxBH,YAAYtF,YAAYwF,WACxBF,YAAYtF,YAAYuF,aACxB9C,YAAYzC,YAAYsF,cArhBhC5O,OAAO+E,GAAG,SAAU/E,SAChBmL,oBACIrD,SAAWM,kBAAiB,GAChCpI,OAAO+H,cAAgBD,SAASC,cAChC/H,OAAOgI,WAAaF,SAASE,WAC7Bb,aAAa,QAASnH,WAE1BA,OAAO+E,GAAG,SAASX,MAAAA,IACf+G,sBACMlD,eAAiBjD,EAAEkK,eAAiBlK,EAAEmK,cAAcD,eAAeE,QAAQ,YAC5EnH,2BAICoH,qBAAuBpH,cAAc1B,OACrC+I,mBAAqB9M,aAAaC,QAAQ,sBAC1C8M,gBAAkBD,oBAAsBD,uBAAyBC,sBAEnE7O,WAAaE,aAAc,IAEL,UAAlBqD,qBACKuL,iBAeLtL,kBAAmB,OACnBC,gBAAiB,KAfbc,EAAEC,iBACFhB,kBAAmB,EACnBC,gBAAiB,EACjBc,EAAEwK,kBACFxK,EAAEyK,+CACQ,gBAAiB,gBAAgB7M,MAAK6D,KACtCzG,OAAO0P,cAAchJ,MAAMD,OAClCxD,OAAMC,OAASf,OAAOgB,QAAQD,MAAMA,cACvCsB,YAAW,KACPN,gBAAiB,EACjBD,kBAAmB,IACpB,SAOW,gBAAlBD,qBACKuL,kBACDvK,EAAEC,iBACFD,EAAEwK,kBACFxK,EAAEyK,2BACFnK,iBAEJpB,gBAAiB,GAIzBA,gBAAiB,KAErBlE,OAAO+E,GAAG,QAAQX,MAAAA,IACd+G,gBACI1K,WAAaE,cACb2E,cAGRtF,OAAO+E,GAAG,WAAY/E,SAClBmL,oBACuC,MAAfnL,OAAOyH,KAA8B,MAAfzH,OAAOyH,OACpDzH,OAAO2P,SAAW3P,OAAO4P,UACJnP,WAAaE,cAAkC,UAAlBqD,gBAA8BE,2BAC7EM,YAAW,KACPN,gBAAiB,IAClB,SAGH4D,SAAWM,mBACfpI,OAAO+H,cAAgBD,SAASC,cAChC/H,OAAOgI,WAAaF,SAASE,WAC7Bb,aAAa,UAAWnH,WAE3BA,OAAO+E,GAAG,OAAO,WACR8K,gBAAkB7P,OAAOwI,UAAUyC,WAAW,CAACC,OAAQ,SAC7D1I,aAAaM,QAAQ,qBAAsB+M,gBAAgBtJ,WAE/DvG,OAAO+E,GAAG,QAAQ,WACR8K,gBAAkB7P,OAAOwI,UAAUyC,WAAW,CAACC,OAAQ,SAC7D1I,aAAaM,QAAQ,qBAAsB+M,gBAAgBtJ,WAE/DvG,OAAO+E,GAAG,aAAaX,MAAAA,SACnBI,YAAW,KACP2D,oBAAoBnI,QACpBmH,aAAa,YAAanH,UAC3B,MAEPA,OAAO+E,GAAG,WAAWX,MAAAA,SACjBI,YAAW,KACP2D,oBAAoBnI,QACpBmH,aAAa,UAAWnH,UACzB,OAEPA,OAAO+E,GAAG,QAAQ,KACdoG,gBACA3I,aAAa6C,WAAW,yBAE5BrF,OAAO+E,GAAG,cAAc,KACpBoG,mBAEJnL,OAAO+E,GAAG,0BAA2BC,QAC7B8K,KAAO,IAAIC,uBAAa9N,KAAM5B,QAASC,WAAYqD,WAAY3D,OAAQO,UAC3EyB,aAAegD,EAAEgL,UAERhL,EAAEgL,MAGHF,KAAKG,eAFLH,KAAKI,aAIX,MAAOhN,OACDa,aACAA,YAAa,sBACH,gBAAiB,gBAAgBnB,MAAK6D,KACrCzG,OAAO0P,cAAchJ,MAAMD,OACnCxD,OAAMC,OAASf,OAAOgB,QAAQD,MAAMA,UAE3C4M,KAAKI,aACL/N,OAAOgB,QAAQD,MAAM,4BAA6BA,WAI1DlD,OAAO+E,GAAG,eAAe,SAASC,MACZ,qBAAdA,EAAEmL,QAAgC,OAC5BC,WAAapL,EAAEsB,MAEf+J,QAAUD,YAAoC,iBAAfA,aAAgD,IAArBA,WAAWE,UAEvEC,gBAAkBH,WAAWI,SAAWJ,WACxChH,QAAUhD,SAASiD,cAAc,OACrCD,QAAQqH,UAAYF,oBAChBhC,KAAOnF,QAAQgB,aAAehB,QAAQI,WAAa,GACnDkH,WAAatH,QAAQgB,aAAehB,QAAQI,WAAa,GAEzD1B,SAAWM,kBAAiB,MAChCpI,OAAO+H,cAAgBD,SAASC,cAChC/H,OAAOgI,WAAaF,SAASE,WAEzBqI,QAAS,IACLpM,wBACAA,kBAAmB,EACnBe,EAAEC,sBACFjF,OAAO2Q,YAAYC,aAGjBtB,mBAAqB9M,aAAaC,QAAQ,sBAC1C8M,gBAAkBD,oBAAsBoB,WAAWnK,SAAW+I,sBAEhE7O,WAAaE,cAAkC,UAAlBqD,gBAA8BuL,uBAC3DrL,gBAAiB,OACjBlE,OAAO2Q,YAAYC,OAIvBzJ,aAAa,QAAS,CAClBM,IAAK,IACLC,QAAS,GACTK,cAAe/H,OAAO+H,cACtBC,WAAYhI,OAAOgI,WACnBC,cAAeyI,WACfG,WAAY,CAACC,QAAS3O,OAAOC,SAASC,aAG1CN,WAAWyF,KAAK+G,MAEhBpH,aAAa,WAAY,CACrBM,IAAK,KACLC,QAAS,EACTK,cAAe/H,OAAO+H,cACtBC,WAAYhI,OAAOgI,WACnBE,UAAWqG,KACXsC,WAAY,CAACC,QAAS3O,OAAOC,SAASC,YAMtDrC,OAAO+E,GAAG,SAAS,SAASC,OACpB8C,SAAWM,kBAAiB,GAChCpI,OAAO+H,cAAgBD,SAASC,cAChC/H,OAAOgI,WAAaF,SAASE,eACzBE,UAAYlD,EAAEsC,MAEE,0BAAhBtC,EAAE+L,WAA0D,eAAhB/L,EAAE+L,WAA8B7I,WAAaA,UAAUoC,OAAS,KAE5GvI,WAAWyF,KAAKU,WAEhBlD,EAAEyC,IAAM,KACRzC,EAAE0C,QAAU,EACZ1C,EAAE+C,cAAgBD,SAASC,cAC3B/C,EAAEgD,WAAaF,SAASE,WACxBhD,EAAEkD,UAAYA,UAEdf,aAAa,WAAYnC,OAsbjC7C,OAAO6O,iBAAiB,UAAU,KAC9B9L,cAGJ+L,YAAY/L,SAAUrD"} \ No newline at end of file +{"version":3,"file":"autosaver.min.js","sources":["../src/autosaver.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 * @module tiny_cursive/autosaver\n * @category TinyMCE Editor\n * @copyright CTI \n * @author Brain Station 23 \n */\n\nimport {call} from 'core/ajax';\nimport {create} from 'core/modal_factory';\nimport {get_string as getString} from 'core/str';\nimport {save, cancel, hidden} from 'core/modal_events';\nimport $ from 'jquery';\nimport {iconUrl, iconGrayUrl, tooltipCss} from 'tiny_cursive/common';\nimport Autosave from 'tiny_cursive/cursive_autosave';\nimport DocumentView from 'tiny_cursive/document_view';\nimport {call as getUser} from \"core/ajax\";\n\nexport const register = (editor, interval, userId, hasApiKey, MODULES, Rubrics, submission, quizInfo, pasteSetting) => {\n\n var isStudent = !($('#body').hasClass('teacher_admin'));\n var intervention = $('#body').hasClass('intervention');\n var host = M.cfg.wwwroot;\n var userid = userId;\n var courseid = M.cfg.courseId;\n var editorid = editor?.id;\n var cmid = M.cfg.contextInstanceId;\n var ed = \"\";\n var event = \"\";\n var filename = \"\";\n var questionid = 0;\n var quizSubmit = $('#mod_quiz-next-nav');\n let assignSubmit = $('#id_submitbutton');\n var syncInterval = interval ? interval * 1000 : 10000; // Default: Sync Every 10s.\n var lastCaretPos = 1;\n let aiContents = [];\n var isFullScreen = false;\n var user = null;\n let ur = window.location.href;\n let parm = new URL(ur);\n let modulesInfo = getModulesInfo(ur, parm, MODULES);\n var resourceId = modulesInfo.resourceId;\n var modulename = modulesInfo.name;\n var errorAlert = true;\n let PASTE_SETTING = pasteSetting || 'allow';\n let shouldBlockPaste = false;\n let isPasteAllowed = false;\n\n if (ur.includes('pdfannotator')) {\n document.addEventListener('click', e => {\n if (e.target.className === \"dropdown-item comment-edit-a\") {\n let id = e.target.id;\n resourceId = id.replace('editButton', '');\n localStorage.setItem('isEditing', '1');\n }\n if (e.target.id === 'commentSubmit') {\n syncData();\n }\n });\n }\n\n const postOne = async(methodname, args) => {\n try {\n const response = await call([{\n methodname,\n args,\n }])[0];\n if (response) {\n setTimeout(() => {\n Autosave.updateSavingState('saved');\n }, 1000);\n }\n return response;\n } catch (error) {\n Autosave.updateSavingState('offline');\n window.console.error('Error in postOne:', error);\n throw error;\n }\n };\n\n getUser([{\n methodname: 'core_user_get_users_by_field',\n args: {field: 'id', values: [userid]},\n }])[0].done(response => {\n user = response[0];\n }).fail((ex) => {\n window.console.error('Error fetching user data:', ex);\n });\n\n assignSubmit.on('click', async function(e) {\n e.preventDefault();\n if (filename) {\n // eslint-disable-next-line\n syncData().then(() => {\n assignSubmit.off('click').click();\n });\n } else {\n assignSubmit.off('click').click();\n }\n localStorage.removeItem('lastCopyCutContent');\n });\n\n quizSubmit.on('click', async function(e) {\n e.preventDefault();\n if (filename) {\n // eslint-disable-next-line\n syncData().then(() => {\n quizSubmit.off('click').click();\n });\n } else {\n quizSubmit.off('click').click();\n }\n localStorage.removeItem('lastCopyCutContent');\n });\n\n const getModal = () => {\n\n Promise.all([\n getString('tiny_cursive_srcurl', 'tiny_cursive'),\n getString('tiny_cursive_srcurl_des', 'tiny_cursive'),\n getString('tiny_cursive_placeholder', 'tiny_cursive')\n ]).then(function([title, titledes, placeholder]) {\n\n return create({\n type: 'SAVE_CANCEL',\n title: `
${title}
\n ${titledes}
`,\n body: ``,\n removeOnClose: true,\n })\n .done(modal => {\n modal.getRoot().addClass('tiny-cursive-modal');\n modal.show();\n var lastEvent = '';\n\n modal.getRoot().on(save, function() {\n\n var number = document.getElementById(\"inputUrl\").value.trim();\n\n if (number === \"\" || number === null || number === undefined) {\n editor.execCommand('Undo');\n // eslint-disable-next-line\n getString('pastewarning', 'tiny_cursive').then(str => alert(str));\n } else {\n editor.execCommand('Paste');\n }\n\n postOne('cursive_user_comments', {\n modulename: modulename,\n cmid: cmid,\n resourceid: resourceId,\n courseid: courseid,\n usercomment: number,\n timemodified: Date.now(),\n editorid: editorid ? editorid : \"\"\n });\n\n lastEvent = 'save';\n modal.destroy();\n });\n modal.getRoot().on(cancel, function() {\n editor.execCommand('Undo');\n lastEvent = 'cancel';\n });\n\n modal.getRoot().on(hidden, function() {\n if (lastEvent != 'cancel' && lastEvent != 'save') {\n editor.execCommand('Undo');\n }\n });\n return modal;\n });\n }).catch(error => window.console.error(error));\n\n };\n\n const sendKeyEvent = (events, editor) => {\n ed = editor;\n event = events;\n\n filename = `${userid}_${resourceId}_${cmid}_${modulename}_attempt`;\n\n if (modulename === 'quiz') {\n questionid = editorid.split(':')[1].split('_')[0];\n filename = `${userid}_${resourceId}_${cmid}_${questionid}_${modulename}_attempt`;\n }\n\n if (localStorage.getItem(filename)) {\n let data = JSON.parse(localStorage.getItem(filename));\n data.push({\n resourceId: resourceId,\n key: editor.key,\n keyCode: editor.keyCode,\n event: event,\n courseId: courseid,\n unixTimestamp: Date.now(),\n clientId: host,\n personId: userid,\n position: ed.caretPosition,\n rePosition: ed.rePosition,\n pastedContent: editor.pastedContent,\n aiContent: editor.aiContent\n });\n localStorage.setItem(filename, JSON.stringify(data));\n } else {\n let data = [{\n resourceId: resourceId,\n key: editor.key,\n keyCode: editor.keyCode,\n event: event,\n courseId: courseid,\n unixTimestamp: Date.now(),\n clientId: host,\n personId: userid,\n position: ed.caretPosition,\n rePosition: ed.rePosition,\n pastedContent: editor.pastedContent,\n aiContent: editor.aiContent\n }];\n localStorage.setItem(filename, JSON.stringify(data));\n }\n };\n\n editor.on('keyUp', (editor) => {\n customTooltip();\n let position = getCaretPosition(false);\n editor.caretPosition = position.caretPosition;\n editor.rePosition = position.rePosition;\n sendKeyEvent(\"keyUp\", editor);\n });\n editor.on('Paste', async(e) => {\n customTooltip();\n const pastedContent = (e.clipboardData || e.originalEvent.clipboardData).getData('text');\n if (!pastedContent) {\n return;\n }\n // Trim both values for consistent comparison\n const trimmedPastedContent = pastedContent.trim();\n const lastCopyCutContent = localStorage.getItem('lastCopyCutContent');\n const isFromOwnEditor = lastCopyCutContent && trimmedPastedContent === lastCopyCutContent;\n\n if (isStudent && intervention) {\n\n if (PASTE_SETTING === 'block') {\n if (!isFromOwnEditor) {\n e.preventDefault();\n shouldBlockPaste = true;\n isPasteAllowed = false;\n e.stopPropagation();\n e.stopImmediatePropagation();\n getString('paste_blocked', 'tiny_cursive').then(str => {\n return editor.windowManager.alert(str);\n }).catch(error => window.console.error(error));\n setTimeout(() => {\n isPasteAllowed = true;\n shouldBlockPaste = false;\n }, 100);\n return;\n }\n shouldBlockPaste = false;\n isPasteAllowed = true;\n return;\n }\n if (PASTE_SETTING === 'cite_source') {\n if (!isFromOwnEditor) {\n e.preventDefault();\n e.stopPropagation();\n e.stopImmediatePropagation();\n getModal(e);\n }\n isPasteAllowed = true;\n return;\n }\n }\n isPasteAllowed = true;\n });\n editor.on('Redo', async(e) => {\n customTooltip();\n if (isStudent && intervention) {\n getModal(e);\n }\n });\n editor.on('keyDown', (editor) => {\n customTooltip();\n const isPasteAttempt = (editor.key === 'v' || editor.key === 'V') &&\n (editor.ctrlKey || editor.metaKey);\n if (isPasteAttempt && isStudent && intervention && PASTE_SETTING === 'block' && !isPasteAllowed) {\n setTimeout(() => {\n isPasteAllowed = true;\n }, 100);\n return;\n }\n let position = getCaretPosition();\n editor.caretPosition = position.caretPosition;\n editor.rePosition = position.rePosition;\n sendKeyEvent(\"keyDown\", editor);\n });\n editor.on('Cut', () => {\n const selectedContent = editor.selection.getContent({format: 'text'});\n localStorage.setItem('lastCopyCutContent', selectedContent.trim());\n });\n editor.on('Copy', () => {\n const selectedContent = editor.selection.getContent({format: 'text'});\n localStorage.setItem('lastCopyCutContent', selectedContent.trim());\n });\n editor.on('mouseDown', async(editor) => {\n setTimeout(() => {\n constructMouseEvent(editor);\n sendKeyEvent(\"mouseDown\", editor);\n }, 0);\n });\n editor.on('mouseUp', async(editor) => {\n setTimeout(() => {\n constructMouseEvent(editor);\n sendKeyEvent(\"mouseUp\", editor);\n }, 10);\n });\n editor.on('init', () => {\n customTooltip();\n localStorage.removeItem('lastCopyCutContent');\n });\n editor.on('SetContent', () => {\n customTooltip();\n });\n editor.on('FullscreenStateChanged', (e) => {\n let view = new DocumentView(user, Rubrics, submission, modulename, editor, quizInfo);\n isFullScreen = e.state;\n try {\n if (!e.state) {\n view.normalMode();\n } else {\n view.fullPageMode();\n }\n } catch (error) {\n if (errorAlert) {\n errorAlert = false;\n getString('fullmodeerror', 'tiny_cursive').then(str => {\n return editor.windowManager.alert(str);\n }).catch(error => window.console.error(error));\n }\n view.normalMode();\n window.console.error('Error ResizeEditor event:', error);\n }\n });\n\n editor.on('execcommand', function(e) {\n if (e.command === \"mceInsertContent\") {\n const contentObj = e.value;\n\n const isPaste = contentObj && typeof contentObj === 'object' && contentObj.paste === true;\n\n let insertedContent = contentObj.content || contentObj;\n let tempDiv = document.createElement('div');\n tempDiv.innerHTML = insertedContent;\n let text = tempDiv.textContent || tempDiv.innerText || '';\n let pastedText = tempDiv.textContent || tempDiv.innerText || '';\n\n let position = getCaretPosition(true);\n editor.caretPosition = position.caretPosition;\n editor.rePosition = position.rePosition;\n\n if (isPaste) {\n if (shouldBlockPaste) {\n shouldBlockPaste = false;\n e.preventDefault();\n editor.undoManager.undo();\n return;\n }\n const lastCopyCutContent = localStorage.getItem('lastCopyCutContent');\n const isFromOwnEditor = lastCopyCutContent && pastedText.trim() === lastCopyCutContent;\n\n if (isStudent && intervention && PASTE_SETTING === 'block' && !isFromOwnEditor) {\n isPasteAllowed = false;\n editor.undoManager.undo();\n return;\n }\n\n sendKeyEvent(\"Paste\", {\n key: \"v\",\n keyCode: 86,\n caretPosition: editor.caretPosition,\n rePosition: editor.rePosition,\n pastedContent: pastedText,\n srcElement: {baseURI: window.location.href}\n });\n } else {\n aiContents.push(text);\n\n sendKeyEvent(\"aiInsert\", {\n key: \"ai\",\n keyCode: 0,\n caretPosition: editor.caretPosition,\n rePosition: editor.rePosition,\n aiContent: text,\n srcElement: {baseURI: window.location.href}\n });\n }\n }\n });\n\n editor.on('input', function(e) {\n let position = getCaretPosition(true);\n editor.caretPosition = position.caretPosition;\n editor.rePosition = position.rePosition;\n let aiContent = e.data;\n\n if (e.inputType === 'insertReplacementText' || (e.inputType === 'insertText' && aiContent && aiContent.length > 1)) {\n\n aiContents.push(aiContent);\n\n e.key = \"ai\";\n e.keyCode = 0;\n e.caretPosition = position.caretPosition;\n e.rePosition = position.rePosition;\n e.aiContent = aiContent;\n\n sendKeyEvent(\"aiInsert\", e);\n }\n });\n\n\n /**\n * Constructs a mouse event object with caret position and button information\n * @param {Object} editor - The TinyMCE editor instance\n * @function constructMouseEvent\n * @description Sets caret position, reposition, key and keyCode properties on the editor object based on current mouse state\n */\n function constructMouseEvent(editor) {\n let position = getCaretPosition(false);\n editor.caretPosition = position.caretPosition;\n editor.rePosition = position.rePosition;\n editor.key = getMouseButton(editor);\n editor.keyCode = editor.button;\n }\n\n /**\n * Gets the string representation of a mouse button based on its numeric value\n * @param {Object} editor - The editor object containing button information\n * @returns {string} The string representation of the mouse button ('left', 'middle', or 'right')\n */\n function getMouseButton(editor) {\n\n switch (editor.button) {\n case 0:\n return 'left';\n case 1:\n return 'middle';\n case 2:\n return 'right';\n }\n return null;\n }\n\n /**\n * Gets the current caret position in the editor\n * @param {boolean} skip - If true, returns the last known caret position instead of calculating a new one\n * @returns {Object} Object containing:\n * - caretPosition: Sequential position number stored in session\n * - rePosition: Absolute character offset from start of content\n * @throws {Error} Logs warning to console if error occurs during calculation\n */\n function getCaretPosition(skip = false) {\n try {\n if (!editor || !editor.selection) {\n return {caretPosition: 0, rePosition: 0};\n }\n\n const range = editor.selection.getRng();\n const body = editor.getBody();\n\n // Create a range from start of document to current caret\n const preCaretRange = range.cloneRange();\n preCaretRange.selectNodeContents(body);\n preCaretRange.setEnd(range.endContainer, range.endOffset);\n\n const fragment = preCaretRange.cloneContents();\n const tempDiv = document.createElement('div');\n tempDiv.appendChild(fragment);\n let textBeforeCursor = tempDiv.innerText || '';\n\n const endContainer = range.endContainer;\n const endOffset = range.endOffset;\n\n if (endOffset === 0 &&\n endContainer.nodeType === Node.ELEMENT_NODE &&\n editor.dom.isBlock(endContainer) &&\n endContainer.previousSibling) {\n textBeforeCursor += '\\n';\n }\n const blockElements = tempDiv.querySelectorAll('p, div, h1, h2, h3, h4, h5, h6, li');\n let emptyBlockCount = 0;\n blockElements.forEach(block => {\n const text = block.innerText || block.textContent || '';\n if (text.trim() === '' && block.childNodes.length === 1 &&\n block.childNodes[0].nodeName === 'BR') {\n emptyBlockCount++;\n }\n });\n\n // Add newlines for empty blocks (these represent Enter presses that created empty lines)\n if (emptyBlockCount > 0) {\n textBeforeCursor += '\\n'.repeat(emptyBlockCount);\n }\n\n const absolutePosition = textBeforeCursor.length;\n\n if (skip) {\n return {\n caretPosition: lastCaretPos,\n rePosition: absolutePosition\n };\n }\n // Increment sequential caretPosition\n const storageKey = `${userid}_${resourceId}_${cmid}_position`;\n let storedPos = parseInt(sessionStorage.getItem(storageKey), 10);\n if (isNaN(storedPos)) {\n storedPos = 0;\n }\n storedPos++;\n lastCaretPos = storedPos;\n sessionStorage.setItem(storageKey, storedPos);\n\n return {\n caretPosition: storedPos,\n rePosition: absolutePosition\n };\n\n } catch (e) {\n window.console.warn('Error getting caret position:', e);\n return {caretPosition: lastCaretPos || 1, rePosition: 0};\n }\n }\n\n\n /**\n * Synchronizes data from localStorage to server\n * @async\n * @function SyncData\n * @description Retrieves stored keypress data from localStorage and sends it to server\n * @returns {Promise} Returns response from server if data exists and is successfully sent\n * @throws {Error} Logs error to console if data submission fails\n */\n async function syncData() {\n checkIsPdfAnnotator();\n let data = localStorage.getItem(filename);\n\n if (!data || data.length === 0) {\n return;\n } else {\n localStorage.removeItem(filename);\n editor.fire('change');\n let originalText = editor.getContent({format: 'text'});\n if (!originalText) {\n originalText = getRawText(editor);\n }\n try {\n Autosave.updateSavingState('saving');\n // eslint-disable-next-line\n return await postOne('cursive_write_local_to_json', {\n key: ed.key,\n event: event,\n keyCode: ed.keyCode,\n resourceId: resourceId,\n cmid: cmid,\n modulename: modulename,\n editorid: editorid,\n \"json_data\": data,\n originalText: originalText\n });\n } catch (error) {\n window.console.error('Error submitting data:', error);\n }\n }\n }\n\n /**\n * Gets the raw text content from a TinyMCE editor iframe\n * @param {Object} editor - The TinyMCE editor instance\n * @returns {string} The raw text content of the editor body, or empty string if not found\n * @description Attempts to get the raw text content from the editor's iframe body by:\n * 1. Getting the editor ID\n * 2. Finding the associated iframe element\n * 3. Accessing the iframe's document body\n * 4. Returning the text content\n * Returns empty string if any step fails\n */\n function getRawText(editor) {\n let editorId = editor?.id;\n if (editorId) {\n let iframe = document.querySelector(`#${editorId}_ifr`);\n let iframeBody = iframe.contentDocument?.body || iframe.contentWindow?.document?.body;\n return iframeBody?.textContent;\n }\n return \"\";\n }\n\n /**\n * Sets up custom tooltip functionality for the Cursive icon\n * Initializes tooltip text, positions the icon in the menubar,\n * and sets up mouse event handlers for showing/hiding the tooltip\n * @function customTooltip\n */\n function customTooltip() {\n try {\n const tooltipText = getTooltipText();\n const menubarDiv = document.querySelectorAll('div[role=\"menubar\"].tox-menubar');\n let classArray = [];\n\n if (menubarDiv.length) {\n menubarDiv.forEach(function(element, index) {\n index += 1;\n let className = 'cursive-menu-' + index;\n element.classList.add(className);\n classArray.push(className);\n });\n }\n\n const cursiveIcon = document.createElement('img');\n cursiveIcon.src = hasApiKey ? iconUrl : iconGrayUrl;\n\n cursiveIcon.setAttribute('class', 'tiny_cursive_StateButton');\n cursiveIcon.style.display = 'inline-block';\n\n cursiveState(cursiveIcon, menubarDiv, classArray);\n\n for (let index in classArray) {\n const elementId = \"tiny_cursive_StateIcon\" + index;\n const tooltipId = `tiny_cursive_tooltip${index}`;\n\n tooltipText.then((text) => {\n return setTooltip(text, document.querySelector(`#${elementId}`), tooltipId);\n }).catch(error => window.console.error(error));\n\n $(`#${elementId}`).on('mouseenter', function() {\n $(this).css('position', 'relative');\n $(`#${tooltipId}`).css(tooltipCss);\n });\n\n $(`#${elementId}`).on('mouseleave', function() {\n $(`#${tooltipId}`).css('display', 'none');\n });\n }\n } catch (error) {\n window.console.error('Error setting up custom tooltip:', error);\n }\n }\n\n /**\n * Retrieves tooltip text strings from language files\n * @async\n * @function getTooltipText\n * @returns {Promise} Object containing buttonTitle and buttonDes strings\n */\n async function getTooltipText() {\n const [\n buttonTitle,\n buttonDes,\n ] = await Promise.all([\n getString('cursive:state:active', 'tiny_cursive'),\n getString('cursive:state:active:des', 'tiny_cursive'),\n ]);\n return {buttonTitle, buttonDes};\n }\n\n /**\n * Updates the Cursive icon state and positions it in the menubar\n * @param {HTMLElement} cursiveIcon - The Cursive icon element to modify\n * @param {HTMLElement} menubarDiv - The menubar div element\n * @param {Array} classArray - Array of class names for the menubar div elements\n */\n function cursiveState(cursiveIcon, menubarDiv, classArray) {\n if (!menubarDiv) {\n return;\n }\n\n for (let index in classArray) {\n const rightWrapper = document.createElement('div');\n const imgWrapper = document.createElement('span');\n const iconClone = cursiveIcon.cloneNode(true);\n const targetMenu = document.querySelector('.' + classArray[index]);\n let elementId = \"tiny_cursive_StateIcon\" + index;\n\n rightWrapper.style.cssText = `\n margin-left: auto;\n display: flex;\n align-items: center;\n `;\n\n imgWrapper.id = elementId;\n imgWrapper.style.marginLeft = '.2rem';\n imgWrapper.appendChild(iconClone);\n rightWrapper.appendChild(imgWrapper);\n\n let moduleIds = {\n resourceId: resourceId,\n cmid: cmid,\n modulename: modulename,\n questionid: questionid,\n userid: userid,\n courseid: courseid};\n // Document mode, other modules single editor instances\n if (isFullScreen && (modulename === 'assign' || modulename === 'forum'\n || modulename === 'lesson')) {\n let existsElement = document.querySelector('.tox-menubar[class*=\"cursive-menu-\"] > div');\n if (existsElement) {\n existsElement.remove();\n }\n\n if (!document.querySelector(`#${elementId}`)) {\n rightWrapper.style.marginTop = '3px';\n document.querySelector('#tiny_cursive-fullpage-right-wrapper').prepend(rightWrapper);\n }\n\n Autosave.destroyInstance();\n Autosave.getInstance(editor, rightWrapper, moduleIds, isFullScreen);\n } else if (isFullScreen && modulename === 'quiz') { // Document mode, quiz multiple editor instances\n let existingElement = editor.container?.childNodes[1]?.childNodes[0]?.childNodes[0]?.childNodes[7];\n let newHeader = editor.container?.childNodes[0];\n if (existingElement) {\n existingElement.remove();\n }\n\n if (newHeader && !newHeader.querySelector(`span[id*=tiny_cursive_StateIcon]`)) {\n rightWrapper.style.marginTop = '3px';\n document.querySelector('#tiny_cursive-fullpage-right-wrapper').prepend(rightWrapper);\n }\n Autosave.destroyInstance();\n Autosave.getInstance(editor, rightWrapper, moduleIds, isFullScreen);\n } else { // Regular view\n let menubar = editor?.container?.children[0]?.childNodes[0]?.childNodes[0];\n\n if (targetMenu && !targetMenu.querySelector(`#${elementId}`)) {\n targetMenu.appendChild(rightWrapper);\n }\n // Regular view, multiple editor instances\n if (modulename === 'quiz' && menubar) {\n let wrapper = menubar.querySelector('span[id*=\"tiny_cursive_StateIcon\"]');\n\n if (wrapper) {\n Autosave.destroyInstance();\n Autosave.getInstance(editor, wrapper?.parentElement, moduleIds, isFullScreen);\n }\n } else {\n Autosave.destroyInstance();\n Autosave.getInstance(editor, rightWrapper, moduleIds, isFullScreen);\n }\n }\n }\n }\n\n /**\n * Sets up tooltip content and styling for the Cursive icon\n * @param {Object} text - Object containing tooltip text strings\n * @param {string} text.buttonTitle - Title text for the tooltip\n * @param {string} text.buttonDes - Description text for the tooltip\n * @param {HTMLElement} cursiveIcon - The Cursive icon element to attach tooltip to\n * @param {string} tooltipId - ID for the tooltip element\n */\n function setTooltip(text, cursiveIcon, tooltipId) {\n\n if (document.querySelector(`#${tooltipId}`)) {\n return;\n }\n if (cursiveIcon) {\n\n const tooltipSpan = document.createElement('span');\n const description = document.createElement('span');\n const linebreak = document.createElement('br');\n const tooltipTitle = document.createElement('strong');\n\n tooltipSpan.style.display = 'none';\n tooltipTitle.textContent = text.buttonTitle;\n tooltipTitle.style.fontSize = '16px';\n tooltipTitle.style.fontWeight = 'bold';\n description.textContent = text.buttonDes;\n description.style.fontSize = '14px';\n\n tooltipSpan.id = tooltipId;\n tooltipSpan.classList.add(`shadow`);\n tooltipSpan.appendChild(tooltipTitle);\n tooltipSpan.appendChild(linebreak);\n tooltipSpan.appendChild(description);\n cursiveIcon.appendChild(tooltipSpan);\n }\n }\n\n /**\n * Extracts module information from URL parameters\n * @param {string} ur - The base URL to analyze\n * @param {URL} parm - URL object containing search parameters\n * @param {Array} MODULES - Array of valid module names to check against\n * @returns {Object|boolean} Object containing resourceId and module name if found, false if no valid module\n */\n function getModulesInfo(ur, parm, MODULES) {\n fetchStrings();\n\n if (!MODULES.some(module => ur.includes(module))) {\n return false;\n }\n\n if (ur.includes(\"forum\") && !ur.includes(\"assign\")) {\n resourceId = parm.searchParams.get('edit');\n } else {\n resourceId = parm.searchParams.get('attempt');\n }\n\n if (resourceId === null) {\n resourceId = 0;\n }\n\n for (const module of MODULES) {\n if (ur.includes(module)) {\n modulename = module;\n if (module === \"lesson\" || module === \"assign\") {\n resourceId = cmid;\n } else if (module === \"oublog\") {\n resourceId = 0;\n }\n break;\n }\n }\n\n checkIsPdfAnnotator();\n\n return {resourceId: resourceId, name: modulename};\n }\n\n /**\n * Fetches and caches localized strings used in the UI\n * @function fetchStrings\n * @description Retrieves strings for sidebar titles and document sidebar elements if not already cached in localStorage\n * Uses Promise.all to fetch multiple strings in parallel for better performance\n * Stores the fetched strings in localStorage under 'sbTitle' and 'docSideBar' keys\n */\n function fetchStrings() {\n if (!localStorage.getItem('sbTitle')) {\n Promise.all([\n getString('assignment', 'tiny_cursive'),\n getString('discussion', 'tiny_cursive'),\n getString('pluginname', 'mod_quiz'),\n getString('pluginname', 'mod_lesson'),\n getString('description', 'tiny_cursive'),\n ]).then(function(strings) {\n return localStorage.setItem('sbTitle', JSON.stringify(strings));\n }).catch(error => window.console.error(error));\n }\n if (!localStorage.getItem('docSideBar')) {\n Promise.all([\n getString('details', 'tiny_cursive'),\n getString('student_info', 'tiny_cursive'),\n getString('progress', 'tiny_cursive'),\n getString('description', 'tiny_cursive'),\n getString('replyingto', 'tiny_cursive'),\n getString('answeringto', 'tiny_cursive'),\n getString('importantdates', 'tiny_cursive'),\n getString('rubrics', 'tiny_cursive'),\n getString('submission_status', 'tiny_cursive'),\n getString('status', 'tiny_cursive'),\n getString('draft', 'tiny_cursive'),\n getString('draftnot', 'tiny_cursive'),\n getString('last_modified', 'tiny_cursive'),\n getString('gradings', 'tiny_cursive'),\n getString('gradenot', 'tiny_cursive'),\n getString('word_count', 'tiny_cursive'),\n getString('timeleft', 'tiny_cursive'),\n getString('nolimit', 'tiny_cursive'),\n getString('name', 'tiny_cursive'),\n getString('userename', 'tiny_cursive'),\n getString('course', 'tiny_cursive'),\n getString('opened', 'tiny_cursive'),\n getString('due', 'tiny_cursive'),\n getString('overdue', 'tiny_cursive'),\n getString('remaining', 'tiny_cursive'),\n getString('savechanges', 'tiny_cursive'),\n getString('subjectnot', 'tiny_cursive'),\n getString('remaining', 'tiny_cursive'),\n ]).then(function(strings) {\n return localStorage.setItem('docSideBar', JSON.stringify(strings));\n }).catch(error => window.console.error(error));\n }\n\n }\n\n /**\n * Checks if the current page is a PDF annotator and updates the resourceId accordingly\n * @function checkIsPdfAnnotator\n * @description Checks if URL contains 'pdfannotator' and sets resourceId based on editor ID and editing state:\n * - If editing an existing annotation (editor.id !== 'id_pdfannotator_content' and isEditing is true):\n * Sets resourceId to the annotation ID extracted from editor.id\n * - Otherwise: Sets resourceId to 0\n */\n function checkIsPdfAnnotator() {\n if (ur.includes('pdfannotator')) {\n if (editor.id !== 'id_pdfannotator_content' && parseInt(localStorage.getItem('isEditing'))) {\n resourceId = parseInt(editor?.id.replace('editarea', ''));\n } else {\n resourceId = 0;\n }\n }\n }\n\n window.addEventListener('unload', () => {\n syncData();\n });\n\n setInterval(syncData, syncInterval);\n};\n"],"names":["editor","interval","userId","hasApiKey","MODULES","Rubrics","submission","quizInfo","pasteSetting","isStudent","hasClass","intervention","host","M","cfg","wwwroot","userid","courseid","courseId","editorid","id","cmid","contextInstanceId","ed","event","filename","questionid","quizSubmit","assignSubmit","syncInterval","lastCaretPos","aiContents","isFullScreen","user","ur","window","location","href","parm","URL","modulesInfo","localStorage","getItem","Promise","all","then","strings","setItem","JSON","stringify","catch","error","console","fetchStrings","some","module","includes","resourceId","searchParams","get","modulename","checkIsPdfAnnotator","name","getModulesInfo","errorAlert","PASTE_SETTING","shouldBlockPaste","isPasteAllowed","document","addEventListener","e","target","className","replace","syncData","postOne","async","methodname","args","response","setTimeout","updateSavingState","field","values","done","fail","ex","on","preventDefault","off","click","removeItem","getModal","title","titledes","placeholder","type","body","removeOnClose","modal","getRoot","addClass","show","lastEvent","save","number","getElementById","value","trim","execCommand","str","alert","resourceid","usercomment","timemodified","Date","now","destroy","cancel","hidden","sendKeyEvent","events","split","data","parse","push","key","keyCode","unixTimestamp","clientId","personId","position","caretPosition","rePosition","pastedContent","aiContent","constructMouseEvent","getCaretPosition","button","getMouseButton","skip","selection","range","getRng","getBody","preCaretRange","cloneRange","selectNodeContents","setEnd","endContainer","endOffset","fragment","cloneContents","tempDiv","createElement","appendChild","textBeforeCursor","innerText","nodeType","Node","ELEMENT_NODE","dom","isBlock","previousSibling","blockElements","querySelectorAll","emptyBlockCount","forEach","block","textContent","childNodes","length","nodeName","repeat","absolutePosition","storageKey","storedPos","parseInt","sessionStorage","isNaN","warn","fire","originalText","getContent","format","editorId","iframe","querySelector","iframeBody","contentDocument","contentWindow","_iframe$contentWindow","_iframe$contentWindow2","getRawText","customTooltip","tooltipText","buttonTitle","buttonDes","getTooltipText","menubarDiv","classArray","element","index","classList","add","cursiveIcon","src","iconUrl","iconGrayUrl","setAttribute","style","display","rightWrapper","imgWrapper","iconClone","cloneNode","targetMenu","elementId","cssText","marginLeft","moduleIds","existingElement","container","_editor$container","_editor$container$chi","_editor$container$chi2","_editor$container$chi3","newHeader","_editor$container2","remove","marginTop","prepend","destroyInstance","getInstance","menubar","_editor$container3","children","_editor$container3$ch","_editor$container3$ch2","wrapper","parentElement","existsElement","cursiveState","tooltipId","text","setTooltip","this","css","tooltipCss","tooltipSpan","description","linebreak","tooltipTitle","fontSize","fontWeight","clipboardData","originalEvent","getData","trimmedPastedContent","lastCopyCutContent","isFromOwnEditor","stopPropagation","stopImmediatePropagation","windowManager","ctrlKey","metaKey","selectedContent","view","DocumentView","state","fullPageMode","normalMode","command","contentObj","isPaste","paste","insertedContent","content","innerHTML","pastedText","undoManager","undo","srcElement","baseURI","inputType","setInterval"],"mappings":"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"} \ No newline at end of file diff --git a/amd/build/document_view.min.js b/amd/build/document_view.min.js index 7b04f290..dfc9c4cb 100644 --- a/amd/build/document_view.min.js +++ b/amd/build/document_view.min.js @@ -5,6 +5,6 @@ define("tiny_cursive/document_view",["exports","tiny_cursive/svg_repo"],(functio * @module tiny_cursive/document_view * @copyright 2025 Cursive Technology, Inc. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_svg_repo=(obj=_svg_repo)&&obj.__esModule?obj:{default:obj};return _exports.default=class{constructor(User,Rubrics,submission,modulename,editor,quizInfo){this.User=User,this.Rubrics=Rubrics,this.submission=submission,this.module=modulename,this.editor=editor,this.moduleIcon=_svg_repo.default.assignment,this.quizInfo=quizInfo,this.initStrings()}normalMode(){var _this$editor;let id=(null===(_this$editor=this.editor)||void 0===_this$editor?void 0:_this$editor.id)+"_ifr";("assign"===this.module||"quiz"===this.module||"forum"===this.module||"lesson"===this.module)&&this.normalizePage(id)}fullPageMode(){var _this$editor4,_this$editor2;if("assign"===this.module)this.moduleIcon=_svg_repo.default.assignment,this.fullPageModule(null===(_this$editor2=this.editor)||void 0===_this$editor2?void 0:_this$editor2.id);else if("forum"===this.module){var _this$editor3;this.moduleIcon=_svg_repo.default.forum,this.fullPageModule(null===(_this$editor3=this.editor)||void 0===_this$editor3?void 0:_this$editor3.id)}else if("quiz"===this.module&&null!==(_this$editor4=this.editor)&&void 0!==_this$editor4&&_this$editor4.id){var _this$editor5;this.moduleIcon=_svg_repo.default.quiz,this.fullPageModule(null===(_this$editor5=this.editor)||void 0===_this$editor5?void 0:_this$editor5.id)}else if("lesson"===this.module){var _this$editor6;this.moduleIcon=_svg_repo.default.lesson,this.fullPageModule(null===(_this$editor6=this.editor)||void 0===_this$editor6?void 0:_this$editor6.id)}}docSideBar(status){var _this$editor7;const replyId=new URL(window.location.href).searchParams.get("reply"),toggle=document.querySelector("#cursive-fullpagemode-sidebar-toggle"),timelimitBlock=this.getTimerBlock(this.module),headerInfo=this.getSidebarTitle(),progressBar=document.querySelector(".box.progress_bar"),courseName=document.querySelector("#page-navbar > nav > ol > li:nth-child(1) > a"),courseDes=document.querySelector("#intro"),Dates=document.querySelector(".activity-dates");let openDate=null==Dates?void 0:Dates.querySelector("div:nth-child(1)"),dueDate=null==Dates?void 0:Dates.querySelector("div:nth-child(2)");const container=this.create("div");Object.assign(container,{id:"cursive-fullpagemode-sidebar",className:"bg-white h-100 shadow"}),Object.assign(container.style,{width:"300px",overflow:"auto"});const crossBtn=this.create("span");Object.assign(crossBtn,{id:"cursive-collapse-sidebar",className:"btn p-2",innerHTML:_svg_repo.default.close}),crossBtn.addEventListener("click",(()=>{container.style.transition="width 0.3s ease",container.style.width="0",toggle.style.display="flex"})),null==toggle||toggle.addEventListener("click",(function(){toggle.style.display="none",container.style.width="300px"}));const btnWrapper=this.create("div");Object.assign(btnWrapper,{padding:"0 1rem",position:"sticky",top:"0",backgroundColor:"white"}),btnWrapper.append(crossBtn);const header=this.create("div");header.className="border-bottom p-3 bg-light",Object.assign(header.style,{position:"sticky",top:"0"});const headerTitle=this.create("h3");headerTitle.className="mb-3 d-flex align-items-center",headerTitle.textContent=`${headerInfo.title} ${this.details}`,headerTitle.style.fontWeight="600";const headerIcon=document.querySelector(".page-header-image > div");headerIcon&&headerTitle.prepend(headerIcon.cloneNode(!0));let wordCount=this.wordCounter(status);null!=timelimitBlock&&timelimitBlock.textContent?header.append(headerTitle,wordCount,this.timerCountDown(timelimitBlock)):header.append(headerTitle,wordCount);const content=this.create("div");if(content.className="p-3",content.append(this.createBox({bg:"bg-info",titleColor:"text-info",icon:_svg_repo.default.people,title:this.studentInfo,bodyHTML:this.generateStudentInfo(this.User,courseName)})),"lesson"===this.module&&progressBar&&content.append(this.createBox({bg:"bg-gray",titleColor:"text-dark",icon:this.moduleIcon,title:this.progress,bodyHTML:progressBar.innerHTML})),courseDes&&""!==(null==courseDes?void 0:courseDes.textContent.trim())&&content.append(this.createBox({bg:"bg-gray",titleColor:"text-dark",icon:this.moduleIcon,title:`${this.getSidebarTitle().title} ${this.description}`,bodyHTML:courseDes.innerHTML})),"forum"===this.module&&replyId){this.checkForumSubject();let replyPost=document.querySelector(`#post-content-${replyId}`);null!=replyPost&&replyPost.textContent.trim()&&content.append(this.createBox({bg:"bg-gray",titleColor:"text-dark",icon:this.moduleIcon,title:this.replyingto,bodyHTML:replyPost.textContent.trim()}))}if("quiz"===this.module&&null!==(_this$editor7=this.editor)&&void 0!==_this$editor7&&_this$editor7.id){var _this$editor8;let questionId=this.getQuestionId(null===(_this$editor8=this.editor)||void 0===_this$editor8?void 0:_this$editor8.id),question=document.querySelector(`#question-${questionId} .qtext`),intro=atob(this.quizInfo.intro);null!=question&&question.textContent.trim()&&content.append(this.createBox({bg:"bg-amber",titleColor:"text-dark",icon:this.moduleIcon,title:this.answeringto,bodyHTML:question.textContent})),intro&&""!==intro.trim()&&content.append(this.createBox({bg:"bg-gray",titleColor:"text-dark",icon:this.moduleIcon,title:`${this.quiz} ${this.description}`,bodyHTML:intro})),Number(this.quizInfo.open)&&content.append(this.createBox({bg:"bg-amber",titleColor:"text-dark",icon:_svg_repo.default.time,title:this.importantdates,bodyHTML:this.generateImportantDates(Number(this.quizInfo.open),Number(this.quizInfo.close))}))}return Object.keys(this.Rubrics).length&&content.append(this.createBox({bg:"bg-gray",titleColor:"text-dark",icon:this.moduleIcon,title:this.rubrics,bodyHTML:this.generateRubrics(this.Rubrics)})),Dates&&content.append(this.createBox({bg:"bg-amber",titleColor:"text-dark",icon:_svg_repo.default.time,title:this.importantdates,bodyHTML:this.generateImportantDates(openDate,dueDate)})),"assign"===this.module&&content.append(this.createBox({bg:"bg-green",titleColor:"text-success",icon:this.moduleIcon,title:this.subStatus,bodyHTML:this.submissionStatus(this.submission)})),container.append(btnWrapper,header,content),container}createBox(_ref){let{bg:bg,titleColor:titleColor,icon:icon,title:title,bodyHTML:bodyHTML}=_ref;const box=this.create("div");box.className=`tiny_cursive-fullpage-card ${bg}`;const heading=this.create("h4");heading.className=`tiny_cursive-fullpage-card-header ${titleColor} d-flex align-items-center`,heading.innerHTML=`${icon} ${title}`;const body=this.create("div");return body.className="tiny_cursive-fullpage-card-body",body.innerHTML=bodyHTML,box.append(heading,body),box}generateRubrics(Rubrics){const wrapper=this.create("div");return Rubrics.forEach((rubric=>{const rubricDiv=this.create("div");rubricDiv.className="tiny_cursive-rubric-card";const title=this.create("h3");title.className="tiny_cursive-rubric-title",title.textContent=rubric.description,rubricDiv.appendChild(title),Object.values(rubric.levels).forEach((level=>{const levelDiv=this.create("div"),score=Number(level.score);levelDiv.className=0===score?"tiny_cursive-rubric-level tiny_cursive-rubric-low":score<=2?"tiny_cursive-rubric-level tiny_cursive-rubric-mid":"tiny_cursive-rubric-level tiny_cursive-rubric-high",levelDiv.textContent=`${level.definition} / ${level.score}`,rubricDiv.appendChild(levelDiv)})),wrapper.appendChild(rubricDiv)})),wrapper.innerHTML}submissionStatus(submission){var _submission$current,_submission$current2;const wrapper=this.create("div"),statusWrapper=this.create("div");statusWrapper.className="tiny_cursive-status-row";const statusName=this.create("span");statusName.textContent=`${this.status}:`;const statusValue=this.create("span"),isNew="new"===(null==submission||null===(_submission$current=submission.current)||void 0===_submission$current?void 0:_submission$current.status);statusValue.textContent=isNew?this.draftnot:this.draft,statusValue.className="tiny_cursive-status-value "+(isNew?"tiny_cursive-status-red":"tiny_cursive-status-green"),statusWrapper.append(statusName,statusValue);const modifiedWrapper=this.create("div");modifiedWrapper.className="tiny_cursive-status-row";const modifiedName=this.create("span");modifiedName.textContent=`${this.lastModified}: `;const modifiedValue=this.create("span");if(null!=submission&&null!==(_submission$current2=submission.current)&&void 0!==_submission$current2&&_submission$current2.timemodified){const date=new Date(1e3*submission.current.timemodified);modifiedValue.textContent=this.formatDate(date)}else modifiedValue.textContent="N/A";modifiedWrapper.append(modifiedName,modifiedValue);const gradeWrapper=this.create("div");gradeWrapper.className="tiny_cursive-status-row";const gradeName=this.create("span");gradeName.textContent=`${this.gradings}: `;const gradeValue=this.create("span");return null!=submission&&submission.grade?gradeValue.textContent=Number(submission.grade.grade)>0?submission.grade.grade:this.gradenot:gradeValue.textContent=this.gradenot,gradeWrapper.append(gradeName,gradeValue),wrapper.append(statusWrapper,gradeWrapper,modifiedWrapper),wrapper.innerHTML}wordCounter(status){const wordCount=this.create("div"),labelDiv=this.create("div"),label=this.create("span"),value=this.create("span"),icon=this.create("span");icon.className="me-2",icon.innerHTML=_svg_repo.default.assignment,labelDiv.appendChild(icon),labelDiv.append(label),label.textContent=`${this.wordCount}:`,value.textContent="0",value.className="text-primary",value.style.fontWeight="600",value.style.fontSize="14px",wordCount.className="bg-white rounded shadow-sm p-2 d-flex justify-content-between my-2",wordCount.append(labelDiv,value),wordCount.style.fontSize="12px";return new MutationObserver((()=>{const newText=status.textContent.trim();value.textContent=`${newText.replace("words","")}`})).observe(status,{characterData:!0,subtree:!0,childList:!0}),wordCount}timerCountDown(timer){let warningDiv=document.querySelector("#user-notifications > div");if(warningDiv){var _clone$querySelector;let clone=warningDiv.cloneNode(!0);null===(_clone$querySelector=clone.querySelector("button"))||void 0===_clone$querySelector||_clone$querySelector.remove(),this.editor.notificationManager.open({text:clone.textContent,type:"error"})}const timerCount=this.create("div");timerCount.className="bg-white rounded shadow-sm p-2 d-flex justify-content-between my-2";const labelDiv=this.create("div"),label=this.create("span"),value=this.create("span"),icon=this.create("span");if(icon.innerHTML=_svg_repo.default.time,labelDiv.appendChild(icon),labelDiv.append(label),label.textContent=`${this.timeleft}: }`,value.textContent="00:00:00",value.className=warningDiv?"text-danger":"text-primary",Object.assign(value.style,{fontWeight:"600",fontSize:"14px"}),timerCount.append(labelDiv,value),timerCount.style.fontSize="12px",timer){new MutationObserver((()=>{const newText=timer.textContent.trim();value.textContent=`${newText}`})).observe(timer,{characterData:!0,subtree:!0,childList:!0})}else value.textContent=this.nolimit;return timerCount}generateStudentInfo(user,course){const wrapper=this.create("div"),nameWrapper=this.create("div"),usernameWrapper=this.create("div"),courseWrapper=this.create("div"),nameLabel=this.create("span"),nameValue=this.create("span"),usernameLabel=this.create("span"),usernameValue=this.create("span"),courseLabel=this.create("span"),courseValue=this.create("span");return nameLabel.textContent=`${this.name}`,nameValue.textContent=user.fullname,usernameLabel.textContent=`${this.userename}: `,usernameValue.textContent=user.username,courseLabel.textContent=`${this.course}: `,courseValue.textContent=course.title,nameWrapper.className="d-flex justify-content-between",usernameWrapper.className="d-flex justify-content-between",courseWrapper.className="d-flex justify-content-between",nameWrapper.append(nameLabel,nameValue),usernameWrapper.append(usernameLabel,usernameValue),courseWrapper.append(courseLabel,courseValue),wrapper.append(nameWrapper,usernameWrapper,courseWrapper),wrapper.innerHTML}generateImportantDates(open,due){const wrapper=this.create("div");let openDate=null,dueDate=null;const openedWrapper=this.create("div"),dueWrapper=this.create("div"),remainingWrapper=this.create("div"),openedLabel=this.create("span"),openedValue=this.create("span"),dueLabel=this.create("span"),dueValue=this.create("span"),remainingLabel=this.create("span"),remainingValue=this.create("span");return"quiz"===this.module?(openDate=1e3*open,dueDate=1e3*due):(openDate=this.extractDate(null==open?void 0:open.textContent),dueDate=this.extractDate(null==due?void 0:due.textContent)),openedLabel.textContent=`${this.opened}: `,openedValue.textContent=this.formatDate(openDate?new Date(openDate):null),openedValue.className="text-dark",dueLabel.textContent=`${this.due}: `,dueValue.textContent=this.formatDate(dueDate?new Date(dueDate):null),dueValue.className="text-danger",remainingLabel.textContent=`${this.remaining}: `,remainingValue.textContent=this.calculateDate(dueDate),remainingValue.className="text-danger",openedWrapper.className="d-flex justify-content-between",dueWrapper.className="d-flex justify-content-between",remainingWrapper.className="d-flex align-items-center justify-content-between mt-2 pt-2 border-top",openedWrapper.append(openedLabel,openedValue),dueWrapper.append(dueLabel,dueValue),remainingWrapper.append(remainingLabel,remainingValue),wrapper.append(openedWrapper,dueWrapper,remainingWrapper),wrapper.innerHTML}formatDate(date){if(!date)return"-";return date.toLocaleString("en-US",{year:"numeric",month:"short",day:"numeric",hour:"numeric",minute:"numeric",hour12:!0})}extractDate(text){if(!text)return"-";const parts=null==text?void 0:text.split(":");return parts.length>1?parts.slice(1).join(":").trim():text.trim()}calculateDate(date){if(!date)return"-";const diffMs=new Date(date)-new Date;if(diffMs<=0)return"Overdue";return`${Math.floor(diffMs/864e5)} days, ${Math.floor(diffMs/36e5%24)} hours`}fullPageModule(module){var _current$contentDocum,_current$contentWindo,_current$contentWindo2,_document$getElementB;let current="quiz"===this.module?document.getElementById(`${module}_ifr`):document.querySelector(`#${module}_ifr`),p1=current.parentElement,p2=p1.parentElement,p4=p2.parentElement.parentElement,statusBar=document.querySelector(".tox-statusbar__right-container > button"),assignName=document.querySelector(".page-context-header"),header=this.create("div"),btn=null;assignName.classList.remove("mb-2"),header.id="tiny_cursive-fullpage-custom-header",Object.assign(header.style,{backgroundColor:"white",display:"flex",justifyContent:"space-between"}),"quiz"===this.module?(btn=document.querySelector("#mod_quiz-next-nav").cloneNode(!0),btn.className="tiny_cursive-fullpage-submit-btn",btn.style.margin=".5rem"):(btn=this.create("input"),btn.className="tiny_cursive-fullpage-submit-btn",btn.value=this.savechanges,btn.type="submit",btn.style.margin=".5rem");const leftSide=this.create("div"),rightSide=this.create("div");let commonStyle={display:"flex",alignItems:"center",margin:"0 1rem"};Object.assign(leftSide.style,commonStyle),rightSide.id="tiny_cursive-fullpage-right-wrapper",Object.assign(rightSide.style,commonStyle),rightSide.appendChild(btn),leftSide.appendChild(assignName.cloneNode(!0)),header.appendChild(leftSide),header.appendChild(rightSide),p4.insertBefore(header,p4.firstChild),p2.style.backgroundColor="#efefef",Object.assign(current.style,{width:"750px",minWidth:"750px",boxShadow:"0 10px 15px -3px rgb(0 0 0/0.1),0 4px 6px -4px rgb(0 0 0/0.1)"}),Object.assign(p1.style,{display:"flex",justifyContent:"center",outline:"none",margin:"2rem 0 0"});const style=this.create("style");style.id="tiny_cursive-fullpage-mode-style",style.textContent="\n .tox.tox-edit-focus .tox-edit-area::before {\n opacity: 0;\n }",document.head.appendChild(style);let iframeBody=(null===(_current$contentDocum=current.contentDocument)||void 0===_current$contentDocum?void 0:_current$contentDocum.body)||(null===(_current$contentWindo=current.contentWindow)||void 0===_current$contentWindo||null===(_current$contentWindo2=_current$contentWindo.document)||void 0===_current$contentWindo2?void 0:_current$contentWindo2.body);iframeBody&&(iframeBody.style.padding="0.5in"),p2.style.position="relative",null===(_document$getElementB=document.getElementById("cursive-fullpagemode-sidebar"))||void 0===_document$getElementB||_document$getElementB.remove();let toggle=this.create("div");toggle.id="cursive-fullpagemode-sidebar-toggle",toggle.innerHTML=_svg_repo.default.hamburger,p2.appendChild(toggle),p2.appendChild(this.docSideBar(statusBar))}normalizePage(editorId){var _document$getElementB2,_document$getElementB3,_current$contentDocum2,_current$contentWindo3,_current$contentWindo4,_document$head$queryS;null===(_document$getElementB2=document.getElementById("tiny_cursive-fullpage-custom-header"))||void 0===_document$getElementB2||_document$getElementB2.remove(),null===(_document$getElementB3=document.getElementById("cursive-fullpagemode-sidebar"))||void 0===_document$getElementB3||_document$getElementB3.remove();let current=document.getElementById(editorId),p1=current.parentElement,p2=p1.parentElement;Object.assign(p2.style,{backgroundColor:"",position:""}),Object.assign(current.style,{width:"",minWidth:"",boxShadow:""}),Object.assign(p1.style,{display:"",justifyContent:"",outline:"",margin:""}),p1.classList.remove("tiny-cursive-editor-container");let iframeBody=(null===(_current$contentDocum2=current.contentDocument)||void 0===_current$contentDocum2?void 0:_current$contentDocum2.body)||(null===(_current$contentWindo3=current.contentWindow)||void 0===_current$contentWindo3||null===(_current$contentWindo4=_current$contentWindo3.document)||void 0===_current$contentWindo4?void 0:_current$contentWindo4.body);iframeBody&&(iframeBody.style.padding="0"),null===(_document$head$queryS=document.head.querySelector("#tiny_cursive-fullpage-mode-style"))||void 0===_document$head$queryS||_document$head$queryS.remove()}checkForumSubject(){const form=document.querySelector("#tiny_cursive-fullpage-right-wrapper > input"),msg=this.subjectnot;form&&form.addEventListener("click",(e=>{const subjectInput=document.getElementById("id_subject");let content=this.editor.getContent().trim();subjectInput&&""!==subjectInput.value.trim()&&""!==content||(e.preventDefault(),e.stopPropagation(),this.editor.windowManager.alert(msg))}))}getSidebarTitle(){const[assign,discus,quiz,lesson]=this.getText("sbTitle");switch(this.module){case"assign":return{title:assign,icon:_svg_repo.default.assignment};case"forum":return{title:discus,icon:_svg_repo.default.forum};case"lesson":return{title:lesson,icon:_svg_repo.default.forum};case"quiz":return{title:quiz,icon:_svg_repo.default.quiz};default:return{title:"Page",icon:_svg_repo.default.quiz}}}getTimerBlock(module){switch(module){case"assign":return document.querySelector("#mod_assign_timelimit_block > div > div");case"forum":return document.querySelector("#mod_forum_timelimit_block");case"lesson":return document.querySelector("#lesson-timer");case"quiz":return document.querySelector("#quiz-time-left");default:return null}}getQuestionId(editoId){try{return editoId&&"string"==typeof editoId?editoId.replace(/^q(\d+):(\d+)_.*$/,"$1-$2"):""}catch(error){return window.console.error("Error getting question ID:",error),""}}initStrings(){[this.details,this.studentInfo,this.progress,this.description,this.replyingto,this.answeringto,this.importantdates,this.rubrics,this.subStatus,this.status,this.draft,this.draftnot,this.lastModified,this.gradings,this.gradenot,this.wordCount,this.timeleft,this.nolimit,this.name,this.userename,this.course,this.opened,this.due,this.overdue,this.remaining,this.savechanges,this.subjectnot]=this.getText("docSideBar")}getText(key){return JSON.parse(localStorage.getItem(key))||[]}create(tag){return document.createElement(tag)}},_exports.default})); + */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_svg_repo=(obj=_svg_repo)&&obj.__esModule?obj:{default:obj};return _exports.default=class{constructor(User,Rubrics,submission,modulename,editor,quizInfo){this.User=User,this.Rubrics=Rubrics,this.submission=submission,this.module=modulename,this.editor=editor,this.moduleIcon=_svg_repo.default.assignment,this.quizInfo=quizInfo,this.initStrings()}normalMode(){var _this$editor;let id=(null===(_this$editor=this.editor)||void 0===_this$editor?void 0:_this$editor.id)+"_ifr";("assign"===this.module||"quiz"===this.module||"forum"===this.module||"lesson"===this.module||"pdfannotator"===this.module)&&this.normalizePage(id)}fullPageMode(){var _this$editor4,_this$editor2;if("assign"===this.module)this.moduleIcon=_svg_repo.default.assignment,this.fullPageModule(null===(_this$editor2=this.editor)||void 0===_this$editor2?void 0:_this$editor2.id);else if("forum"===this.module){var _this$editor3;this.moduleIcon=_svg_repo.default.forum,this.fullPageModule(null===(_this$editor3=this.editor)||void 0===_this$editor3?void 0:_this$editor3.id)}else if("quiz"===this.module&&null!==(_this$editor4=this.editor)&&void 0!==_this$editor4&&_this$editor4.id){var _this$editor5;this.moduleIcon=_svg_repo.default.quiz,this.fullPageModule(null===(_this$editor5=this.editor)||void 0===_this$editor5?void 0:_this$editor5.id)}else if("lesson"===this.module){var _this$editor6;this.moduleIcon=_svg_repo.default.lesson,this.fullPageModule(null===(_this$editor6=this.editor)||void 0===_this$editor6?void 0:_this$editor6.id)}else if("pdfannotator"===this.module){var _this$editor7;this.moduleIcon=_svg_repo.default.pdfannotator,this.fullPageModule(null===(_this$editor7=this.editor)||void 0===_this$editor7?void 0:_this$editor7.id)}}docSideBar(status){var _this$editor8;const replyId=new URL(window.location.href).searchParams.get("reply"),toggle=document.querySelector("#cursive-fullpagemode-sidebar-toggle"),timelimitBlock=this.getTimerBlock(this.module),headerInfo=this.getSidebarTitle(),progressBar=document.querySelector(".box.progress_bar"),courseName=document.querySelector("#page-navbar > nav > ol > li:nth-child(1) > a"),courseDes=document.querySelector("#intro"),Dates=document.querySelector(".activity-dates");let openDate=null==Dates?void 0:Dates.querySelector("div:nth-child(1)"),dueDate=null==Dates?void 0:Dates.querySelector("div:nth-child(2)");const container=this.create("div");Object.assign(container,{id:"cursive-fullpagemode-sidebar",className:"bg-white h-100 shadow"}),Object.assign(container.style,{width:"300px",overflow:"auto"});const crossBtn=this.create("span");Object.assign(crossBtn,{id:"cursive-collapse-sidebar",className:"btn p-2",innerHTML:_svg_repo.default.close}),crossBtn.addEventListener("click",(()=>{container.style.transition="width 0.3s ease",container.style.width="0",toggle.style.display="flex"})),null==toggle||toggle.addEventListener("click",(function(){toggle.style.display="none",container.style.width="300px"}));const btnWrapper=this.create("div");Object.assign(btnWrapper,{padding:"0 1rem",position:"sticky",top:"0",backgroundColor:"white"}),btnWrapper.append(crossBtn);const header=this.create("div");header.className="border-bottom p-3 bg-light",Object.assign(header.style,{position:"sticky",top:"0"});const headerTitle=this.create("h3");headerTitle.className="mb-3 d-flex align-items-center",headerTitle.textContent=`${headerInfo.title} ${this.details}`,headerTitle.style.fontWeight="600";const headerIcon=document.querySelector(".page-header-image > div");headerIcon&&headerTitle.prepend(headerIcon.cloneNode(!0));let wordCount=this.wordCounter(status);null!=timelimitBlock&&timelimitBlock.textContent?header.append(headerTitle,wordCount,this.timerCountDown(timelimitBlock)):header.append(headerTitle,wordCount);const content=this.create("div");if(content.className="p-3",content.append(this.createBox({bg:"bg-info",titleColor:"text-info",icon:_svg_repo.default.people,title:this.studentInfo,bodyHTML:this.generateStudentInfo(this.User,courseName)})),"lesson"===this.module&&progressBar&&content.append(this.createBox({bg:"bg-gray",titleColor:"text-dark",icon:this.moduleIcon,title:this.progress,bodyHTML:progressBar.innerHTML})),courseDes&&""!==(null==courseDes?void 0:courseDes.textContent.trim())){let fileSubDiv=document.querySelectorAll(".fileuploadsubmission");fileSubDiv&&fileSubDiv.forEach((Element=>{Element.style.verticalAlign="middle"})),content.append(this.createBox({bg:"bg-gray",titleColor:"text-dark",icon:this.moduleIcon,title:`${this.getSidebarTitle().title} ${this.description}`,bodyHTML:courseDes.innerHTML}))}if("forum"===this.module&&replyId){this.checkForumSubject();let replyPost=document.querySelector(`#post-content-${replyId}`);null!=replyPost&&replyPost.textContent.trim()&&content.append(this.createBox({bg:"bg-gray",titleColor:"text-dark",icon:this.moduleIcon,title:this.replyingto,bodyHTML:replyPost.textContent.trim()}))}if("quiz"===this.module&&null!==(_this$editor8=this.editor)&&void 0!==_this$editor8&&_this$editor8.id){var _this$editor9;let questionId=this.getQuestionId(null===(_this$editor9=this.editor)||void 0===_this$editor9?void 0:_this$editor9.id),question=document.querySelector(`#question-${questionId} .qtext`),intro=atob(this.quizInfo.intro);null!=question&&question.textContent.trim()&&content.append(this.createBox({bg:"bg-amber",titleColor:"text-dark",icon:this.moduleIcon,title:this.answeringto,bodyHTML:question.textContent})),intro&&""!==intro.trim()&&content.append(this.createBox({bg:"bg-gray",titleColor:"text-dark",icon:this.moduleIcon,title:`${this.quiz} ${this.description}`,bodyHTML:intro})),Number(this.quizInfo.open)&&content.append(this.createBox({bg:"bg-amber",titleColor:"text-dark",icon:_svg_repo.default.time,title:this.importantdates,bodyHTML:this.generateImportantDates(Number(this.quizInfo.open),Number(this.quizInfo.close))}))}return Object.keys(this.Rubrics).length&&content.append(this.createBox({bg:"bg-gray",titleColor:"text-dark",icon:this.moduleIcon,title:this.rubrics,bodyHTML:this.generateRubrics(this.Rubrics)})),Dates&&content.append(this.createBox({bg:"bg-amber",titleColor:"text-dark",icon:_svg_repo.default.time,title:this.importantdates,bodyHTML:this.generateImportantDates(openDate,dueDate)})),"assign"===this.module&&content.append(this.createBox({bg:"bg-green",titleColor:"text-success",icon:this.moduleIcon,title:this.subStatus,bodyHTML:this.submissionStatus(this.submission)})),container.append(btnWrapper,header,content),container}createBox(_ref){let{bg:bg,titleColor:titleColor,icon:icon,title:title,bodyHTML:bodyHTML}=_ref;const box=this.create("div");box.className=`tiny_cursive-fullpage-card ${bg}`;const heading=this.create("h4");heading.className=`tiny_cursive-fullpage-card-header ${titleColor} d-flex align-items-center`,heading.innerHTML=`${icon} ${title}`;const body=this.create("div");return body.className="tiny_cursive-fullpage-card-body",body.innerHTML=bodyHTML,box.append(heading,body),box}generateRubrics(Rubrics){const wrapper=this.create("div");return Rubrics.forEach((rubric=>{const rubricDiv=this.create("div");rubricDiv.className="tiny_cursive-rubric-card";const title=this.create("h3");title.className="tiny_cursive-rubric-title",title.textContent=rubric.description,rubricDiv.appendChild(title),Object.values(rubric.levels).forEach((level=>{const levelDiv=this.create("div"),score=Number(level.score);levelDiv.className=0===score?"tiny_cursive-rubric-level tiny_cursive-rubric-low":score<=2?"tiny_cursive-rubric-level tiny_cursive-rubric-mid":"tiny_cursive-rubric-level tiny_cursive-rubric-high",levelDiv.textContent=`${level.definition} / ${level.score}`,rubricDiv.appendChild(levelDiv)})),wrapper.appendChild(rubricDiv)})),wrapper.innerHTML}submissionStatus(submission){var _submission$current,_submission$current2;const wrapper=this.create("div"),statusWrapper=this.create("div");statusWrapper.className="tiny_cursive-status-row";const statusName=this.create("span");statusName.textContent=`${this.status}:`;const statusValue=this.create("span"),isNew="new"===(null==submission||null===(_submission$current=submission.current)||void 0===_submission$current?void 0:_submission$current.status);statusValue.textContent=isNew?this.draftnot:this.draft,statusValue.className="tiny_cursive-status-value "+(isNew?"tiny_cursive-status-red":"tiny_cursive-status-green"),statusWrapper.append(statusName,statusValue);const modifiedWrapper=this.create("div");modifiedWrapper.className="tiny_cursive-status-row";const modifiedName=this.create("span");modifiedName.textContent=`${this.lastModified}: `;const modifiedValue=this.create("span");if(null!=submission&&null!==(_submission$current2=submission.current)&&void 0!==_submission$current2&&_submission$current2.timemodified){const date=new Date(1e3*submission.current.timemodified);modifiedValue.textContent=this.formatDate(date)}else modifiedValue.textContent="N/A";modifiedWrapper.append(modifiedName,modifiedValue);const gradeWrapper=this.create("div");gradeWrapper.className="tiny_cursive-status-row";const gradeName=this.create("span");gradeName.textContent=`${this.gradings}: `;const gradeValue=this.create("span");return null!=submission&&submission.grade?gradeValue.textContent=Number(submission.grade.grade)>0?submission.grade.grade:this.gradenot:gradeValue.textContent=this.gradenot,gradeWrapper.append(gradeName,gradeValue),wrapper.append(statusWrapper,gradeWrapper,modifiedWrapper),wrapper.innerHTML}wordCounter(status){const wordCount=this.create("div"),labelDiv=this.create("div"),label=this.create("span"),value=this.create("span"),icon=this.create("span");icon.className="me-2",icon.innerHTML=_svg_repo.default.assignment,labelDiv.appendChild(icon),labelDiv.append(label),label.textContent=`${this.wordCount}:`,value.textContent="0",value.className="text-primary",value.style.fontWeight="600",value.style.fontSize="14px",wordCount.className="bg-white rounded shadow-sm p-2 d-flex justify-content-between my-2",wordCount.append(labelDiv,value),wordCount.style.fontSize="12px";return new MutationObserver((()=>{const newText=status.textContent.trim();value.textContent=`${newText.replace("words","")}`})).observe(status,{characterData:!0,subtree:!0,childList:!0}),wordCount}timerCountDown(timer){let warningDiv=document.querySelector("#user-notifications > div");if(warningDiv){var _clone$querySelector;let clone=warningDiv.cloneNode(!0);null===(_clone$querySelector=clone.querySelector("button"))||void 0===_clone$querySelector||_clone$querySelector.remove(),this.editor.notificationManager.open({text:clone.textContent,type:"error"})}const timerCount=this.create("div");timerCount.className="bg-white rounded shadow-sm p-2 d-flex justify-content-between my-2";const labelDiv=this.create("div"),label=this.create("span"),value=this.create("span"),icon=this.create("span");if(icon.innerHTML=_svg_repo.default.time,labelDiv.appendChild(icon),labelDiv.append(label),label.textContent=`${this.timeleft}:`,value.textContent="00:00:00",value.className=warningDiv?"text-danger":"text-primary",Object.assign(value.style,{fontWeight:"600",fontSize:"14px"}),timerCount.append(labelDiv,value),timerCount.style.fontSize="12px",timer){new MutationObserver((()=>{const newText=timer.textContent.trim();value.textContent=`${newText}`})).observe(timer,{characterData:!0,subtree:!0,childList:!0})}else value.textContent=this.nolimit;return timerCount}generateStudentInfo(user,course){const wrapper=this.create("div"),nameWrapper=this.create("div"),usernameWrapper=this.create("div"),courseWrapper=this.create("div"),nameLabel=this.create("strong"),nameValue=this.create("span"),usernameLabel=this.create("strong"),usernameValue=this.create("span"),courseLabel=this.create("strong"),courseValue=this.create("span");return nameLabel.textContent=`${this.name}`,nameValue.textContent=user.fullname,usernameLabel.textContent=`${this.userename}: `,usernameValue.textContent=user.username,courseLabel.textContent=`${this.course}: `,courseValue.textContent=course.title,usernameLabel.className="cfw-bold me-2",usernameValue.className="cursiveFw-wrap",courseLabel.className="cfw-bold me-2",courseValue.className="cursiveFw-wrap",nameLabel.className="cfw-bold me-2",nameValue.className="cursiveFw-wrap",nameWrapper.append(nameLabel,nameValue),usernameWrapper.append(usernameLabel,usernameValue),courseWrapper.append(courseLabel,courseValue),wrapper.append(nameWrapper,usernameWrapper,courseWrapper),wrapper.innerHTML}generateImportantDates(open,due){const wrapper=this.create("div");let openDate=null,dueDate=null;const openedWrapper=this.create("div"),dueWrapper=this.create("div"),remainingWrapper=this.create("div"),openedLabel=this.create("span"),openedValue=this.create("span"),dueLabel=this.create("span"),dueValue=this.create("span"),remainingLabel=this.create("span"),remainingValue=this.create("span");return"quiz"===this.module?(openDate=1e3*open,dueDate=1e3*due):(openDate=this.extractDate(null==open?void 0:open.textContent),dueDate=this.extractDate(null==due?void 0:due.textContent)),openedLabel.textContent=`${this.opened}: `,openedValue.textContent=this.formatDate(openDate?new Date(openDate):null),openedValue.className="text-dark",dueLabel.textContent=`${this.due}: `,dueValue.textContent=this.formatDate(dueDate?new Date(dueDate):null),dueValue.className="text-danger",remainingLabel.textContent=`${this.remaining}: `,remainingValue.textContent=this.calculateDate(dueDate),remainingValue.className="text-danger",openedWrapper.className="d-flex justify-content-between",dueWrapper.className="d-flex justify-content-between",remainingWrapper.className="d-flex align-items-center justify-content-between mt-2 pt-2 border-top",openedWrapper.append(openedLabel,openedValue),dueWrapper.append(dueLabel,dueValue),remainingWrapper.append(remainingLabel,remainingValue),wrapper.append(openedWrapper,dueWrapper,remainingWrapper),wrapper.innerHTML}formatDate(date){if(!date)return"-";return date.toLocaleString("en-US",{year:"numeric",month:"short",day:"numeric",hour:"numeric",minute:"numeric",hour12:!0})}extractDate(text){if(!text)return"-";const parts=null==text?void 0:text.split(":");return parts.length>1?parts.slice(1).join(":").trim():text.trim()}calculateDate(date){if(!date)return"-";const diffMs=new Date(date)-new Date;if(diffMs<=0)return"Overdue";return`${Math.floor(diffMs/864e5)} days, ${Math.floor(diffMs/36e5%24)} hours`}fullPageModule(module){var _current$contentDocum,_current$contentWindo,_current$contentWindo2,_document$getElementB;let current="quiz"===this.module?document.getElementById(`${module}_ifr`):document.querySelector(`#${module}_ifr`),p1=current.parentElement,p2=p1.parentElement,p4=p2.parentElement.parentElement,statusBar=document.querySelector(".tox-statusbar__right-container > button"),assignName=document.querySelector(".page-context-header"),header=this.create("div"),btn=null;if(assignName.classList.remove("mb-2"),header.id="tiny_cursive-fullpage-custom-header",Object.assign(header.style,{backgroundColor:"white",display:"flex",justifyContent:"space-between"}),"quiz"===this.module?(btn=document.querySelector("#mod_quiz-next-nav").cloneNode(!0),btn.className="tiny_cursive-fullpage-submit-btn",btn.style.margin=".5rem"):(btn=this.create("input"),btn.className="tiny_cursive-fullpage-submit-btn",btn.value=this.savechanges,btn.type="submit",btn.style.margin=".5rem"),"pdfannotator"===this.module){const style=document.createElement("style");style.id="cursiveForceStyle",style.textContent="\n .path-mod-pdfannotator #comment-wrapper h4,\n .path-mod-pdfannotator #comment-nav {\n margin: 0 !important;\n }\n ",document.head.appendChild(style)}const leftSide=this.create("div"),rightSide=this.create("div");let commonStyle={display:"flex",alignItems:"center",margin:"0 1rem"};Object.assign(leftSide.style,commonStyle),rightSide.id="tiny_cursive-fullpage-right-wrapper",Object.assign(rightSide.style,commonStyle),rightSide.appendChild(btn),leftSide.appendChild(assignName.cloneNode(!0)),header.appendChild(leftSide),header.appendChild(rightSide),p4.insertBefore(header,p4.firstChild),p2.style.backgroundColor="#efefef",Object.assign(current.style,{width:"750px",minWidth:"750px",boxShadow:"0 10px 15px -3px rgb(0 0 0/0.1),0 4px 6px -4px rgb(0 0 0/0.1)"}),Object.assign(p1.style,{display:"flex",justifyContent:"center",outline:"none",margin:"2rem 0 0"});const style=this.create("style");style.id="tiny_cursive-fullpage-mode-style",style.textContent="\n .tox.tox-edit-focus .tox-edit-area::before {\n opacity: 0;\n }",document.head.appendChild(style);let iframeBody=(null===(_current$contentDocum=current.contentDocument)||void 0===_current$contentDocum?void 0:_current$contentDocum.body)||(null===(_current$contentWindo=current.contentWindow)||void 0===_current$contentWindo||null===(_current$contentWindo2=_current$contentWindo.document)||void 0===_current$contentWindo2?void 0:_current$contentWindo2.body);iframeBody&&(iframeBody.style.padding="0.5in"),p2.style.position="relative",null===(_document$getElementB=document.getElementById("cursive-fullpagemode-sidebar"))||void 0===_document$getElementB||_document$getElementB.remove();let toggle=this.create("div");toggle.id="cursive-fullpagemode-sidebar-toggle",toggle.innerHTML=_svg_repo.default.hamburger,p2.appendChild(toggle),p2.appendChild(this.docSideBar(statusBar))}normalizePage(editorId){var _document$getElementB2,_document$getElementB3,_current$contentDocum2,_current$contentWindo3,_current$contentWindo4,_document$head$queryS,_document$head$queryS2;null===(_document$getElementB2=document.getElementById("tiny_cursive-fullpage-custom-header"))||void 0===_document$getElementB2||_document$getElementB2.remove(),null===(_document$getElementB3=document.getElementById("cursive-fullpagemode-sidebar"))||void 0===_document$getElementB3||_document$getElementB3.remove();let current=document.getElementById(editorId),p1=current.parentElement,p2=p1.parentElement;Object.assign(p2.style,{backgroundColor:"",position:""}),Object.assign(current.style,{width:"",minWidth:"",boxShadow:""}),Object.assign(p1.style,{display:"",justifyContent:"",outline:"",margin:""}),p1.classList.remove("tiny-cursive-editor-container");let iframeBody=(null===(_current$contentDocum2=current.contentDocument)||void 0===_current$contentDocum2?void 0:_current$contentDocum2.body)||(null===(_current$contentWindo3=current.contentWindow)||void 0===_current$contentWindo3||null===(_current$contentWindo4=_current$contentWindo3.document)||void 0===_current$contentWindo4?void 0:_current$contentWindo4.body);iframeBody&&(iframeBody.style.padding="0"),null===(_document$head$queryS=document.head.querySelector("#tiny_cursive-fullpage-mode-style"))||void 0===_document$head$queryS||_document$head$queryS.remove(),null===(_document$head$queryS2=document.head.querySelector("#cursiveForceStyle"))||void 0===_document$head$queryS2||_document$head$queryS2.remove()}checkForumSubject(){const form=document.querySelector("#tiny_cursive-fullpage-right-wrapper > input"),msg=this.subjectnot;form&&form.addEventListener("click",(e=>{const subjectInput=document.getElementById("id_subject");let content=this.editor.getContent().trim();subjectInput&&""!==subjectInput.value.trim()&&""!==content||(e.preventDefault(),e.stopPropagation(),this.editor.windowManager.alert(msg))}))}getSidebarTitle(){const[assign,discus,quiz,lesson]=this.getText("sbTitle");switch(this.module){case"assign":return{title:assign,icon:_svg_repo.default.assignment};case"forum":return{title:discus,icon:_svg_repo.default.forum};case"lesson":return{title:lesson,icon:_svg_repo.default.forum};case"quiz":return{title:quiz,icon:_svg_repo.default.quiz};case"pdfannotator":return{title:"PDF Annotation",icon:_svg_repo.default.pdfannotator};default:return{title:"Page",icon:_svg_repo.default.quiz}}}getTimerBlock(module){switch(module){case"assign":return document.querySelector("#mod_assign_timelimit_block > div > div");case"forum":return document.querySelector("#mod_forum_timelimit_block");case"lesson":return document.querySelector("#lesson-timer");case"quiz":return document.querySelector("#quiz-time-left");default:return null}}getQuestionId(editoId){try{return editoId&&"string"==typeof editoId?editoId.replace(/^q(\d+):(\d+)_.*$/,"$1-$2"):""}catch(error){return window.console.error("Error getting question ID:",error),""}}initStrings(){[this.details,this.studentInfo,this.progress,this.description,this.replyingto,this.answeringto,this.importantdates,this.rubrics,this.subStatus,this.status,this.draft,this.draftnot,this.lastModified,this.gradings,this.gradenot,this.wordCount,this.timeleft,this.nolimit,this.name,this.userename,this.course,this.opened,this.due,this.overdue,this.remaining,this.savechanges,this.subjectnot]=this.getText("docSideBar")}getText(key){return JSON.parse(localStorage.getItem(key))||[]}create(tag){return document.createElement(tag)}},_exports.default})); //# sourceMappingURL=document_view.min.js.map \ No newline at end of file diff --git a/amd/build/document_view.min.js.map b/amd/build/document_view.min.js.map index 39104e64..e291a61f 100644 --- a/amd/build/document_view.min.js.map +++ b/amd/build/document_view.min.js.map @@ -1 +1 @@ -{"version":3,"file":"document_view.min.js","sources":["../src/document_view.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 * This module provides functionality for document view management in the Tiny editor,\n * including full page mode display and sidebar information\n * @module tiny_cursive/document_view\n * @copyright 2025 Cursive Technology, Inc. \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Icons from 'tiny_cursive/svg_repo';\nexport default class DocumentView {\n\n constructor(User, Rubrics, submission, modulename, editor, quizInfo) {\n this.User = User;\n this.Rubrics = Rubrics;\n this.submission = submission;\n this.module = modulename;\n this.editor = editor;\n this.moduleIcon = Icons.assignment;\n this.quizInfo = quizInfo;\n this.initStrings();\n }\n\n normalMode() {\n let id = this.editor?.id + \"_ifr\";\n if (this.module === 'assign') {\n this.normalizePage(id);\n } else if (this.module === 'quiz') {\n this.normalizePage(id);\n } else if (this.module === 'forum') {\n this.normalizePage(id);\n } else if (this.module === 'lesson') {\n this.normalizePage(id);\n }\n }\n\n fullPageMode() {\n\n if (this.module === 'assign') {\n this.moduleIcon = Icons.assignment;\n this.fullPageModule(this.editor?.id);\n } else if (this.module === 'forum') {\n this.moduleIcon = Icons.forum;\n this.fullPageModule(this.editor?.id);\n } else if (this.module === 'quiz' && this.editor?.id) {\n this.moduleIcon = Icons.quiz;\n this.fullPageModule(this.editor?.id);\n } else if (this.module === 'lesson') {\n this.moduleIcon = Icons.lesson;\n this.fullPageModule(this.editor?.id);\n }\n }\n\n docSideBar(status) {\n\n const url = new URL(window.location.href);\n const replyId = url.searchParams.get(\"reply\");\n const toggle = document.querySelector('#cursive-fullpagemode-sidebar-toggle');\n const timelimitBlock = this.getTimerBlock(this.module);\n const headerInfo = this.getSidebarTitle();\n const progressBar = document.querySelector('.box.progress_bar');\n\n const courseName = document.querySelector('#page-navbar > nav > ol > li:nth-child(1) > a');\n const courseDes = document.querySelector('#intro');\n const Dates = document.querySelector('.activity-dates');\n\n let openDate = Dates?.querySelector('div:nth-child(1)');\n let dueDate = Dates?.querySelector('div:nth-child(2)');\n\n const container = this.create('div');\n Object.assign(container, {\n id: 'cursive-fullpagemode-sidebar',\n className: 'bg-white h-100 shadow'\n });\n Object.assign(container.style, {\n width: '300px',\n overflow: 'auto'\n });\n\n const crossBtn = this.create('span');\n Object.assign(crossBtn, {\n id: 'cursive-collapse-sidebar',\n className: 'btn p-2',\n innerHTML: Icons.close\n });\n\n crossBtn.addEventListener('click', () => {\n container.style.transition = 'width 0.3s ease';\n container.style.width = '0';\n toggle.style.display = 'flex';\n });\n toggle?.addEventListener('click', function() {\n toggle.style.display = 'none';\n container.style.width = '300px';\n });\n\n const btnWrapper = this.create('div');\n Object.assign(btnWrapper, {\n padding: '0 1rem',\n position: 'sticky',\n top: '0',\n backgroundColor: 'white'\n });\n btnWrapper.append(crossBtn);\n\n\n const header = this.create('div');\n header.className = 'border-bottom p-3 bg-light';\n Object.assign(header.style, {\n position: 'sticky',\n top: '0'\n });\n\n const headerTitle = this.create('h3');\n headerTitle.className = 'mb-3 d-flex align-items-center';\n headerTitle.textContent = `${headerInfo.title} ${this.details}`;\n headerTitle.style.fontWeight = '600';\n\n const headerIcon = document.querySelector('.page-header-image > div');\n if (headerIcon) {\n headerTitle.prepend(headerIcon.cloneNode(true));\n }\n\n let wordCount = this.wordCounter(status);\n if (timelimitBlock?.textContent) {\n header.append(headerTitle, wordCount, this.timerCountDown(timelimitBlock));\n } else {\n header.append(headerTitle, wordCount);\n }\n\n const content = this.create('div');\n content.className = 'p-3';\n\n content.append(\n this.createBox({\n bg: 'bg-info',\n titleColor: 'text-info',\n icon: Icons.people,\n title: this.studentInfo,\n bodyHTML: this.generateStudentInfo(this.User, courseName)\n })\n );\n\n if (this.module === 'lesson' && progressBar) {\n content.append(\n this.createBox({\n bg: 'bg-gray',\n titleColor: 'text-dark',\n icon: this.moduleIcon,\n title: this.progress,\n bodyHTML: progressBar.innerHTML\n })\n );\n }\n\n if (courseDes && courseDes?.textContent.trim() !== '') {\n content.append(\n this.createBox({\n bg: 'bg-gray',\n titleColor: 'text-dark',\n icon: this.moduleIcon,\n title: `${this.getSidebarTitle().title} ${this.description}`,\n bodyHTML: courseDes.innerHTML\n })\n );\n }\n\n if (this.module === 'forum' && replyId) {\n this.checkForumSubject();\n let replyPost = document.querySelector(`#post-content-${replyId}`);\n if (replyPost?.textContent.trim()) {\n content.append(\n this.createBox({\n bg: 'bg-gray',\n titleColor: 'text-dark',\n icon: this.moduleIcon,\n title: this.replyingto,\n bodyHTML: replyPost.textContent.trim()\n })\n );\n }\n }\n\n if (this.module === 'quiz' && this.editor?.id) {\n\n let questionId = this.getQuestionId(this.editor?.id);\n let question = document.querySelector(`#question-${questionId} .qtext`);\n let intro = atob(this.quizInfo.intro);\n\n if (question?.textContent.trim()) {\n content.append(\n this.createBox({\n bg: 'bg-amber',\n titleColor: 'text-dark',\n icon: this.moduleIcon,\n title: this.answeringto,\n bodyHTML: question.textContent\n })\n );\n }\n\n if (intro && intro.trim() !== '') {\n content.append(\n this.createBox({\n bg: 'bg-gray',\n titleColor: 'text-dark',\n icon: this.moduleIcon,\n title: `${this.quiz} ${this.description}`,\n bodyHTML: intro\n })\n );\n }\n\n if (Number(this.quizInfo.open)) {\n content.append(\n this.createBox({\n bg: 'bg-amber',\n titleColor: 'text-dark',\n icon: Icons.time,\n title: this.importantdates,\n bodyHTML: this.generateImportantDates(Number(this.quizInfo.open), Number(this.quizInfo.close))\n })\n );\n }\n }\n\n if (Object.keys(this.Rubrics).length) {\n content.append(\n this.createBox({\n bg: 'bg-gray',\n titleColor: 'text-dark',\n icon: this.moduleIcon,\n title: this.rubrics,\n bodyHTML: this.generateRubrics(this.Rubrics)\n })\n );\n }\n\n if (Dates) {\n content.append(\n this.createBox({\n bg: 'bg-amber',\n titleColor: 'text-dark',\n icon: Icons.time,\n title: this.importantdates,\n bodyHTML: this.generateImportantDates(openDate, dueDate)\n })\n );\n }\n if (this.module === 'assign') {\n content.append(\n this.createBox({\n bg: 'bg-green',\n titleColor: 'text-success',\n icon: this.moduleIcon,\n title: this.subStatus,\n bodyHTML: this.submissionStatus(this.submission)\n })\n );\n }\n\n container.append(btnWrapper, header, content);\n return container;\n\n }\n // Helper to create info boxes\n createBox({bg, titleColor, icon, title, bodyHTML}) {\n const box = this.create('div');\n box.className = `tiny_cursive-fullpage-card ${bg}`;\n\n const heading = this.create('h4');\n heading.className = `tiny_cursive-fullpage-card-header ${titleColor} d-flex align-items-center`;\n heading.innerHTML = `${icon} ${title}`;\n\n const body = this.create('div');\n body.className = `tiny_cursive-fullpage-card-body`;\n body.innerHTML = bodyHTML;\n\n box.append(heading, body);\n return box;\n }\n\n generateRubrics(Rubrics) {\n const wrapper = this.create('div');\n\n Rubrics.forEach(rubric => {\n const rubricDiv = this.create('div');\n rubricDiv.className = 'tiny_cursive-rubric-card';\n\n const title = this.create('h3');\n title.className = 'tiny_cursive-rubric-title';\n title.textContent = rubric.description;\n rubricDiv.appendChild(title);\n\n Object.values(rubric.levels).forEach(level => {\n const levelDiv = this.create('div');\n const score = Number(level.score);\n\n // Assign background color class based on score\n if (score === 0) {\n levelDiv.className = 'tiny_cursive-rubric-level tiny_cursive-rubric-low';\n } else if (score <= 2) {\n levelDiv.className = 'tiny_cursive-rubric-level tiny_cursive-rubric-mid';\n } else {\n levelDiv.className = 'tiny_cursive-rubric-level tiny_cursive-rubric-high';\n }\n\n levelDiv.textContent = `${level.definition} / ${level.score}`;\n rubricDiv.appendChild(levelDiv);\n });\n\n wrapper.appendChild(rubricDiv);\n });\n\n return wrapper.innerHTML;\n }\n\n submissionStatus(submission) {\n const wrapper = this.create('div');\n\n const statusWrapper = this.create('div');\n statusWrapper.className = 'tiny_cursive-status-row';\n\n const statusName = this.create('span');\n statusName.textContent = `${this.status}:`;\n\n const statusValue = this.create('span');\n const isNew = submission?.current?.status === 'new';\n statusValue.textContent = isNew ? this.draftnot : this.draft;\n statusValue.className = `tiny_cursive-status-value ${isNew ? 'tiny_cursive-status-red' : 'tiny_cursive-status-green'}`;\n\n statusWrapper.append(statusName, statusValue);\n\n const modifiedWrapper = this.create('div');\n modifiedWrapper.className = 'tiny_cursive-status-row';\n\n const modifiedName = this.create('span');\n modifiedName.textContent = `${this.lastModified}: `;\n\n const modifiedValue = this.create('span');\n if (submission?.current?.timemodified) {\n const date = new Date(submission.current.timemodified * 1000);\n modifiedValue.textContent = this.formatDate(date);\n } else {\n modifiedValue.textContent = 'N/A';\n }\n modifiedWrapper.append(modifiedName, modifiedValue);\n\n const gradeWrapper = this.create('div');\n gradeWrapper.className = 'tiny_cursive-status-row';\n\n const gradeName = this.create('span');\n gradeName.textContent = `${this.gradings}: `;\n\n const gradeValue = this.create('span');\n\n if (submission?.grade) {\n gradeValue.textContent = Number(submission.grade.grade) > 0\n ? submission.grade.grade\n : this.gradenot;\n } else {\n gradeValue.textContent = this.gradenot;\n }\n\n gradeWrapper.append(gradeName, gradeValue);\n wrapper.append(statusWrapper, gradeWrapper, modifiedWrapper);\n return wrapper.innerHTML;\n }\n\n wordCounter(status) {\n const wordCount = this.create('div');\n const labelDiv = this.create('div');\n const label = this.create('span');\n const value = this.create('span');\n const icon = this.create('span');\n\n icon.className = 'me-2';\n icon.innerHTML = Icons.assignment;\n\n labelDiv.appendChild(icon);\n labelDiv.append(label);\n\n label.textContent = `${this.wordCount}:`;\n value.textContent = '0';\n value.className = 'text-primary';\n value.style.fontWeight = '600';\n value.style.fontSize = '14px';\n\n wordCount.className = 'bg-white rounded shadow-sm p-2 d-flex justify-content-between my-2';\n wordCount.append(labelDiv, value);\n wordCount.style.fontSize = '12px';\n\n const observer = new MutationObserver(() => {\n const newText = status.textContent.trim();\n value.textContent = `${newText.replace('words', '')}`;\n });\n\n observer.observe(status, {\n characterData: true,\n subtree: true,\n childList: true\n });\n\n return wordCount;\n }\n\n\n timerCountDown(timer) {\n\n let warningDiv = document.querySelector('#user-notifications > div');\n if (warningDiv) {\n let clone = warningDiv.cloneNode(true);\n clone.querySelector('button')?.remove();\n this.editor.notificationManager.open({\n text: clone.textContent,\n type: 'error'\n });\n }\n\n\n const timerCount = this.create('div');\n timerCount.className = 'bg-white rounded shadow-sm p-2 d-flex justify-content-between my-2';\n\n const labelDiv = this.create('div');\n const label = this.create('span');\n const value = this.create('span');\n const icon = this.create('span');\n icon.innerHTML = Icons.time;\n\n labelDiv.appendChild(icon);\n labelDiv.append(label);\n\n label.textContent = `${this.timeleft}: }`;\n value.textContent = '00:00:00';\n value.className = warningDiv ? 'text-danger' : 'text-primary';\n Object.assign(value.style, {\n fontWeight: '600',\n fontSize: '14px'\n });\n\n\n timerCount.append(labelDiv, value);\n timerCount.style.fontSize = '12px';\n if (timer) {\n const observer = new MutationObserver(() => {\n const newText = timer.textContent.trim();\n value.textContent = `${newText}`;\n });\n observer.observe(timer, {\n characterData: true,\n subtree: true,\n childList: true\n });\n } else {\n value.textContent = this.nolimit;\n }\n\n\n return timerCount;\n }\n\n\n generateStudentInfo(user, course) {\n\n const wrapper = this.create('div');\n\n const nameWrapper = this.create('div');\n const usernameWrapper = this.create('div');\n const courseWrapper = this.create('div');\n\n const nameLabel = this.create('span');\n const nameValue = this.create('span');\n const usernameLabel = this.create('span');\n const usernameValue = this.create('span');\n const courseLabel = this.create('span');\n const courseValue = this.create('span');\n\n nameLabel.textContent = `${this.name}`;\n nameValue.textContent = user.fullname;\n\n usernameLabel.textContent = `${this.userename}: `;\n usernameValue.textContent = user.username;\n\n courseLabel.textContent = `${this.course}: `;\n courseValue.textContent = course.title;\n\n nameWrapper.className = 'd-flex justify-content-between';\n usernameWrapper.className = 'd-flex justify-content-between';\n courseWrapper.className = 'd-flex justify-content-between';\n\n nameWrapper.append(nameLabel, nameValue);\n usernameWrapper.append(usernameLabel, usernameValue);\n courseWrapper.append(courseLabel, courseValue);\n\n wrapper.append(nameWrapper, usernameWrapper, courseWrapper);\n\n return wrapper.innerHTML;\n\n }\n\n generateImportantDates(open, due) {\n\n const wrapper = this.create('div');\n let openDate = null;\n let dueDate = null;\n\n const openedWrapper = this.create('div');\n const dueWrapper = this.create('div');\n const remainingWrapper = this.create('div');\n\n const openedLabel = this.create('span');\n const openedValue = this.create('span');\n const dueLabel = this.create('span');\n const dueValue = this.create('span');\n const remainingLabel = this.create('span');\n const remainingValue = this.create('span');\n if (this.module === 'quiz') {\n openDate = open * 1000;\n dueDate = due * 1000;\n } else {\n openDate = this.extractDate(open?.textContent);\n dueDate = this.extractDate(due?.textContent);\n }\n\n openedLabel.textContent = `${this.opened}: `;\n openedValue.textContent = this.formatDate(openDate ? new Date(openDate) : null);\n openedValue.className = 'text-dark';\n\n dueLabel.textContent = `${this.due}: `;\n dueValue.textContent = this.formatDate(dueDate ? new Date(dueDate) : null);\n dueValue.className = 'text-danger';\n\n remainingLabel.textContent = `${this.remaining}: `;\n remainingValue.textContent = this.calculateDate(dueDate);\n remainingValue.className = 'text-danger';\n\n openedWrapper.className = 'd-flex justify-content-between';\n dueWrapper.className = 'd-flex justify-content-between';\n remainingWrapper.className = 'd-flex align-items-center justify-content-between mt-2 pt-2 border-top';\n\n openedWrapper.append(openedLabel, openedValue);\n dueWrapper.append(dueLabel, dueValue);\n remainingWrapper.append(remainingLabel, remainingValue);\n\n wrapper.append(openedWrapper, dueWrapper, remainingWrapper);\n\n return wrapper.innerHTML;\n }\n\n formatDate(date) {\n if (!date) {\n return '-';\n }\n\n let options = {year: 'numeric', month: 'short', day: 'numeric', hour: 'numeric', minute: 'numeric', hour12: true};\n return date.toLocaleString('en-US', options);\n }\n\n extractDate(text) {\n if (!text) {\n return '-';\n }\n // Split on first colon and return the right part\n const parts = text?.split(':');\n if (parts.length > 1) {\n return parts.slice(1).join(':').trim();\n }\n\n return text.trim();\n }\n\n\n calculateDate(date) {\n if (!date) {\n return '-';\n }\n const date1 = new Date(date); // Due date (local time)\n const now = new Date(); // Current date/time\n\n // Calculate the difference in milliseconds\n const diffMs = date1 - now;\n\n // Convert to days, hours, minutes\n if (diffMs <= 0) {\n return \"Overdue\";\n } else {\n const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));\n const diffHours = Math.floor((diffMs / (1000 * 60 * 60)) % 24);\n\n return `${diffDays} days, ${diffHours} hours`;\n }\n\n }\n\n fullPageModule(module) {\n let current = this.module === 'quiz' ?\n document.getElementById(`${module}_ifr`) : document.querySelector(`#${module}_ifr`);\n\n let p1 = current.parentElement;\n let p2 = p1.parentElement;\n let p3 = p2.parentElement;\n let p4 = p3.parentElement;\n\n let statusBar = document.querySelector('.tox-statusbar__right-container > button');\n let assignName = document.querySelector('.page-context-header');\n let header = this.create('div');\n let btn = null;\n\n assignName.classList.remove('mb-2');\n header.id = 'tiny_cursive-fullpage-custom-header';\n Object.assign(header.style, {\n backgroundColor: 'white',\n display: 'flex',\n justifyContent: 'space-between'\n });\n\n if (this.module === 'quiz') {\n btn = document.querySelector('#mod_quiz-next-nav').cloneNode(true);\n btn.className = 'tiny_cursive-fullpage-submit-btn';\n btn.style.margin = '.5rem';\n } else {\n btn = this.create('input');\n btn.className = 'tiny_cursive-fullpage-submit-btn';\n btn.value = this.savechanges;\n btn.type = 'submit';\n btn.style.margin = '.5rem';\n }\n\n\n const leftSide = this.create('div');\n const rightSide = this.create('div');\n let commonStyle = {\n display: 'flex',\n alignItems: 'center',\n margin: '0 1rem'\n };\n\n Object.assign(leftSide.style, commonStyle);\n rightSide.id = 'tiny_cursive-fullpage-right-wrapper';\n Object.assign(rightSide.style, commonStyle);\n\n rightSide.appendChild(btn);\n leftSide.appendChild(assignName.cloneNode(true));\n\n header.appendChild(leftSide);\n header.appendChild(rightSide);\n\n p4.insertBefore(header, p4.firstChild);\n p2.style.backgroundColor = '#efefef';\n Object.assign(current.style, {\n width: '750px',\n minWidth: '750px',\n boxShadow: '0 10px 15px -3px rgb(0 0 0/0.1),0 4px 6px -4px rgb(0 0 0/0.1)'\n });\n\n Object.assign(p1.style, {\n display: 'flex',\n justifyContent: 'center',\n outline: 'none',\n margin: '2rem 0 0'\n });\n const style = this.create('style');\n style.id = 'tiny_cursive-fullpage-mode-style';\n style.textContent = `\n .tox.tox-edit-focus .tox-edit-area::before {\n opacity: 0;\n }`;\n document.head.appendChild(style);\n\n let iframeBody = current.contentDocument?.body || current.contentWindow?.document?.body;\n\n if (iframeBody) {\n iframeBody.style.padding = '0.5in';\n }\n p2.style.position = 'relative';\n document.getElementById('cursive-fullpagemode-sidebar')?.remove();\n\n let toggle = this.create('div');\n toggle.id = 'cursive-fullpagemode-sidebar-toggle';\n toggle.innerHTML = Icons.hamburger;\n p2.appendChild(toggle);\n p2.appendChild(this.docSideBar(statusBar));\n }\n\n normalizePage(editorId) {\n document.getElementById('tiny_cursive-fullpage-custom-header')?.remove();\n document.getElementById('cursive-fullpagemode-sidebar')?.remove();\n\n let current = document.getElementById(editorId);\n let p1 = current.parentElement;\n let p2 = p1.parentElement;\n\n Object.assign(p2.style, {\n backgroundColor: \"\",\n position: \"\"\n });\n\n Object.assign(current.style, {\n width: '',\n minWidth: '',\n boxShadow: '',\n });\n\n Object.assign(p1.style, {\n display: '',\n justifyContent: '',\n outline: '',\n margin: ''\n });\n\n p1.classList.remove('tiny-cursive-editor-container');\n\n let iframeBody = current.contentDocument?.body || current.contentWindow?.document?.body;\n if (iframeBody) {\n iframeBody.style.padding = '0';\n }\n document.head.querySelector('#tiny_cursive-fullpage-mode-style')?.remove();\n }\n\n checkForumSubject() {\n const form = document.querySelector('#tiny_cursive-fullpage-right-wrapper > input');\n const msg = this.subjectnot;\n\n if (form) {\n form.addEventListener('click', (e) => {\n const subjectInput = document.getElementById('id_subject');\n let content = this.editor.getContent().trim();\n if (!subjectInput || subjectInput.value.trim() === '' || content === '') {\n e.preventDefault();\n e.stopPropagation();\n this.editor.windowManager.alert(msg);\n }\n });\n }\n }\n\n getSidebarTitle() {\n const [assign, discus, quiz, lesson] = this.getText('sbTitle');\n switch (this.module) {\n case 'assign':\n return {title: assign, icon: Icons.assignment};\n case 'forum':\n return {title: discus, icon: Icons.forum};\n case 'lesson':\n return {title: lesson, icon: Icons.forum};\n case 'quiz':\n return {title: quiz, icon: Icons.quiz};\n default:\n return {title: 'Page', icon: Icons.quiz};\n }\n }\n\n getTimerBlock(module) {\n switch (module) {\n case 'assign':\n return document.querySelector('#mod_assign_timelimit_block > div > div');\n case 'forum':\n return document.querySelector('#mod_forum_timelimit_block');\n case 'lesson':\n return document.querySelector('#lesson-timer');\n case 'quiz':\n return document.querySelector('#quiz-time-left');\n default:\n return null;\n }\n }\n\n getQuestionId(editoId) {\n try {\n if (!editoId || typeof editoId !== 'string') {\n return '';\n }\n return editoId.replace(/^q(\\d+):(\\d+)_.*$/, \"$1-$2\");\n } catch (error) {\n window.console.error('Error getting question ID:', error);\n return '';\n }\n }\n\n initStrings() {\n [\n this.details,\n this.studentInfo,\n this.progress,\n this.description,\n this.replyingto,\n this.answeringto,\n this.importantdates,\n this.rubrics,\n this.subStatus,\n this.status,\n this.draft,\n this.draftnot,\n this.lastModified,\n this.gradings,\n this.gradenot,\n this.wordCount,\n this.timeleft,\n this.nolimit,\n this.name,\n this.userename,\n this.course,\n this.opened,\n this.due,\n this.overdue,\n this.remaining,\n this.savechanges,\n this.subjectnot\n ] = this.getText('docSideBar');\n }\n\n getText(key) {\n return JSON.parse(localStorage.getItem(key)) || [];\n }\n\n create(tag) {\n return document.createElement(tag);\n }\n\n}"],"names":["constructor","User","Rubrics","submission","modulename","editor","quizInfo","module","moduleIcon","Icons","assignment","initStrings","normalMode","id","this","normalizePage","fullPageMode","fullPageModule","_this$editor2","forum","_this$editor3","_this$editor4","quiz","_this$editor5","lesson","_this$editor6","docSideBar","status","replyId","URL","window","location","href","searchParams","get","toggle","document","querySelector","timelimitBlock","getTimerBlock","headerInfo","getSidebarTitle","progressBar","courseName","courseDes","Dates","openDate","dueDate","container","create","Object","assign","className","style","width","overflow","crossBtn","innerHTML","close","addEventListener","transition","display","btnWrapper","padding","position","top","backgroundColor","append","header","headerTitle","textContent","title","details","fontWeight","headerIcon","prepend","cloneNode","wordCount","wordCounter","timerCountDown","content","createBox","bg","titleColor","icon","people","studentInfo","bodyHTML","generateStudentInfo","progress","trim","description","checkForumSubject","replyPost","replyingto","_this$editor7","questionId","getQuestionId","_this$editor8","question","intro","atob","answeringto","Number","open","time","importantdates","generateImportantDates","keys","length","rubrics","generateRubrics","subStatus","submissionStatus","box","heading","body","wrapper","forEach","rubric","rubricDiv","appendChild","values","levels","level","levelDiv","score","definition","statusWrapper","statusName","statusValue","isNew","current","draftnot","draft","modifiedWrapper","modifiedName","lastModified","modifiedValue","_submission$current2","timemodified","date","Date","formatDate","gradeWrapper","gradeName","gradings","gradeValue","grade","gradenot","labelDiv","label","value","fontSize","MutationObserver","newText","replace","observe","characterData","subtree","childList","timer","warningDiv","clone","remove","notificationManager","text","type","timerCount","timeleft","nolimit","user","course","nameWrapper","usernameWrapper","courseWrapper","nameLabel","nameValue","usernameLabel","usernameValue","courseLabel","courseValue","name","fullname","userename","username","due","openedWrapper","dueWrapper","remainingWrapper","openedLabel","openedValue","dueLabel","dueValue","remainingLabel","remainingValue","extractDate","opened","remaining","calculateDate","toLocaleString","year","month","day","hour","minute","hour12","parts","split","slice","join","diffMs","Math","floor","getElementById","p1","parentElement","p2","p4","statusBar","assignName","btn","classList","justifyContent","margin","savechanges","leftSide","rightSide","commonStyle","alignItems","insertBefore","firstChild","minWidth","boxShadow","outline","head","iframeBody","contentDocument","contentWindow","_current$contentWindo","_current$contentWindo2","hamburger","editorId","_current$contentWindo3","_current$contentWindo4","form","msg","subjectnot","e","subjectInput","getContent","preventDefault","stopPropagation","windowManager","alert","discus","getText","editoId","error","console","overdue","key","JSON","parse","localStorage","getItem","tag","createElement"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"document_view.min.js","sources":["../src/document_view.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 * This module provides functionality for document view management in the Tiny editor,\n * including full page mode display and sidebar information\n * @module tiny_cursive/document_view\n * @copyright 2025 Cursive Technology, Inc. \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Icons from 'tiny_cursive/svg_repo';\nexport default class DocumentView {\n\n constructor(User, Rubrics, submission, modulename, editor, quizInfo) {\n this.User = User;\n this.Rubrics = Rubrics;\n this.submission = submission;\n this.module = modulename;\n this.editor = editor;\n this.moduleIcon = Icons.assignment;\n this.quizInfo = quizInfo;\n this.initStrings();\n }\n\n normalMode() {\n let id = this.editor?.id + \"_ifr\";\n if (this.module === 'assign') {\n this.normalizePage(id);\n } else if (this.module === 'quiz') {\n this.normalizePage(id);\n } else if (this.module === 'forum') {\n this.normalizePage(id);\n } else if (this.module === 'lesson') {\n this.normalizePage(id);\n } else if(this.module === 'pdfannotator') {\n this.normalizePage(id);\n }\n }\n\n fullPageMode() {\n\n if (this.module === 'assign') {\n this.moduleIcon = Icons.assignment;\n this.fullPageModule(this.editor?.id);\n } else if (this.module === 'forum') {\n this.moduleIcon = Icons.forum;\n this.fullPageModule(this.editor?.id);\n } else if (this.module === 'quiz' && this.editor?.id) {\n this.moduleIcon = Icons.quiz;\n this.fullPageModule(this.editor?.id);\n } else if (this.module === 'lesson') {\n this.moduleIcon = Icons.lesson;\n this.fullPageModule(this.editor?.id);\n } else if (this.module === 'pdfannotator') {\n this.moduleIcon = Icons.pdfannotator;\n this.fullPageModule(this.editor?.id);\n }\n }\n\n docSideBar(status) {\n\n const url = new URL(window.location.href);\n const replyId = url.searchParams.get(\"reply\");\n const toggle = document.querySelector('#cursive-fullpagemode-sidebar-toggle');\n const timelimitBlock = this.getTimerBlock(this.module);\n const headerInfo = this.getSidebarTitle();\n const progressBar = document.querySelector('.box.progress_bar');\n\n const courseName = document.querySelector('#page-navbar > nav > ol > li:nth-child(1) > a');\n const courseDes = document.querySelector('#intro');\n const Dates = document.querySelector('.activity-dates');\n\n let openDate = Dates?.querySelector('div:nth-child(1)');\n let dueDate = Dates?.querySelector('div:nth-child(2)');\n\n const container = this.create('div');\n Object.assign(container, {\n id: 'cursive-fullpagemode-sidebar',\n className: 'bg-white h-100 shadow'\n });\n Object.assign(container.style, {\n width: '300px',\n overflow: 'auto'\n });\n\n const crossBtn = this.create('span');\n Object.assign(crossBtn, {\n id: 'cursive-collapse-sidebar',\n className: 'btn p-2',\n innerHTML: Icons.close\n });\n\n crossBtn.addEventListener('click', () => {\n container.style.transition = 'width 0.3s ease';\n container.style.width = '0';\n toggle.style.display = 'flex';\n });\n toggle?.addEventListener('click', function() {\n toggle.style.display = 'none';\n container.style.width = '300px';\n });\n\n const btnWrapper = this.create('div');\n Object.assign(btnWrapper, {\n padding: '0 1rem',\n position: 'sticky',\n top: '0',\n backgroundColor: 'white'\n });\n btnWrapper.append(crossBtn);\n\n\n const header = this.create('div');\n header.className = 'border-bottom p-3 bg-light';\n Object.assign(header.style, {\n position: 'sticky',\n top: '0'\n });\n\n const headerTitle = this.create('h3');\n headerTitle.className = 'mb-3 d-flex align-items-center';\n headerTitle.textContent = `${headerInfo.title} ${this.details}`;\n headerTitle.style.fontWeight = '600';\n\n const headerIcon = document.querySelector('.page-header-image > div');\n if (headerIcon) {\n headerTitle.prepend(headerIcon.cloneNode(true));\n }\n\n let wordCount = this.wordCounter(status);\n if (timelimitBlock?.textContent) {\n header.append(headerTitle, wordCount, this.timerCountDown(timelimitBlock));\n } else {\n header.append(headerTitle, wordCount);\n }\n\n const content = this.create('div');\n content.className = 'p-3';\n\n content.append(\n this.createBox({\n bg: 'bg-info',\n titleColor: 'text-info',\n icon: Icons.people,\n title: this.studentInfo,\n bodyHTML: this.generateStudentInfo(this.User, courseName)\n })\n );\n\n if (this.module === 'lesson' && progressBar) {\n content.append(\n this.createBox({\n bg: 'bg-gray',\n titleColor: 'text-dark',\n icon: this.moduleIcon,\n title: this.progress,\n bodyHTML: progressBar.innerHTML\n })\n );\n }\n\n if (courseDes && courseDes?.textContent.trim() !== '') {\n let fileSubDiv = document.querySelectorAll('.fileuploadsubmission');\n if (fileSubDiv) {\n fileSubDiv.forEach(Element => {\n Element.style.verticalAlign = 'middle';\n });\n }\n content.append(\n this.createBox({\n bg: 'bg-gray',\n titleColor: 'text-dark',\n icon: this.moduleIcon,\n title: `${this.getSidebarTitle().title} ${this.description}`,\n bodyHTML: courseDes.innerHTML\n })\n );\n }\n\n if (this.module === 'forum' && replyId) {\n this.checkForumSubject();\n let replyPost = document.querySelector(`#post-content-${replyId}`);\n if (replyPost?.textContent.trim()) {\n content.append(\n this.createBox({\n bg: 'bg-gray',\n titleColor: 'text-dark',\n icon: this.moduleIcon,\n title: this.replyingto,\n bodyHTML: replyPost.textContent.trim()\n })\n );\n }\n }\n\n if (this.module === 'quiz' && this.editor?.id) {\n\n let questionId = this.getQuestionId(this.editor?.id);\n let question = document.querySelector(`#question-${questionId} .qtext`);\n let intro = atob(this.quizInfo.intro);\n\n if (question?.textContent.trim()) {\n content.append(\n this.createBox({\n bg: 'bg-amber',\n titleColor: 'text-dark',\n icon: this.moduleIcon,\n title: this.answeringto,\n bodyHTML: question.textContent\n })\n );\n }\n\n if (intro && intro.trim() !== '') {\n content.append(\n this.createBox({\n bg: 'bg-gray',\n titleColor: 'text-dark',\n icon: this.moduleIcon,\n title: `${this.quiz} ${this.description}`,\n bodyHTML: intro\n })\n );\n }\n\n if (Number(this.quizInfo.open)) {\n content.append(\n this.createBox({\n bg: 'bg-amber',\n titleColor: 'text-dark',\n icon: Icons.time,\n title: this.importantdates,\n bodyHTML: this.generateImportantDates(Number(this.quizInfo.open), Number(this.quizInfo.close))\n })\n );\n }\n }\n\n if (Object.keys(this.Rubrics).length) {\n content.append(\n this.createBox({\n bg: 'bg-gray',\n titleColor: 'text-dark',\n icon: this.moduleIcon,\n title: this.rubrics,\n bodyHTML: this.generateRubrics(this.Rubrics)\n })\n );\n }\n\n if (Dates) {\n content.append(\n this.createBox({\n bg: 'bg-amber',\n titleColor: 'text-dark',\n icon: Icons.time,\n title: this.importantdates,\n bodyHTML: this.generateImportantDates(openDate, dueDate)\n })\n );\n }\n if (this.module === 'assign') {\n content.append(\n this.createBox({\n bg: 'bg-green',\n titleColor: 'text-success',\n icon: this.moduleIcon,\n title: this.subStatus,\n bodyHTML: this.submissionStatus(this.submission)\n })\n );\n }\n\n container.append(btnWrapper, header, content);\n return container;\n\n }\n // Helper to create info boxes\n createBox({bg, titleColor, icon, title, bodyHTML}) {\n const box = this.create('div');\n box.className = `tiny_cursive-fullpage-card ${bg}`;\n\n const heading = this.create('h4');\n heading.className = `tiny_cursive-fullpage-card-header ${titleColor} d-flex align-items-center`;\n heading.innerHTML = `${icon} ${title}`;\n\n const body = this.create('div');\n body.className = `tiny_cursive-fullpage-card-body`;\n body.innerHTML = bodyHTML;\n\n box.append(heading, body);\n return box;\n }\n\n generateRubrics(Rubrics) {\n const wrapper = this.create('div');\n\n Rubrics.forEach(rubric => {\n const rubricDiv = this.create('div');\n rubricDiv.className = 'tiny_cursive-rubric-card';\n\n const title = this.create('h3');\n title.className = 'tiny_cursive-rubric-title';\n title.textContent = rubric.description;\n rubricDiv.appendChild(title);\n\n Object.values(rubric.levels).forEach(level => {\n const levelDiv = this.create('div');\n const score = Number(level.score);\n\n // Assign background color class based on score\n if (score === 0) {\n levelDiv.className = 'tiny_cursive-rubric-level tiny_cursive-rubric-low';\n } else if (score <= 2) {\n levelDiv.className = 'tiny_cursive-rubric-level tiny_cursive-rubric-mid';\n } else {\n levelDiv.className = 'tiny_cursive-rubric-level tiny_cursive-rubric-high';\n }\n\n levelDiv.textContent = `${level.definition} / ${level.score}`;\n rubricDiv.appendChild(levelDiv);\n });\n\n wrapper.appendChild(rubricDiv);\n });\n\n return wrapper.innerHTML;\n }\n\n submissionStatus(submission) {\n const wrapper = this.create('div');\n\n const statusWrapper = this.create('div');\n statusWrapper.className = 'tiny_cursive-status-row';\n\n const statusName = this.create('span');\n statusName.textContent = `${this.status}:`;\n\n const statusValue = this.create('span');\n const isNew = submission?.current?.status === 'new';\n statusValue.textContent = isNew ? this.draftnot : this.draft;\n statusValue.className = `tiny_cursive-status-value ${isNew ? 'tiny_cursive-status-red' : 'tiny_cursive-status-green'}`;\n\n statusWrapper.append(statusName, statusValue);\n\n const modifiedWrapper = this.create('div');\n modifiedWrapper.className = 'tiny_cursive-status-row';\n\n const modifiedName = this.create('span');\n modifiedName.textContent = `${this.lastModified}: `;\n\n const modifiedValue = this.create('span');\n if (submission?.current?.timemodified) {\n const date = new Date(submission.current.timemodified * 1000);\n modifiedValue.textContent = this.formatDate(date);\n } else {\n modifiedValue.textContent = 'N/A';\n }\n modifiedWrapper.append(modifiedName, modifiedValue);\n\n const gradeWrapper = this.create('div');\n gradeWrapper.className = 'tiny_cursive-status-row';\n\n const gradeName = this.create('span');\n gradeName.textContent = `${this.gradings}: `;\n\n const gradeValue = this.create('span');\n\n if (submission?.grade) {\n gradeValue.textContent = Number(submission.grade.grade) > 0\n ? submission.grade.grade\n : this.gradenot;\n } else {\n gradeValue.textContent = this.gradenot;\n }\n\n gradeWrapper.append(gradeName, gradeValue);\n wrapper.append(statusWrapper, gradeWrapper, modifiedWrapper);\n return wrapper.innerHTML;\n }\n\n wordCounter(status) {\n const wordCount = this.create('div');\n const labelDiv = this.create('div');\n const label = this.create('span');\n const value = this.create('span');\n const icon = this.create('span');\n\n icon.className = 'me-2';\n icon.innerHTML = Icons.assignment;\n\n labelDiv.appendChild(icon);\n labelDiv.append(label);\n\n label.textContent = `${this.wordCount}:`;\n value.textContent = '0';\n value.className = 'text-primary';\n value.style.fontWeight = '600';\n value.style.fontSize = '14px';\n\n wordCount.className = 'bg-white rounded shadow-sm p-2 d-flex justify-content-between my-2';\n wordCount.append(labelDiv, value);\n wordCount.style.fontSize = '12px';\n\n const observer = new MutationObserver(() => {\n const newText = status.textContent.trim();\n value.textContent = `${newText.replace('words', '')}`;\n });\n\n observer.observe(status, {\n characterData: true,\n subtree: true,\n childList: true\n });\n\n return wordCount;\n }\n\n\n timerCountDown(timer) {\n\n let warningDiv = document.querySelector('#user-notifications > div');\n if (warningDiv) {\n let clone = warningDiv.cloneNode(true);\n clone.querySelector('button')?.remove();\n this.editor.notificationManager.open({\n text: clone.textContent,\n type: 'error'\n });\n }\n\n\n const timerCount = this.create('div');\n timerCount.className = 'bg-white rounded shadow-sm p-2 d-flex justify-content-between my-2';\n\n const labelDiv = this.create('div');\n const label = this.create('span');\n const value = this.create('span');\n const icon = this.create('span');\n icon.innerHTML = Icons.time;\n\n labelDiv.appendChild(icon);\n labelDiv.append(label);\n\n label.textContent = `${this.timeleft}:`;\n value.textContent = '00:00:00';\n value.className = warningDiv ? 'text-danger' : 'text-primary';\n Object.assign(value.style, {\n fontWeight: '600',\n fontSize: '14px'\n });\n\n\n timerCount.append(labelDiv, value);\n timerCount.style.fontSize = '12px';\n if (timer) {\n const observer = new MutationObserver(() => {\n const newText = timer.textContent.trim();\n value.textContent = `${newText}`;\n });\n observer.observe(timer, {\n characterData: true,\n subtree: true,\n childList: true\n });\n } else {\n value.textContent = this.nolimit;\n }\n\n\n return timerCount;\n }\n\n\n generateStudentInfo(user, course) {\n\n const wrapper = this.create('div');\n\n const nameWrapper = this.create('div');\n const usernameWrapper = this.create('div');\n const courseWrapper = this.create('div');\n\n const nameLabel = this.create('strong');\n const nameValue = this.create('span');\n const usernameLabel = this.create('strong');\n const usernameValue = this.create('span');\n const courseLabel = this.create('strong');\n const courseValue = this.create('span');\n\n nameLabel.textContent = `${this.name}`;\n nameValue.textContent = user.fullname;\n\n usernameLabel.textContent = `${this.userename}: `;\n usernameValue.textContent = user.username;\n\n courseLabel.textContent = `${this.course}: `;\n courseValue.textContent = course.title;\n\n usernameLabel.className = 'cfw-bold me-2';\n usernameValue.className = 'cursiveFw-wrap';\n courseLabel.className = 'cfw-bold me-2';\n courseValue.className = 'cursiveFw-wrap';\n nameLabel.className = 'cfw-bold me-2';\n nameValue.className = 'cursiveFw-wrap';\n\n nameWrapper.append(nameLabel, nameValue);\n usernameWrapper.append(usernameLabel, usernameValue);\n courseWrapper.append(courseLabel, courseValue);\n\n wrapper.append(nameWrapper, usernameWrapper, courseWrapper);\n\n return wrapper.innerHTML;\n\n }\n\n generateImportantDates(open, due) {\n\n const wrapper = this.create('div');\n let openDate = null;\n let dueDate = null;\n\n const openedWrapper = this.create('div');\n const dueWrapper = this.create('div');\n const remainingWrapper = this.create('div');\n\n const openedLabel = this.create('span');\n const openedValue = this.create('span');\n const dueLabel = this.create('span');\n const dueValue = this.create('span');\n const remainingLabel = this.create('span');\n const remainingValue = this.create('span');\n if (this.module === 'quiz') {\n openDate = open * 1000;\n dueDate = due * 1000;\n } else {\n openDate = this.extractDate(open?.textContent);\n dueDate = this.extractDate(due?.textContent);\n }\n\n openedLabel.textContent = `${this.opened}: `;\n openedValue.textContent = this.formatDate(openDate ? new Date(openDate) : null);\n openedValue.className = 'text-dark';\n\n dueLabel.textContent = `${this.due}: `;\n dueValue.textContent = this.formatDate(dueDate ? new Date(dueDate) : null);\n dueValue.className = 'text-danger';\n\n remainingLabel.textContent = `${this.remaining}: `;\n remainingValue.textContent = this.calculateDate(dueDate);\n remainingValue.className = 'text-danger';\n\n openedWrapper.className = 'd-flex justify-content-between';\n dueWrapper.className = 'd-flex justify-content-between';\n remainingWrapper.className = 'd-flex align-items-center justify-content-between mt-2 pt-2 border-top';\n\n openedWrapper.append(openedLabel, openedValue);\n dueWrapper.append(dueLabel, dueValue);\n remainingWrapper.append(remainingLabel, remainingValue);\n\n wrapper.append(openedWrapper, dueWrapper, remainingWrapper);\n\n return wrapper.innerHTML;\n }\n\n formatDate(date) {\n if (!date) {\n return '-';\n }\n\n let options = {year: 'numeric', month: 'short', day: 'numeric', hour: 'numeric', minute: 'numeric', hour12: true};\n return date.toLocaleString('en-US', options);\n }\n\n extractDate(text) {\n if (!text) {\n return '-';\n }\n // Split on first colon and return the right part\n const parts = text?.split(':');\n if (parts.length > 1) {\n return parts.slice(1).join(':').trim();\n }\n\n return text.trim();\n }\n\n\n calculateDate(date) {\n if (!date) {\n return '-';\n }\n const date1 = new Date(date); // Due date (local time)\n const now = new Date(); // Current date/time\n\n // Calculate the difference in milliseconds\n const diffMs = date1 - now;\n\n // Convert to days, hours, minutes\n if (diffMs <= 0) {\n return \"Overdue\";\n } else {\n const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));\n const diffHours = Math.floor((diffMs / (1000 * 60 * 60)) % 24);\n\n return `${diffDays} days, ${diffHours} hours`;\n }\n\n }\n\n fullPageModule(module) {\n let current = this.module === 'quiz' ?\n document.getElementById(`${module}_ifr`) : document.querySelector(`#${module}_ifr`);\n\n let p1 = current.parentElement;\n let p2 = p1.parentElement;\n let p3 = p2.parentElement;\n let p4 = p3.parentElement;\n\n let statusBar = document.querySelector('.tox-statusbar__right-container > button');\n let assignName = document.querySelector('.page-context-header');\n let header = this.create('div');\n let btn = null;\n\n assignName.classList.remove('mb-2');\n header.id = 'tiny_cursive-fullpage-custom-header';\n Object.assign(header.style, {\n backgroundColor: 'white',\n display: 'flex',\n justifyContent: 'space-between'\n });\n\n if (this.module === 'quiz') {\n btn = document.querySelector('#mod_quiz-next-nav').cloneNode(true);\n btn.className = 'tiny_cursive-fullpage-submit-btn';\n btn.style.margin = '.5rem';\n } else {\n btn = this.create('input');\n btn.className = 'tiny_cursive-fullpage-submit-btn';\n btn.value = this.savechanges;\n btn.type = 'submit';\n btn.style.margin = '.5rem';\n }\n\n if (this.module === 'pdfannotator') {\n const style = document.createElement('style');\n style.id = 'cursiveForceStyle';\n style.textContent = `\n .path-mod-pdfannotator #comment-wrapper h4,\n .path-mod-pdfannotator #comment-nav {\n margin: 0 !important;\n }\n `;\n document.head.appendChild(style);\n }\n\n const leftSide = this.create('div');\n const rightSide = this.create('div');\n let commonStyle = {\n display: 'flex',\n alignItems: 'center',\n margin: '0 1rem'\n };\n\n Object.assign(leftSide.style, commonStyle);\n rightSide.id = 'tiny_cursive-fullpage-right-wrapper';\n Object.assign(rightSide.style, commonStyle);\n\n rightSide.appendChild(btn);\n leftSide.appendChild(assignName.cloneNode(true));\n\n header.appendChild(leftSide);\n header.appendChild(rightSide);\n\n p4.insertBefore(header, p4.firstChild);\n p2.style.backgroundColor = '#efefef';\n Object.assign(current.style, {\n width: '750px',\n minWidth: '750px',\n boxShadow: '0 10px 15px -3px rgb(0 0 0/0.1),0 4px 6px -4px rgb(0 0 0/0.1)'\n });\n\n Object.assign(p1.style, {\n display: 'flex',\n justifyContent: 'center',\n outline: 'none',\n margin: '2rem 0 0'\n });\n const style = this.create('style');\n style.id = 'tiny_cursive-fullpage-mode-style';\n style.textContent = `\n .tox.tox-edit-focus .tox-edit-area::before {\n opacity: 0;\n }`;\n document.head.appendChild(style);\n\n let iframeBody = current.contentDocument?.body || current.contentWindow?.document?.body;\n\n if (iframeBody) {\n iframeBody.style.padding = '0.5in';\n }\n p2.style.position = 'relative';\n document.getElementById('cursive-fullpagemode-sidebar')?.remove();\n\n let toggle = this.create('div');\n toggle.id = 'cursive-fullpagemode-sidebar-toggle';\n toggle.innerHTML = Icons.hamburger;\n p2.appendChild(toggle);\n p2.appendChild(this.docSideBar(statusBar));\n }\n\n normalizePage(editorId) {\n document.getElementById('tiny_cursive-fullpage-custom-header')?.remove();\n document.getElementById('cursive-fullpagemode-sidebar')?.remove();\n\n let current = document.getElementById(editorId);\n let p1 = current.parentElement;\n let p2 = p1.parentElement;\n\n Object.assign(p2.style, {\n backgroundColor: \"\",\n position: \"\"\n });\n\n Object.assign(current.style, {\n width: '',\n minWidth: '',\n boxShadow: '',\n });\n\n Object.assign(p1.style, {\n display: '',\n justifyContent: '',\n outline: '',\n margin: ''\n });\n\n p1.classList.remove('tiny-cursive-editor-container');\n\n let iframeBody = current.contentDocument?.body || current.contentWindow?.document?.body;\n if (iframeBody) {\n iframeBody.style.padding = '0';\n }\n document.head.querySelector('#tiny_cursive-fullpage-mode-style')?.remove();\n document.head.querySelector('#cursiveForceStyle')?.remove();\n }\n\n checkForumSubject() {\n const form = document.querySelector('#tiny_cursive-fullpage-right-wrapper > input');\n const msg = this.subjectnot;\n\n if (form) {\n form.addEventListener('click', (e) => {\n const subjectInput = document.getElementById('id_subject');\n let content = this.editor.getContent().trim();\n if (!subjectInput || subjectInput.value.trim() === '' || content === '') {\n e.preventDefault();\n e.stopPropagation();\n this.editor.windowManager.alert(msg);\n }\n });\n }\n }\n\n getSidebarTitle() {\n const [assign, discus, quiz, lesson] = this.getText('sbTitle');\n switch (this.module) {\n case 'assign':\n return {title: assign, icon: Icons.assignment};\n case 'forum':\n return {title: discus, icon: Icons.forum};\n case 'lesson':\n return {title: lesson, icon: Icons.forum};\n case 'quiz':\n return {title: quiz, icon: Icons.quiz};\n case 'pdfannotator':\n return {title: 'PDF Annotation', icon: Icons.pdfannotator};\n default:\n return {title: 'Page', icon: Icons.quiz};\n }\n }\n\n getTimerBlock(module) {\n switch (module) {\n case 'assign':\n return document.querySelector('#mod_assign_timelimit_block > div > div');\n case 'forum':\n return document.querySelector('#mod_forum_timelimit_block');\n case 'lesson':\n return document.querySelector('#lesson-timer');\n case 'quiz':\n return document.querySelector('#quiz-time-left');\n default:\n return null;\n }\n }\n\n getQuestionId(editoId) {\n try {\n if (!editoId || typeof editoId !== 'string') {\n return '';\n }\n return editoId.replace(/^q(\\d+):(\\d+)_.*$/, \"$1-$2\");\n } catch (error) {\n window.console.error('Error getting question ID:', error);\n return '';\n }\n }\n\n initStrings() {\n [\n this.details,\n this.studentInfo,\n this.progress,\n this.description,\n this.replyingto,\n this.answeringto,\n this.importantdates,\n this.rubrics,\n this.subStatus,\n this.status,\n this.draft,\n this.draftnot,\n this.lastModified,\n this.gradings,\n this.gradenot,\n this.wordCount,\n this.timeleft,\n this.nolimit,\n this.name,\n this.userename,\n this.course,\n this.opened,\n this.due,\n this.overdue,\n this.remaining,\n this.savechanges,\n this.subjectnot\n ] = this.getText('docSideBar');\n }\n\n getText(key) {\n return JSON.parse(localStorage.getItem(key)) || [];\n }\n\n create(tag) {\n return document.createElement(tag);\n }\n\n}"],"names":["constructor","User","Rubrics","submission","modulename","editor","quizInfo","module","moduleIcon","Icons","assignment","initStrings","normalMode","id","this","normalizePage","fullPageMode","fullPageModule","_this$editor2","forum","_this$editor3","_this$editor4","quiz","_this$editor5","lesson","_this$editor6","pdfannotator","_this$editor7","docSideBar","status","replyId","URL","window","location","href","searchParams","get","toggle","document","querySelector","timelimitBlock","getTimerBlock","headerInfo","getSidebarTitle","progressBar","courseName","courseDes","Dates","openDate","dueDate","container","create","Object","assign","className","style","width","overflow","crossBtn","innerHTML","close","addEventListener","transition","display","btnWrapper","padding","position","top","backgroundColor","append","header","headerTitle","textContent","title","details","fontWeight","headerIcon","prepend","cloneNode","wordCount","wordCounter","timerCountDown","content","createBox","bg","titleColor","icon","people","studentInfo","bodyHTML","generateStudentInfo","progress","trim","fileSubDiv","querySelectorAll","forEach","Element","verticalAlign","description","checkForumSubject","replyPost","replyingto","_this$editor8","questionId","getQuestionId","_this$editor9","question","intro","atob","answeringto","Number","open","time","importantdates","generateImportantDates","keys","length","rubrics","generateRubrics","subStatus","submissionStatus","box","heading","body","wrapper","rubric","rubricDiv","appendChild","values","levels","level","levelDiv","score","definition","statusWrapper","statusName","statusValue","isNew","current","draftnot","draft","modifiedWrapper","modifiedName","lastModified","modifiedValue","_submission$current2","timemodified","date","Date","formatDate","gradeWrapper","gradeName","gradings","gradeValue","grade","gradenot","labelDiv","label","value","fontSize","MutationObserver","newText","replace","observe","characterData","subtree","childList","timer","warningDiv","clone","remove","notificationManager","text","type","timerCount","timeleft","nolimit","user","course","nameWrapper","usernameWrapper","courseWrapper","nameLabel","nameValue","usernameLabel","usernameValue","courseLabel","courseValue","name","fullname","userename","username","due","openedWrapper","dueWrapper","remainingWrapper","openedLabel","openedValue","dueLabel","dueValue","remainingLabel","remainingValue","extractDate","opened","remaining","calculateDate","toLocaleString","year","month","day","hour","minute","hour12","parts","split","slice","join","diffMs","Math","floor","getElementById","p1","parentElement","p2","p4","statusBar","assignName","btn","classList","justifyContent","margin","savechanges","createElement","head","leftSide","rightSide","commonStyle","alignItems","insertBefore","firstChild","minWidth","boxShadow","outline","iframeBody","contentDocument","contentWindow","_current$contentWindo","_current$contentWindo2","hamburger","editorId","_current$contentWindo3","_current$contentWindo4","form","msg","subjectnot","e","subjectInput","getContent","preventDefault","stopPropagation","windowManager","alert","discus","getText","editoId","error","console","overdue","key","JSON","parse","localStorage","getItem","tag"],"mappings":"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"} \ No newline at end of file diff --git a/amd/build/plugin.min.js b/amd/build/plugin.min.js index cbbc0ab8..02dbc830 100644 --- a/amd/build/plugin.min.js +++ b/amd/build/plugin.min.js @@ -1,3 +1,3 @@ -define("tiny_cursive/plugin",["exports","editor_tiny/loader","editor_tiny/utils","./common","./autosaver","core/ajax"],(function(_exports,_loader,_utils,_common,Autosaver,_ajax){var obj;function _getRequireWildcardCache(nodeInterop){if("function"!=typeof WeakMap)return null;var cacheBabelInterop=new WeakMap,cacheNodeInterop=new WeakMap;return(_getRequireWildcardCache=function(nodeInterop){return nodeInterop?cacheNodeInterop:cacheBabelInterop})(nodeInterop)}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,Autosaver=function(obj,nodeInterop){if(!nodeInterop&&obj&&obj.__esModule)return obj;if(null===obj||"object"!=typeof obj&&"function"!=typeof obj)return{default:obj};var cache=_getRequireWildcardCache(nodeInterop);if(cache&&cache.has(obj))return cache.get(obj);var newObj={},hasPropertyDescriptor=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var key in obj)if("default"!==key&&Object.prototype.hasOwnProperty.call(obj,key)){var desc=hasPropertyDescriptor?Object.getOwnPropertyDescriptor(obj,key):null;desc&&(desc.get||desc.set)?Object.defineProperty(newObj,key,desc):newObj[key]=obj[key]}newObj.default=obj,cache&&cache.set(obj,newObj);return newObj}(Autosaver),_ajax=(obj=_ajax)&&obj.__esModule?obj:{default:obj};var _default=new Promise(((resolve,reject)=>{const page=["page-mod-assign-editsubmission","page-mod-quiz-attempt","page-mod-forum-view","page-mod-forum-post","page-mod-lesson-view"];Promise.all([(0,_loader.getTinyMCE)(),(0,_utils.getPluginMetadata)(_common.component,_common.pluginName)]).then((_ref=>{let[tinyMCE,pluginMetadata]=_ref;return tinyMCE.PluginManager.add(_common.pluginName,(editor=>(_ajax.default.call([{methodname:"cursive_get_config",args:{courseid:M.cfg.courseId,cmid:M.cfg.contextInstanceId}}])[0].done((data=>{data.status&&page.includes(document.body.id)&&data.mod_state&&Autosaver.register(editor,data.sync_interval,data.userid,data.apikey_status,JSON.parse(data.plugins),JSON.parse(data.rubrics),JSON.parse(data.submission),JSON.parse(data.quizinfo),data.pastesetting)})).fail((error=>{window.console.error("Error getting cursive config:",error)})),pluginMetadata))),resolve(_common.pluginName)})).catch((error=>{reject(error)}))}));return _exports.default=_default,_exports.default})); +define("tiny_cursive/plugin",["exports","editor_tiny/loader","editor_tiny/utils","./common","./autosaver","core/ajax"],(function(_exports,_loader,_utils,_common,Autosaver,_ajax){var obj;function _getRequireWildcardCache(nodeInterop){if("function"!=typeof WeakMap)return null;var cacheBabelInterop=new WeakMap,cacheNodeInterop=new WeakMap;return(_getRequireWildcardCache=function(nodeInterop){return nodeInterop?cacheNodeInterop:cacheBabelInterop})(nodeInterop)}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,Autosaver=function(obj,nodeInterop){if(!nodeInterop&&obj&&obj.__esModule)return obj;if(null===obj||"object"!=typeof obj&&"function"!=typeof obj)return{default:obj};var cache=_getRequireWildcardCache(nodeInterop);if(cache&&cache.has(obj))return cache.get(obj);var newObj={},hasPropertyDescriptor=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var key in obj)if("default"!==key&&Object.prototype.hasOwnProperty.call(obj,key)){var desc=hasPropertyDescriptor?Object.getOwnPropertyDescriptor(obj,key):null;desc&&(desc.get||desc.set)?Object.defineProperty(newObj,key,desc):newObj[key]=obj[key]}newObj.default=obj,cache&&cache.set(obj,newObj);return newObj}(Autosaver),_ajax=(obj=_ajax)&&obj.__esModule?obj:{default:obj};var _default=new Promise(((resolve,reject)=>{const page=["page-mod-assign-editsubmission","page-mod-quiz-attempt","page-mod-forum-view","page-mod-forum-post","page-mod-lesson-view","page-mod-pdfannotator-view"];Promise.all([(0,_loader.getTinyMCE)(),(0,_utils.getPluginMetadata)(_common.component,_common.pluginName)]).then((_ref=>{let[tinyMCE,pluginMetadata]=_ref;return tinyMCE.PluginManager.add(_common.pluginName,(editor=>(_ajax.default.call([{methodname:"cursive_get_config",args:{courseid:M.cfg.courseId,cmid:M.cfg.contextInstanceId}}])[0].done((data=>{data.status&&page.includes(document.body.id)&&data.mod_state&&Autosaver.register(editor,data.sync_interval,data.userid,data.apikey_status,JSON.parse(data.plugins),JSON.parse(data.rubrics),JSON.parse(data.submission),JSON.parse(data.quizinfo),data.pastesetting)})).fail((error=>{window.console.error("Error getting cursive config:",error)})),pluginMetadata))),resolve(_common.pluginName)})).catch((error=>{reject(error)}))}));return _exports.default=_default,_exports.default})); //# sourceMappingURL=plugin.min.js.map \ No newline at end of file diff --git a/amd/build/plugin.min.js.map b/amd/build/plugin.min.js.map index 73faa28f..30e6bff0 100644 --- a/amd/build/plugin.min.js.map +++ b/amd/build/plugin.min.js.map @@ -1 +1 @@ -{"version":3,"file":"plugin.min.js","sources":["../src/plugin.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 * @module tiny_cursive/plugin\n * @category TinyMCE Editor\n * @copyright 2025 CTI \n * @author Brain Station 23 \n */\n\nimport {getTinyMCE} from 'editor_tiny/loader';\nimport {getPluginMetadata} from 'editor_tiny/utils';\nimport {component, pluginName} from './common';\nimport * as Autosaver from './autosaver';\nimport getConfig from 'core/ajax';\n\nexport default new Promise((resolve, reject) => {\n const page = [\n 'page-mod-assign-editsubmission',\n 'page-mod-quiz-attempt',\n 'page-mod-forum-view',\n 'page-mod-forum-post',\n 'page-mod-lesson-view']; // 'page-mod-oublog-editpost' excluded\n\n Promise.all([\n getTinyMCE(),\n getPluginMetadata(component, pluginName),\n ])\n .then(([tinyMCE, pluginMetadata]) => {\n tinyMCE.PluginManager.add(pluginName, (editor) => {\n\n getConfig.call([{\n methodname: \"cursive_get_config\",\n args: {courseid: M.cfg.courseId, cmid: M.cfg.contextInstanceId}\n }])[0].done((data) => {\n if (data.status && page.includes(document.body.id) && data.mod_state) {\n\n Autosaver.register(\n editor,\n data.sync_interval,\n data.userid,\n data.apikey_status,\n JSON.parse(data.plugins),\n JSON.parse(data.rubrics),\n JSON.parse(data.submission),\n JSON.parse(data.quizinfo),\n data.pastesetting\n );\n }\n }).fail((error) => {\n window.console.error('Error getting cursive config:', error);\n });\n\n return pluginMetadata;\n });\n return resolve(pluginName);\n })\n .catch((error) => {\n reject(error);\n });\n});\n"],"names":["Promise","resolve","reject","page","all","component","pluginName","then","_ref","tinyMCE","pluginMetadata","PluginManager","add","editor","call","methodname","args","courseid","M","cfg","courseId","cmid","contextInstanceId","done","data","status","includes","document","body","id","mod_state","Autosaver","register","sync_interval","userid","apikey_status","JSON","parse","plugins","rubrics","submission","quizinfo","pastesetting","fail","error","window","console","catch"],"mappings":"gwCA4Be,IAAIA,SAAQ,CAACC,QAASC,gBAC3BC,KAAO,CACT,iCACA,wBACA,sBACA,sBACA,wBAEJH,QAAQI,IAAI,EACR,yBACA,4BAAkBC,kBAAWC,sBAE5BC,MAAKC,WAAEC,QAASC,4BACbD,QAAQE,cAAcC,IAAIN,oBAAaO,uBAEzBC,KAAK,CAAC,CACZC,WAAY,qBACZC,KAAM,CAACC,SAAUC,EAAEC,IAAIC,SAAUC,KAAMH,EAAEC,IAAIG,sBAC7C,GAAGC,MAAMC,OACLA,KAAKC,QAAUtB,KAAKuB,SAASC,SAASC,KAAKC,KAAOL,KAAKM,WAEvDC,UAAUC,SACNnB,OACAW,KAAKS,cACLT,KAAKU,OACLV,KAAKW,cACLC,KAAKC,MAAMb,KAAKc,SAChBF,KAAKC,MAAMb,KAAKe,SAChBH,KAAKC,MAAMb,KAAKgB,YAChBJ,KAAKC,MAAMb,KAAKiB,UAChBjB,KAAKkB,iBAGdC,MAAMC,QACLC,OAAOC,QAAQF,MAAM,gCAAiCA,UAGnDlC,kBAEJT,QAAQK,uBAElByC,OAAOH,QACJ1C,OAAO0C"} \ No newline at end of file +{"version":3,"file":"plugin.min.js","sources":["../src/plugin.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 * @module tiny_cursive/plugin\n * @category TinyMCE Editor\n * @copyright 2025 CTI \n * @author Brain Station 23 \n */\n\nimport {getTinyMCE} from 'editor_tiny/loader';\nimport {getPluginMetadata} from 'editor_tiny/utils';\nimport {component, pluginName} from './common';\nimport * as Autosaver from './autosaver';\nimport getConfig from 'core/ajax';\n\nexport default new Promise((resolve, reject) => {\n const page = [\n 'page-mod-assign-editsubmission',\n 'page-mod-quiz-attempt',\n 'page-mod-forum-view',\n 'page-mod-forum-post',\n 'page-mod-lesson-view',\n 'page-mod-pdfannotator-view']; // 'page-mod-oublog-editpost' excluded\n\n Promise.all([\n getTinyMCE(),\n getPluginMetadata(component, pluginName),\n ])\n .then(([tinyMCE, pluginMetadata]) => {\n tinyMCE.PluginManager.add(pluginName, (editor) => {\n\n getConfig.call([{\n methodname: \"cursive_get_config\",\n args: {courseid: M.cfg.courseId, cmid: M.cfg.contextInstanceId}\n }])[0].done((data) => {\n if (data.status && page.includes(document.body.id) && data.mod_state) {\n\n Autosaver.register(\n editor,\n data.sync_interval,\n data.userid,\n data.apikey_status,\n JSON.parse(data.plugins),\n JSON.parse(data.rubrics),\n JSON.parse(data.submission),\n JSON.parse(data.quizinfo),\n data.pastesetting\n );\n }\n }).fail((error) => {\n window.console.error('Error getting cursive config:', error);\n });\n\n return pluginMetadata;\n });\n return resolve(pluginName);\n })\n .catch((error) => {\n reject(error);\n });\n});\n"],"names":["Promise","resolve","reject","page","all","component","pluginName","then","_ref","tinyMCE","pluginMetadata","PluginManager","add","editor","call","methodname","args","courseid","M","cfg","courseId","cmid","contextInstanceId","done","data","status","includes","document","body","id","mod_state","Autosaver","register","sync_interval","userid","apikey_status","JSON","parse","plugins","rubrics","submission","quizinfo","pastesetting","fail","error","window","console","catch"],"mappings":"gwCA4Be,IAAIA,SAAQ,CAACC,QAASC,gBAC3BC,KAAO,CACT,iCACA,wBACA,sBACA,sBACA,uBACA,8BAEJH,QAAQI,IAAI,EACR,yBACA,4BAAkBC,kBAAWC,sBAE5BC,MAAKC,WAAEC,QAASC,4BACbD,QAAQE,cAAcC,IAAIN,oBAAaO,uBAEzBC,KAAK,CAAC,CACZC,WAAY,qBACZC,KAAM,CAACC,SAAUC,EAAEC,IAAIC,SAAUC,KAAMH,EAAEC,IAAIG,sBAC7C,GAAGC,MAAMC,OACLA,KAAKC,QAAUtB,KAAKuB,SAASC,SAASC,KAAKC,KAAOL,KAAKM,WAEvDC,UAAUC,SACNnB,OACAW,KAAKS,cACLT,KAAKU,OACLV,KAAKW,cACLC,KAAKC,MAAMb,KAAKc,SAChBF,KAAKC,MAAMb,KAAKe,SAChBH,KAAKC,MAAMb,KAAKgB,YAChBJ,KAAKC,MAAMb,KAAKiB,UAChBjB,KAAKkB,iBAGdC,MAAMC,QACLC,OAAOC,QAAQF,MAAM,gCAAiCA,UAGnDlC,kBAEJT,QAAQK,uBAElByC,OAAOH,QACJ1C,OAAO0C"} \ No newline at end of file diff --git a/amd/build/svg_repo.min.js b/amd/build/svg_repo.min.js index ef22ae26..e4901924 100644 --- a/amd/build/svg_repo.min.js +++ b/amd/build/svg_repo.min.js @@ -6,6 +6,6 @@ define("tiny_cursive/svg_repo",["exports"],(function(_exports){Object.defineProp * @copyright 2025 Cursive Technology, Inc. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -var _default={people:'\n \n \n \n \n ',assignment:'\n \n \n \n ',time:'\n \n \n ',offline:'',forum:'',close:'\n \n ',hamburger:'\n \n ',quiz:'',cloudSave:'',lesson:''};return _exports.default=_default,_exports.default})); +var _default={people:'\n \n \n \n \n ',assignment:'\n \n \n \n ',time:'\n \n \n ',offline:'',forum:'',close:'\n \n ',hamburger:'\n \n ',quiz:'',cloudSave:'',lesson:'',pdfannotator:'\n \n \n \n \n \n \n \n \n \n \n \n \n \n '};return _exports.default=_default,_exports.default})); //# sourceMappingURL=svg_repo.min.js.map \ No newline at end of file diff --git a/amd/build/svg_repo.min.js.map b/amd/build/svg_repo.min.js.map index 5b3ccebe..505312fd 100644 --- a/amd/build/svg_repo.min.js.map +++ b/amd/build/svg_repo.min.js.map @@ -1 +1 @@ -{"version":3,"file":"svg_repo.min.js","sources":["../src/svg_repo.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 * SVG repository for icons used in the Curs\n *\n * @module tiny_cursive/svg_repo\n * @copyright 2025 Cursive Technology, Inc. \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nexport default {\n people: `\n \n \n \n \n `,\n assignment: `\n \n \n \n `,\n time: `\n \n \n `,\n offline: ``,\n forum: ``,\n close: `\n \n `,\n hamburger: `\n \n `,\n quiz: ``,\n cloudSave: ``,\n lesson: ``\n};\n"],"names":["people","assignment","time","offline","forum","close","hamburger","quiz","cloudSave","lesson"],"mappings":";;;;;;;;aAuBe,CACbA,OAAS,ijBASTC,WAAa,siBAQbC,KAAO,qaAOPC,QAAU,qgBAMVC,MAAQ,mtDAeNC,MAAQ,85BAQRC,UAAY,6jBAKZC,KAAO,ksFAuBPC,UAAY,qzBAOZC,OAAS"} \ No newline at end of file +{"version":3,"file":"svg_repo.min.js","sources":["../src/svg_repo.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 * SVG repository for icons used in the Curs\n *\n * @module tiny_cursive/svg_repo\n * @copyright 2025 Cursive Technology, Inc. \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nexport default {\n people: `\n \n \n \n \n `,\n assignment: `\n \n \n \n `,\n time: `\n \n \n `,\n offline: ``,\n forum: ``,\n close: `\n \n `,\n hamburger: `\n \n `,\n quiz: ``,\n cloudSave: ``,\n lesson: ``,\n pdfannotator: `\n \n \n \n \n \n \n \n \n \n \n \n \n \n `\n};\n"],"names":["people","assignment","time","offline","forum","close","hamburger","quiz","cloudSave","lesson","pdfannotator"],"mappings":";;;;;;;;aAuBe,CACXA,OAAS,ijBASTC,WAAa,siBAQbC,KAAO,qaAOPC,QAAU,qgBAMVC,MAAQ,mtDAeRC,MAAQ,85BAQRC,UAAY,6jBAKZC,KAAO,ksFAuBPC,UAAY,qzBAOZC,OAAS,4/EAqBTC,aAAe"} \ No newline at end of file diff --git a/amd/src/append_pdfannotator.js b/amd/src/append_pdfannotator.js new file mode 100644 index 00000000..f52c1ebd --- /dev/null +++ b/amd/src/append_pdfannotator.js @@ -0,0 +1,262 @@ +// This file is part of Moodle - http://moodle.org/ +// +// Moodle is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Moodle is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Moodle. If not, see . + +/** + * Module for handling PDF annotator functionality, + * + * @module tiny_cursive/append_pdfannotator + * @copyright 2025 Cursive Technology, Inc. + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +import {call} from 'core/ajax'; +import analyticButton from 'tiny_cursive/analytic_button'; +import replayButton from 'tiny_cursive/replay_button'; +import AnalyticEvents from 'tiny_cursive/analytic_events'; +import templates from 'core/templates'; +import Replay from 'tiny_cursive/replay'; +export const init = (scoreSetting, comments, hasApiKey, userid) => { + const replayInstances = {}; + // eslint-disable-next-line camelcase + window.video_playback = function(mid, filepath) { + if (filepath !== '') { + const replay = new Replay( + 'content' + mid, + filepath, + 10, + false, + 'player_' + mid + ); + replayInstances[mid] = replay; + } else { + templates.render('tiny_cursive/no_submission').then(html => { + document.getElementById('content' + mid).innerHTML = html; + return true; + }).catch(e => window.console.error(e)); + } + return false; + }; + + let container = document.querySelector('.comment-list-container'); + const overviewTable = document.querySelector('table[id^="mod-pdfannotator-"]'); + + document.addEventListener('click', handleSubmit); + const moduleName = document.body.id.split('-')[2]; + var pendingSubmit = false; + var buttonElement = ""; + + if (container) { + const observer = new MutationObserver(() => { + if (container?.lastChild?.id) { + extractResourceId(container.lastChild.id); + } + }); + + observer.observe(container, { + subtree: true, + childList: true + }); + } + + if (overviewTable) { + let newChild = document.createElement('th'); + newChild.textContent = 'Analytics'; + let header = overviewTable.querySelector('thead>tr>th:first-child'); + header.insertAdjacentElement('afterend', newChild); + setReplayButton(overviewTable); + } + + /** + * Sets up replay buttons and analytics for each row in the overview table + * @param {HTMLTableElement} overviewTable - The table element containing the overview data + * @description This function: + * 1. Gets all rows from the table + * 2. For each row: + * - Extracts comment ID and user ID from relevant links + * - Adds analytics column with replay/analytics buttons + * - Sets up cursive analytics functionality + */ + function setReplayButton(overviewTable) { + const rows = overviewTable.querySelectorAll('tbody > tr'); + const action = new URL(window.location.href).searchParams.get('action'); + + rows.forEach(row => { + const cols = { + col1: row.querySelector('td:nth-child(1)'), + col2: row.querySelector('td:nth-child(2)'), + col3: row.querySelector('td:nth-child(3)') + }; + + const links = { + link1: cols.col1?.querySelector('a'), + link2: cols.col2?.querySelector('a'), + link3: cols.col3?.querySelector('a') + }; + + // Extract comment ID safely + const commentId = links.link1?.href ? + new URL(links.link1.href).searchParams.get('commid') : null; + const cmid = links.link1?.href ? + new URL(links.link1.href).searchParams.get('id') : M.cfg.contextInstanceId; + // Extract user ID based on action + let userId = null; + let userLink = null; + + switch (action) { + case 'overviewquestions': + userLink = links.link2; + break; + case 'overviewanswers': + userLink = links.link3; + break; + default: + userId = userid; + } + + if (userLink?.href) { + try { + userId = new URL(userLink.href).searchParams.get('id'); + } catch (e) { + window.console.warn('Error parsing user URL:', e); + } + } + + getCursiveAnalytics(userId, commentId, cmid, cols.col1); + }); + } + + /** + * Handles the submission and cancellation of comments + * @param {Event} e - The click event object + * @description When comment is submitted or cancelled: + * - Removes 'isEditing' flag from localStorage + * - Sets pendingSubmit flag appropriately (true for submit, false for cancel) + */ + function handleSubmit(e) { + if (e.target.id === 'commentSubmit') { + localStorage.removeItem('isEditing'); + buttonElement = e.target.value; + pendingSubmit = true; + } + if (e.target.id === 'commentCancel') { + localStorage.removeItem('isEditing'); + pendingSubmit = false; + } + } + + const updateEntries = async(methodname, args) => { + try { + const response = await call([{ + methodname, + args, + }])[0]; + return response; + } catch (error) { + window.console.error('updating Entries:', error); + throw error; + } + }; + + /** + * Extracts the resource ID from a comment ID and updates entries if submission is pending + * @param {string} id - The ID string to extract resource ID from, expected format: 'prefix_number' + * @description This function: + * 1. Parses the resource ID from the given ID string + * 2. If resource ID exists and there's a pending submission: + * - Resets the pending submission flag + * - Constructs arguments with context info + * - Calls updateEntries to process the PDF annotation + */ + function extractResourceId(id) { + + // Prevent updating ID while editing a existing entry. + if (buttonElement === 'Save') { + + pendingSubmit = false; + return; + } + + let resourceId = parseInt(id?.split('_')[1]); + if (resourceId && pendingSubmit) { + pendingSubmit = false; + let args = { + cmid: M.cfg.contextInstanceId, + userid: M.cfg.userId ?? 0, + courseid: M.cfg.courseId, + modulename: moduleName, + resourceid: resourceId + }; + updateEntries('cursive_update_pdf_annote_id', args); + } + } + + /** + * Retrieves and displays cursive analytics for a given resource + * @param {number} userid - The ID of the user + * @param {number} resourceid - The ID of the resource to get analytics for + * @param {number} cmid - The course module ID + * @param {HTMLElement} place - The DOM element where analytics should be placed + * @description This function: + * 1. Makes an AJAX call to get forum comment data + * 2. Creates and inserts analytics/replay buttons + * 3. Sets up analytics events and modal functionality + * 4. Handles both API key and non-API key scenarios + */ + function getCursiveAnalytics(userid, resourceid, cmid, place) { + let args = {id: resourceid, modulename: "pdfannotator", cmid: cmid}; + let methodname = 'cursive_get_forum_comment_link'; + let com = call([{methodname, args}]); + com[0].done(function(json) { + var data = JSON.parse(json); + + var filepath = ''; + if (data.data.filename) { + filepath = data.data.filename; + } + + let analyticButtonDiv = document.createElement('div'); + let analyticsColumn = document.createElement('td'); + + if (!hasApiKey) { + analyticButtonDiv.append(replayButton(resourceid)); + } else { + analyticButtonDiv.append(analyticButton(data.data.effort_ratio, resourceid)); + } + + analyticButtonDiv.dataset.region = "analytic-div" + userid; + analyticsColumn.append(analyticButtonDiv); + place.insertAdjacentElement('afterend', analyticsColumn); + + let myEvents = new AnalyticEvents(); + var context = { + tabledata: data.data, + formattime: myEvents.formatedTime(data.data), + page: scoreSetting, + userid: resourceid, + apikey: hasApiKey + }; + + let authIcon = myEvents.authorshipStatus(data.data.first_file, data.data.score, scoreSetting); + myEvents.createModal(resourceid, context, '', replayInstances, authIcon); + myEvents.analytics(resourceid, templates, context, '', replayInstances, authIcon); + myEvents.checkDiff(resourceid, data.data.file_id, '', replayInstances); + myEvents.replyWriting(resourceid, filepath, '', replayInstances); + + }); + com[0].fail((error) => { + window.console.error('Error getting cursive config:', error); + }); + } +}; \ No newline at end of file diff --git a/amd/src/autosaver.js b/amd/src/autosaver.js index a3948532..a18e5c2a 100644 --- a/amd/src/autosaver.js +++ b/amd/src/autosaver.js @@ -60,9 +60,19 @@ export const register = (editor, interval, userId, hasApiKey, MODULES, Rubrics, let shouldBlockPaste = false; let isPasteAllowed = false; - if (modulename !== 'assign') { - PASTE_SETTING = 'cite_source'; + if (ur.includes('pdfannotator')) { + document.addEventListener('click', e => { + if (e.target.className === "dropdown-item comment-edit-a") { + let id = e.target.id; + resourceId = id.replace('editButton', ''); + localStorage.setItem('isEditing', '1'); + } + if (e.target.id === 'commentSubmit') { + syncData(); + } + }); } + const postOne = async(methodname, args) => { try { const response = await call([{ @@ -299,7 +309,7 @@ export const register = (editor, interval, userId, hasApiKey, MODULES, Rubrics, editor.rePosition = position.rePosition; sendKeyEvent("keyDown", editor); }); - editor.on('Cut', () => { + editor.on('Cut', () => { const selectedContent = editor.selection.getContent({format: 'text'}); localStorage.setItem('lastCopyCutContent', selectedContent.trim()); }); @@ -465,75 +475,75 @@ export const register = (editor, interval, userId, hasApiKey, MODULES, Rubrics, */ function getCaretPosition(skip = false) { try { - if (!editor || !editor.selection) { + if (!editor || !editor.selection) { return {caretPosition: 0, rePosition: 0}; - } - - const range = editor.selection.getRng(); - const body = editor.getBody(); - - // Create a range from start of document to current caret - const preCaretRange = range.cloneRange(); - preCaretRange.selectNodeContents(body); - preCaretRange.setEnd(range.endContainer, range.endOffset); - - const fragment = preCaretRange.cloneContents(); - const tempDiv = document.createElement('div'); - tempDiv.appendChild(fragment); - let textBeforeCursor = tempDiv.innerText || ''; - - const endContainer = range.endContainer; - const endOffset = range.endOffset; - - if (endOffset === 0 && - endContainer.nodeType === Node.ELEMENT_NODE && - editor.dom.isBlock(endContainer) && - endContainer.previousSibling) { - textBeforeCursor += '\n'; - } - const blockElements = tempDiv.querySelectorAll('p, div, h1, h2, h3, h4, h5, h6, li'); - let emptyBlockCount = 0; - blockElements.forEach(block => { + } + + const range = editor.selection.getRng(); + const body = editor.getBody(); + + // Create a range from start of document to current caret + const preCaretRange = range.cloneRange(); + preCaretRange.selectNodeContents(body); + preCaretRange.setEnd(range.endContainer, range.endOffset); + + const fragment = preCaretRange.cloneContents(); + const tempDiv = document.createElement('div'); + tempDiv.appendChild(fragment); + let textBeforeCursor = tempDiv.innerText || ''; + + const endContainer = range.endContainer; + const endOffset = range.endOffset; + + if (endOffset === 0 && + endContainer.nodeType === Node.ELEMENT_NODE && + editor.dom.isBlock(endContainer) && + endContainer.previousSibling) { + textBeforeCursor += '\n'; + } + const blockElements = tempDiv.querySelectorAll('p, div, h1, h2, h3, h4, h5, h6, li'); + let emptyBlockCount = 0; + blockElements.forEach(block => { const text = block.innerText || block.textContent || ''; if (text.trim() === '' && block.childNodes.length === 1 && block.childNodes[0].nodeName === 'BR') { - emptyBlockCount++; + emptyBlockCount++; } - }); + }); - // Add newlines for empty blocks (these represent Enter presses that created empty lines) - if (emptyBlockCount > 0) { + // Add newlines for empty blocks (these represent Enter presses that created empty lines) + if (emptyBlockCount > 0) { textBeforeCursor += '\n'.repeat(emptyBlockCount); - } + } - const absolutePosition = textBeforeCursor.length; + const absolutePosition = textBeforeCursor.length; - if (skip) { + if (skip) { return { - caretPosition: lastCaretPos, - rePosition: absolutePosition + caretPosition: lastCaretPos, + rePosition: absolutePosition }; - } - // Increment sequential caretPosition - const storageKey = `${userid}_${resourceId}_${cmid}_position`; - let storedPos = parseInt(sessionStorage.getItem(storageKey), 10); - if (isNaN(storedPos)) { + } + // Increment sequential caretPosition + const storageKey = `${userid}_${resourceId}_${cmid}_position`; + let storedPos = parseInt(sessionStorage.getItem(storageKey), 10); + if (isNaN(storedPos)) { storedPos = 0; - } - storedPos++; - lastCaretPos = storedPos; - sessionStorage.setItem(storageKey, storedPos); + } + storedPos++; + lastCaretPos = storedPos; + sessionStorage.setItem(storageKey, storedPos); - return { + return { caretPosition: storedPos, rePosition: absolutePosition - }; + }; } catch (e) { window.console.warn('Error getting caret position:', e); return {caretPosition: lastCaretPos || 1, rePosition: 0}; } - } + } /** @@ -545,14 +555,18 @@ export const register = (editor, interval, userId, hasApiKey, MODULES, Rubrics, * @throws {Error} Logs error to console if data submission fails */ async function syncData() { - + checkIsPdfAnnotator(); let data = localStorage.getItem(filename); if (!data || data.length === 0) { return; } else { localStorage.removeItem(filename); + editor.fire('change'); let originalText = editor.getContent({format: 'text'}); + if (!originalText) { + originalText = getRawText(editor); + } try { Autosave.updateSavingState('saving'); // eslint-disable-next-line @@ -572,6 +586,28 @@ export const register = (editor, interval, userId, hasApiKey, MODULES, Rubrics, } } } + + /** + * Gets the raw text content from a TinyMCE editor iframe + * @param {Object} editor - The TinyMCE editor instance + * @returns {string} The raw text content of the editor body, or empty string if not found + * @description Attempts to get the raw text content from the editor's iframe body by: + * 1. Getting the editor ID + * 2. Finding the associated iframe element + * 3. Accessing the iframe's document body + * 4. Returning the text content + * Returns empty string if any step fails + */ + function getRawText(editor) { + let editorId = editor?.id; + if (editorId) { + let iframe = document.querySelector(`#${editorId}_ifr`); + let iframeBody = iframe.contentDocument?.body || iframe.contentWindow?.document?.body; + return iframeBody?.textContent; + } + return ""; + } + /** * Sets up custom tooltip functionality for the Cursive icon * Initializes tooltip text, positions the icon in the menubar, @@ -771,6 +807,7 @@ export const register = (editor, interval, userId, hasApiKey, MODULES, Rubrics, */ function getModulesInfo(ur, parm, MODULES) { fetchStrings(); + if (!MODULES.some(module => ur.includes(module))) { return false; } @@ -797,6 +834,8 @@ export const register = (editor, interval, userId, hasApiKey, MODULES, Rubrics, } } + checkIsPdfAnnotator(); + return {resourceId: resourceId, name: modulename}; } @@ -856,6 +895,24 @@ export const register = (editor, interval, userId, hasApiKey, MODULES, Rubrics, } + /** + * Checks if the current page is a PDF annotator and updates the resourceId accordingly + * @function checkIsPdfAnnotator + * @description Checks if URL contains 'pdfannotator' and sets resourceId based on editor ID and editing state: + * - If editing an existing annotation (editor.id !== 'id_pdfannotator_content' and isEditing is true): + * Sets resourceId to the annotation ID extracted from editor.id + * - Otherwise: Sets resourceId to 0 + */ + function checkIsPdfAnnotator() { + if (ur.includes('pdfannotator')) { + if (editor.id !== 'id_pdfannotator_content' && parseInt(localStorage.getItem('isEditing'))) { + resourceId = parseInt(editor?.id.replace('editarea', '')); + } else { + resourceId = 0; + } + } + } + window.addEventListener('unload', () => { syncData(); }); diff --git a/amd/src/document_view.js b/amd/src/document_view.js index 74b67d89..14eeb59a 100644 --- a/amd/src/document_view.js +++ b/amd/src/document_view.js @@ -45,6 +45,8 @@ export default class DocumentView { this.normalizePage(id); } else if (this.module === 'lesson') { this.normalizePage(id); + } else if(this.module === 'pdfannotator') { + this.normalizePage(id); } } @@ -62,6 +64,9 @@ export default class DocumentView { } else if (this.module === 'lesson') { this.moduleIcon = Icons.lesson; this.fullPageModule(this.editor?.id); + } else if (this.module === 'pdfannotator') { + this.moduleIcon = Icons.pdfannotator; + this.fullPageModule(this.editor?.id); } } @@ -168,6 +173,12 @@ export default class DocumentView { } if (courseDes && courseDes?.textContent.trim() !== '') { + let fileSubDiv = document.querySelectorAll('.fileuploadsubmission'); + if (fileSubDiv) { + fileSubDiv.forEach(Element => { + Element.style.verticalAlign = 'middle'; + }); + } content.append( this.createBox({ bg: 'bg-gray', @@ -444,7 +455,7 @@ export default class DocumentView { labelDiv.appendChild(icon); labelDiv.append(label); - label.textContent = `${this.timeleft}: }`; + label.textContent = `${this.timeleft}:`; value.textContent = '00:00:00'; value.className = warningDiv ? 'text-danger' : 'text-primary'; Object.assign(value.style, { @@ -482,11 +493,11 @@ export default class DocumentView { const usernameWrapper = this.create('div'); const courseWrapper = this.create('div'); - const nameLabel = this.create('span'); + const nameLabel = this.create('strong'); const nameValue = this.create('span'); - const usernameLabel = this.create('span'); + const usernameLabel = this.create('strong'); const usernameValue = this.create('span'); - const courseLabel = this.create('span'); + const courseLabel = this.create('strong'); const courseValue = this.create('span'); nameLabel.textContent = `${this.name}`; @@ -498,9 +509,12 @@ export default class DocumentView { courseLabel.textContent = `${this.course}: `; courseValue.textContent = course.title; - nameWrapper.className = 'd-flex justify-content-between'; - usernameWrapper.className = 'd-flex justify-content-between'; - courseWrapper.className = 'd-flex justify-content-between'; + usernameLabel.className = 'cfw-bold me-2'; + usernameValue.className = 'cursiveFw-wrap'; + courseLabel.className = 'cfw-bold me-2'; + courseValue.className = 'cursiveFw-wrap'; + nameLabel.className = 'cfw-bold me-2'; + nameValue.className = 'cursiveFw-wrap'; nameWrapper.append(nameLabel, nameValue); usernameWrapper.append(usernameLabel, usernameValue); @@ -640,6 +654,17 @@ export default class DocumentView { btn.style.margin = '.5rem'; } + if (this.module === 'pdfannotator') { + const style = document.createElement('style'); + style.id = 'cursiveForceStyle'; + style.textContent = ` + .path-mod-pdfannotator #comment-wrapper h4, + .path-mod-pdfannotator #comment-nav { + margin: 0 !important; + } + `; + document.head.appendChild(style); + } const leftSide = this.create('div'); const rightSide = this.create('div'); @@ -729,6 +754,7 @@ export default class DocumentView { iframeBody.style.padding = '0'; } document.head.querySelector('#tiny_cursive-fullpage-mode-style')?.remove(); + document.head.querySelector('#cursiveForceStyle')?.remove(); } checkForumSubject() { @@ -759,6 +785,8 @@ export default class DocumentView { return {title: lesson, icon: Icons.forum}; case 'quiz': return {title: quiz, icon: Icons.quiz}; + case 'pdfannotator': + return {title: 'PDF Annotation', icon: Icons.pdfannotator}; default: return {title: 'Page', icon: Icons.quiz}; } diff --git a/amd/src/plugin.js b/amd/src/plugin.js index 8e3a0cfc..0ef0aef3 100644 --- a/amd/src/plugin.js +++ b/amd/src/plugin.js @@ -32,7 +32,8 @@ export default new Promise((resolve, reject) => { 'page-mod-quiz-attempt', 'page-mod-forum-view', 'page-mod-forum-post', - 'page-mod-lesson-view']; // 'page-mod-oublog-editpost' excluded + 'page-mod-lesson-view', + 'page-mod-pdfannotator-view']; // 'page-mod-oublog-editpost' excluded Promise.all([ getTinyMCE(), diff --git a/amd/src/svg_repo.js b/amd/src/svg_repo.js index 18a0ef79..8c56956b 100644 --- a/amd/src/svg_repo.js +++ b/amd/src/svg_repo.js @@ -22,7 +22,7 @@ */ export default { - people: ` @@ -31,7 +31,7 @@ export default { `, - assignment: ` @@ -39,20 +39,20 @@ export default { `, - time: ` `, - offline: ``, - forum: `` + 15.0007Z" fill="#212529"/>`, + pdfannotator: ` + + + + + + + + + + + + + + ` }; diff --git a/classes/constants.php b/classes/constants.php index 41584e99..c03270e6 100644 --- a/classes/constants.php +++ b/classes/constants.php @@ -34,7 +34,7 @@ class constants { * Array of supported activity module names. * const array NAMES List of module names where cursive can be used */ - public const NAMES = ["assign", "forum", "quiz", "lesson"]; // Excluded oublog. + public const NAMES = ["assign", "forum", "quiz", "lesson", 'pdfannotator']; // Excluded oublog. /** * Array mapping module names to their corresponding rubric areas. * Used to identify the correct rubric area for different module types. @@ -58,6 +58,7 @@ class constants { 'page-mod-quiz-review' => ['show_url_in_quiz_detail', 'quiz'], 'page-course-view-participants' => ['append_participants_table', 'course'], 'page-mod-lesson-essay' => ['append_lesson_grade_table', 'lesson'], + 'page-mod-pdfannotator-view' => ['append_pdfannotator', 'pdfannotator'], ]; diff --git a/classes/helper.php b/classes/helper.php new file mode 100644 index 00000000..f7b413d2 --- /dev/null +++ b/classes/helper.php @@ -0,0 +1,128 @@ +. + +namespace tiny_cursive; + +/** + * Class helper + * + * @package tiny_cursive + * @copyright 2026 Cursive Technology, Inc. + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class helper { + /** + * Updates resource IDs for both comments and cursive files + * + * @param array $data Array containing userid, modulename, courseid, cmid and resourceid + * @return void + * @throws \dml_exception + */ + public static function update_resource_id($data) { + self::update_comment($data); + self::update_cursive_files($data); + } + + /** + * Updates comments in the tiny_cursive_comments table. + * + * @param array $data Array containing userid, modulename, courseid, cmid and resourceid + * @throws \dml_exception + */ + public static function update_comment($data) { + global $DB; + + $table = 'tiny_cursive_comments'; + $conditions = [ + "userid" => $data['userid'], + "modulename" => $data['modulename'], + 'resourceid' => 0, + 'courseid' => $data['courseid'], + 'cmid' => $data['cmid'], + ]; + + $recs = $DB->get_records($table, $conditions); + if ($recs) { + self::update_records($recs, $table, $data['resourceid']); + } + // Update autosave content as well. + $conditions['modulename'] = $data['modulename'] . "_autosave"; + self::update_autosaved_content($conditions, $table, $data['resourceid']); + } + + /** + * Updates cursive file in the tiny_cursive_files table. + * + * @param array $data Array containing userid, modulename, courseid, cmid and resourceid + * @throws \dml_exception + */ + public static function update_cursive_files($data) { + global $DB; + + $table = 'tiny_cursive_files'; + $conditions = [ + "userid" => $data['userid'], + "modulename" => $data['modulename'], + 'resourceid' => 0, + 'courseid' => $data['courseid'], + 'cmid' => $data['cmid'], + ]; + $recs = $DB->get_records($table, $conditions); + if ($recs) { + $fname = $data['userid'] . '_' . $data['resourceid'] . '_' . $data['cmid'] . '_attempt' . '.json'; + self::update_records($recs, $table, $data['resourceid'], $fname); + } + } + + /** + * Update autosaved content records. + * + * @param array $conditions The conditions to find records to update + * @param string $table The database table name + * @param int $postid The post ID to update the records with + * @return void + * @throws \dml_exception + */ + public static function update_autosaved_content($conditions, $table, $postid) { + global $DB; + $recs = $DB->get_records($table, $conditions); + if ($recs) { + self::update_records($recs, $table, $postid); + } + } + + /** + * Updates records in the database with new resource ID and optionally a new filename + * + * @param array $recs Array of records to update + * @param string $table Database table name + * @param int $id New resource ID to set + * @param string|null $name Optional new filename to set + * @return void + * @throws \dml_exception + */ + private static function update_records($recs, $table, $id, $name = null) { + global $DB; + + foreach ($recs as $rec) { + $rec->resourceid = $id; + if ($name) { + $rec->filename = $name; + } + $DB->update_record($table, $rec, true); + } + } +} diff --git a/classes/hook_callbacks.php b/classes/hook_callbacks.php index d1f74a2a..317ccb9f 100644 --- a/classes/hook_callbacks.php +++ b/classes/hook_callbacks.php @@ -88,7 +88,7 @@ public static function before_footer_html_generation(before_footer_html_generati $PAGE->requires->js_call_amd( "tiny_cursive/" . constants::BODY_IDS[$PAGE->bodyid][0], 'init', - [constants::confidence_threshold(), constants::show_comments(), constants::has_api_key()], + [constants::confidence_threshold(), constants::show_comments(), constants::has_api_key(), $USER->id], ); } } diff --git a/db/services.php b/db/services.php index f9f477ce..04134454 100644 --- a/db/services.php +++ b/db/services.php @@ -230,6 +230,15 @@ 'ajax' => true, 'capabilities' => 'tiny/cursive:view', ], + 'cursive_update_pdf_annote_id' => [ + 'classname' => 'cursive_json_func_data', + 'methodname' => 'update_pdf_annote_id', + 'classpath' => '/lib/editor/tiny/plugins/cursive/externallib.php', + 'description' => 'update resourceid for pdf annote analytics file', + 'type' => 'write', + 'ajax' => true, + 'capabilities' => 'tiny/cursive:view', + ], ]; // We define the services to install as pre-build services. diff --git a/externallib.php b/externallib.php index 90870c6a..6cadbf94 100644 --- a/externallib.php +++ b/externallib.php @@ -30,6 +30,7 @@ use core_external\external_single_structure; use core_external\external_value; use tiny_cursive\constants; +use tiny_cursive\helper; defined('MOODLE_INTERNAL') || die; @@ -1658,9 +1659,12 @@ public static function write_local_to_json( ], ); - if ($params['resourceId'] == 0 && $params['modulename'] !== 'forum' && $params['modulename'] !== 'oublog') { - // For Quiz and Assignment there is no resourceid that's why cmid is resourceid. + if ( + $params['resourceId'] == 0 && $params['modulename'] !== 'forum' && $params['modulename'] !== 'oublog' && + $params['modulename'] !== 'pdfannotator' + ) { $params['resourceId'] = $params['cmid']; + // For Quiz and Assignment there is no resourceid that's why cmid is resourceid. } $courseid = 0; @@ -2159,4 +2163,69 @@ public static function get_autosave_content($id, $modulename, $cmid, $editorid = public static function get_autosave_content_returns() { return new external_value(PARAM_TEXT, 'autosave content'); } + + + /** + * Returns the parameters definition for update_pdf_annote_id external function. + * + * @return external_function_parameters Parameters definition containing: + * - resourceid (int): Optional ID parameter + * - modulename (string): Optional module name parameter + * - cmid (int): Optional course module ID parameter + * - userid (int): Optional user ID parameter + * - courseid (int): Optional course ID parameter + */ + public static function update_pdf_annote_id_parameters() { + return new external_function_parameters([ + 'cmid' => new external_value(PARAM_INT, 'cmid', VALUE_DEFAULT, 0), + 'userid' => new external_value(PARAM_INT, 'userid', VALUE_DEFAULT, 0), + 'courseid' => new external_value(PARAM_INT, 'courseid', VALUE_DEFAULT, 0), + 'modulename' => new external_value(PARAM_TEXT, 'modulename', VALUE_DEFAULT, ''), + 'resourceid' => new external_value(PARAM_INT, 'pdf annote comment id', VALUE_DEFAULT, 0), + ]); + } + + /** + * Updates the PDF annotation ID for a comment record + * + * @param int $cmid The course module ID + * @param int $userid The user ID (defaults to current user) + * @param int $courseid The course ID + * @param string $modulename The name of the module + * @param int $resourceid The PDF annotation comment ID + * @return bool + * @throws coding_exception + * @throws dml_exception + * @throws invalid_parameter_exception + * @throws moodle_exception + * @throws required_capability_exception + */ + public static function update_pdf_annote_id($cmid, $userid, $courseid, $modulename, $resourceid) { + $params = self::validate_parameters( + self::update_pdf_annote_id_parameters(), + [ + 'cmid' => $cmid, + 'userid' => $userid, + 'courseid' => $courseid, + 'modulename' => $modulename, + 'resourceid' => $resourceid, + ], + ); + + $context = context_module::instance($params['cmid']); + self::validate_context($context); + require_capability("tiny/cursive:writingreport", $context); + + helper::update_resource_id($params); + return true; + } + + /** + * Returns description of update_pdf_annote_id return value + * + * @return external_value Returns a boolean parameter indicating if the update was successful + */ + public static function update_pdf_annote_id_returns() { + return new external_value(PARAM_BOOL, 'update pdf annote id'); + } } diff --git a/lib.php b/lib.php index d5761124..e96bba8b 100644 --- a/lib.php +++ b/lib.php @@ -166,8 +166,8 @@ function tiny_cursive_coursemodule_standard_elements($formwrapper, $mform) { if (in_array($module, constants::NAMES)) { $mform->addElement('header', 'cursiveheader', 'Cursive', 'local_callbacks'); $options = [ - 0 => get_string('disabled', 'tiny_cursive'), - 1 => get_string('enabled', 'tiny_cursive'), + 0 => get_string('disabled', 'tiny_cursive'), + 1 => get_string('enabled', 'tiny_cursive'), ]; $mform->addElement('select', 'cursive', get_string('cursive_status', 'tiny_cursive'), $options); $mform->setType('cursive', PARAM_INT); @@ -175,7 +175,7 @@ function tiny_cursive_coursemodule_standard_elements($formwrapper, $mform) { $mform->setdefault('cursive', $state); } - if ($state && $module == 'assign') { + if ($state) { $pasteoptions = [ 'allow' => get_string('paste_allow', 'tiny_cursive'), 'block' => get_string('paste_block', 'tiny_cursive'), diff --git a/styles.css b/styles.css index d35d914b..0f2d9860 100644 --- a/styles.css +++ b/styles.css @@ -1918,4 +1918,14 @@ body.tox-fullscreen .tiny-cursive-modal .modal-dialog .close { .tiny_cursive-card-price span { font-size: 16px; font-weight: 600; -} \ No newline at end of file +} +.cfw-bold { + font-weight: 600 !important; +} +.cursiveFw-wrap { + word-wrap: break-word; +} + +#cursive-fullpagemode-sidebar .fileuploadsubmissiontime { + display: none !important; +} diff --git a/version.php b/version.php index 1881a399..d8027c3e 100644 --- a/version.php +++ b/version.php @@ -28,7 +28,7 @@ defined('MOODLE_INTERNAL') || die(); $plugin->component = 'tiny_cursive'; -$plugin->release = '2.1.2'; -$plugin->version = 2025121900; +$plugin->release = '2.1.3'; +$plugin->version = 2026013000; $plugin->requires = 2022041912; $plugin->maturity = MATURITY_STABLE;