diff --git a/amd/build/ai_manager.min.js b/amd/build/ai_manager.min.js index fca32a7..5908b82 100644 --- a/amd/build/ai_manager.min.js +++ b/amd/build/ai_manager.min.js @@ -1,3 +1,3 @@ -define("block_ai_chat/ai_manager",["exports","local_ai_manager/make_request","core/notification"],(function(_exports,_make_request,_notification){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.askLocalAiManager=void 0;_exports.askLocalAiManager=async function(purpose,prompt){let options=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[],result={};try{result=await(0,_make_request.makeRequest)(purpose,prompt,options)}catch(error){console.log(error),result.code="aiconnector",result.result=error.error+" "+error.message,result.result+=error.backtrace}return result}})); +define("block_ai_chat/ai_manager",["exports","local_ai_manager/make_request"],(function(_exports,_make_request){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.askLocalAiManager=void 0;_exports.askLocalAiManager=async function(purpose,prompt){let options=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[],result={};try{result=await(0,_make_request.makeRequest)(purpose,prompt,options)}catch(error){result.code="aiconnector",result.result=error.error+" "+error.message,result.result+=error.backtrace}return result}})); //# sourceMappingURL=ai_manager.min.js.map \ No newline at end of file diff --git a/amd/build/ai_manager.min.js.map b/amd/build/ai_manager.min.js.map index f58b68c..8acf45e 100644 --- a/amd/build/ai_manager.min.js.map +++ b/amd/build/ai_manager.min.js.map @@ -1 +1 @@ -{"version":3,"file":"ai_manager.min.js","sources":["../src/ai_manager.js"],"sourcesContent":["import {makeRequest} from 'local_ai_manager/make_request';\nimport {exception as displayException} from 'core/notification';\n\n/**\n * Get the async answer from the local_ai_manager.\n *\n * @param {string} purpose\n * @param {string} prompt\n * @param {array} options\n * @returns {string}\n */\nexport const askLocalAiManager = async(purpose, prompt, options = []) => {\n let result = {};\n try {\n result = await makeRequest(purpose, prompt, options);\n } catch (error) {\n console.log(error);\n result.code = 'aiconnector';\n result.result = error.error + \" \" + error.message;\n // For devs.\n result.result += error.backtrace;\n }\n return result;\n};\n"],"names":["async","purpose","prompt","options","result","error","console","log","code","message","backtrace"],"mappings":"uQAWiCA,eAAMC,QAASC,YAAQC,+DAAU,GAC1DC,OAAS,OAETA,aAAe,6BAAYH,QAASC,OAAQC,SAC9C,MAAOE,OACLC,QAAQC,IAAIF,OACZD,OAAOI,KAAO,cACdJ,OAAOA,OAASC,MAAMA,MAAQ,IAAMA,MAAMI,QAE1CL,OAAOA,QAAUC,MAAMK,iBAEpBN"} \ No newline at end of file +{"version":3,"file":"ai_manager.min.js","sources":["../src/ai_manager.js"],"sourcesContent":["import {makeRequest} from 'local_ai_manager/make_request';\n\n/**\n * Get the async answer from the local_ai_manager.\n *\n * @param {string} purpose\n * @param {string} prompt\n * @param {array} options\n * @returns {string}\n */\nexport const askLocalAiManager = async(purpose, prompt, options = []) => {\n let result = {};\n try {\n result = await makeRequest(purpose, prompt, options);\n } catch (error) {\n result.code = 'aiconnector';\n result.result = error.error + \" \" + error.message;\n // For devs.\n result.result += error.backtrace;\n }\n return result;\n};\n"],"names":["async","purpose","prompt","options","result","error","code","message","backtrace"],"mappings":"qOAUiCA,eAAMC,QAASC,YAAQC,+DAAU,GAC1DC,OAAS,OAETA,aAAe,6BAAYH,QAASC,OAAQC,SAC9C,MAAOE,OACLD,OAAOE,KAAO,cACdF,OAAOA,OAASC,MAAMA,MAAQ,IAAMA,MAAME,QAE1CH,OAAOA,QAAUC,MAAMG,iBAEpBJ"} \ No newline at end of file diff --git a/amd/build/dialog.min.js b/amd/build/dialog.min.js index ef6f0d7..555a6cf 100644 --- a/amd/build/dialog.min.js +++ b/amd/build/dialog.min.js @@ -1,3 +1,3 @@ -define("block_ai_chat/dialog",["exports","core/modal","block_ai_chat/webservices","core/templates","core/notification","core/modal_events","block_ai_chat/helper","block_ai_chat/ai_manager","core/str","local_ai_manager/infobox","local_ai_manager/userquota","local_ai_manager/config","core/localstorage","./helper","core/config"],(function(_exports,_modal,externalServices,_templates,_notification,_modal_events,helper,manager,_str,_infobox,_userquota,_config,_localstorage,_helper2,_config2){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)}function _interopRequireWildcard(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]}return newObj.default=obj,cache&&cache.set(obj,newObj),newObj}function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}function _defineProperty(obj,key,value){return key in obj?Object.defineProperty(obj,key,{value:value,enumerable:!0,configurable:!0,writable:!0}):obj[key]=value,obj}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_modal=_interopRequireDefault(_modal),externalServices=_interopRequireWildcard(externalServices),_templates=_interopRequireDefault(_templates),_modal_events=_interopRequireDefault(_modal_events),helper=_interopRequireWildcard(helper),manager=_interopRequireWildcard(manager),_localstorage=_interopRequireDefault(_localstorage),_config2=_interopRequireDefault(_config2);const VIEW_CHATWINDOW="block_ai_chat_chatwindow",VIEW_OPENFULL="block_ai_chat_openfull",VIEW_DOCKRIGHT="block_ai_chat_dockright";let strHistory,strNewDialog,strToday,strYesterday,badge,viewmode,modal={},modalopen=!1,conversation={id:0,messages:[]},allConversations=[],userid=0,contextid=0,firstLoad=!0,aiAtWork=!1,maxHistory=5,maxHistoryWarnings=new Set,tenantConfig={},chatConfig={};class DialogModal extends _modal.default{configure(modalConfig){modalConfig.show=!1,modalConfig.removeOnClose=!1,modalConfig.isVerticallyCentered=!1,super.configure(modalConfig),modalConfig.titletest&&this.setTitletest(modalConfig.titletest)}setTitletest(value){this.titletest=value}hide(){super.hide(),modalopen=!1;document.querySelector("body").classList.remove("block_ai_chat_open")}}_defineProperty(DialogModal,"TYPE","block_ai_chat/dialog_modal"),_defineProperty(DialogModal,"TEMPLATE","block_ai_chat/dialog_modal");_exports.init=async params=>{userid=params.userid,contextid=params.contextid,strNewDialog=params.new,strHistory=params.history,badge=params.badge,badge=!1;const aiConfig=await(0,_config.getAiConfig)();tenantConfig=aiConfig,chatConfig=aiConfig.purposes.find((p=>"chat"===p.purpose)),modal=await DialogModal.create({templateContext:{title:strNewDialog,badge:false}}),modal.getRoot().on("modal:shown",(function(e){e.target.classList.add("ai_chat_modal")})),modal.getRoot().on(_modal_events.default.outsideClick,(event=>{checkOutsideClick(event)})),setView(),document.getElementById("ai_chat_button").addEventListener("mousedown",(async()=>{!async function(){if(modalopen)return void modal.hide();await modal.show(),modalopen=!0;document.querySelector("body").classList.add("block_ai_chat_open");const textarea=document.getElementById("block_ai_chat-input-id");addTextareaListener(textarea);if(document.getElementById("block_ai_chat-submit-id").addEventListener("click",(event=>{clickSubmitButton(event)})),firstLoad){await getConversations(),showConversation();let conversationcontextLimit=await externalServices.getConversationcontextLimit(contextid);maxHistory=conversationcontextLimit.limit;document.getElementById("block_ai_chat_new_dialog").addEventListener("click",(()=>{newDialog()}));document.getElementById("block_ai_chat_delete_dialog").addEventListener("click",(()=>{deleteCurrentDialog()}));document.getElementById("block_ai_chat_show_history").addEventListener("click",(()=>{showHistory()}));document.getElementById(VIEW_CHATWINDOW).addEventListener("click",(()=>{setView(VIEW_CHATWINDOW)}));document.getElementById(VIEW_OPENFULL).addEventListener("click",(()=>{setView(VIEW_OPENFULL)}));document.getElementById(VIEW_DOCKRIGHT).addEventListener("click",(()=>{setView(VIEW_DOCKRIGHT)})),await(0,_userquota.renderUserQuota)("#block_ai_chat_userquota",["chat"]),await(0,_infobox.renderInfoBox)("block_ai_chat",userid,'.ai_chat_modal_body [data-content="local_ai_manager_infobox"]',["chat"]);const message=await userAllowed();if(""!==message){const notice=await(0,_str.getString)("notice","block_ai_chat");await(0,_notification.alert)(notice,message)}firstLoad=!1}helper.focustextarea()}()})),strToday=await(0,_str.getString)("today","core"),strYesterday=await(0,_str.getString)("yesterday","block_ai_chat");window.matchMedia("(max-width: 576px)").addEventListener("change",handleScreenWidthChange),window.innerWidth<=576&&setView(VIEW_OPENFULL)};const getConversations=async()=>{console.log("allConversations called");try{allConversations=await externalServices.getAllConversations(userid,contextid),console.log(allConversations)}catch(error){console.log(allConversations),(0,_notification.exception)(error)}},showConversation=function(){let id=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0;console.log("showConversation called"),aiAtWork||(0!==id?conversation=allConversations.find((x=>x.id===id)):void 0!==allConversations[0]?conversation=allConversations.at(allConversations.length-1):0===allConversations.length&&newDialog(!0),clearMessages(),setModalHeader(),showMessages())};document.showConversation=showConversation;const enterQuestion=async question=>{if(""==question)return void(aiAtWork=!1);const message=await userAllowed();if(""!==message){console.log("User not allowed");const notice=await(0,_str.getString)("noticenewquestion","block_ai_chat");return await(0,_notification.alert)(notice,message),void(aiAtWork=!1)}if(showMessage(question,"self",!1),0===conversation.messages.length){const currentUserLanguage=_config2.default.language.substring(0,2),LangNames=new Intl.DisplayNames("en",{type:"language"});conversation.messages.push({message:"Answer in "+LangNames.of(currentUserLanguage),sender:"system"})}const convHistory=await checkMessageHistoryLengthLimit(conversation.messages),options={component:"block_ai_chat",contextid:contextid,conversationcontext:convHistory};if(0===conversation.id){try{let idresult=await externalServices.getNewConversationId(contextid);conversation.id=idresult.id,conversation.timecreated=Math.floor(Date.now()/1e3),setModalHeader((0,_helper2.escapeHTML)(question))}catch(error){(0,_notification.exception)(error)}options.forcenewitemid=!0}options.itemid=conversation.id;let requestresult=await manager.askLocalAiManager("chat",question,options);200!=requestresult.code&&(requestresult=await errorHandling(requestresult,question,options));let copy=document.querySelector(".ai_chat_modal .awaitanswer .copy");copy.addEventListener("mousedown",(()=>{helper.copyToClipboard(copy)})),showReply(requestresult.result),aiAtWork=!1,saveConversationLocally(question,requestresult.result);document.getElementById("block_ai_chat_userquota").innerHTML="",(0,_userquota.renderUserQuota)("#block_ai_chat_userquota",["chat"])},showReply=async text=>{let fields=document.querySelectorAll(".ai_chat_modal .awaitanswer .text");const field=fields[fields.length-1];field.innerHTML=text,field.classList.remove("small");let awaitdivs=document.querySelectorAll(".ai_chat_modal .awaitanswer");awaitdivs[awaitdivs.length-1].classList.remove("awaitanswer")},showMessages=()=>{console.log("showMessages called"),conversation.messages.forEach((val=>{showMessage(val.message,val.sender)}))},showMessage=async function(text){let sender=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",answer=!(arguments.length>2&&void 0!==arguments[2])||arguments[2];if("system"===sender)return;"ai"===sender&&(sender=""),answer||(text=(0,_helper2.escapeHTML)(text));const templateData={sender:sender,content:text,answer:answer},{html:html,js:js}=await _templates.default.renderForPromise("block_ai_chat/message",templateData);_templates.default.appendNodeContents(".block_ai_chat-output",html,js),""===sender&&helper.attachCopyListenerLast(),helper.scrollToBottom()},newDialog=async function(){let deleted=arguments.length>0&&void 0!==arguments[0]&&arguments[0];console.log("newDialog called"),aiAtWork||(void 0!==allConversations.find((x=>x.id===conversation.id))||deleted||allConversations.push(conversation),conversation={id:0,messages:[]},clearMessages(),setModalHeader(strNewDialog),helper.focustextarea())},deleteCurrentDialog=()=>{console.log("deleteCurrentDialog called"),(0,_notification.deleteCancelPromise)((0,_str.getString)("delete","block_ai_chat"),(0,_str.getString)("deletewarning","block_ai_chat")).then((async()=>{if(0!==conversation.id)try{await externalServices.deleteConversation(contextid,userid,conversation.id)&&(removeFromHistory(),showConversation())}catch(error){(0,_notification.exception)(error)}})).catch((()=>{}))},showHistory=async()=>{console.log("showHistory called"),void 0===allConversations.find((x=>x.id===conversation.id))&&allConversations.push(conversation);let title=''+strHistory+"";clearMessages(!0),setModalHeader(title);document.getElementById("block_ai_chat_backlink").addEventListener("click",(()=>{0!==conversation.id?showConversation(conversation.id):newDialog(),clearMessages(),setModalHeader()})),document.querySelector(".ai_chat_modal").classList.add("onhistorypage");let groupedByDate={};allConversations.forEach((convo=>{if(void 0!==convo.messages[1]){let title=convo.messages[1].message;const now=new Date,date=new Date(1e3*convo.timecreated),today=new Date(now.getFullYear(),now.getMonth(),now.getDate()),yesterday=new Date(now.getFullYear(),now.getMonth(),now.getDate()-1),twoWeeksAgo=new Date(now);twoWeeksAgo.setDate(now.getDate()-14);const options={weekday:"long",day:"2-digit",month:"2-digit"},monthOptions={month:"long",year:"2-digit"};let dateString="";dateString=date>=today?strToday:date>=yesterday?strYesterday:date>=twoWeeksAgo?date.toLocaleDateString(void 0,options):date.toLocaleDateString(void 0,monthOptions);const hours=date.getHours(),minutes=date.getMinutes().toString().padStart(2,"0");let convItem={title:title,conversationid:convo.id,time:hours+":"+minutes};groupedByDate[dateString]||(groupedByDate[dateString]=[]),groupedByDate[dateString].push(convItem)}}));const templateData={dates:{groups:Object.keys(groupedByDate).map((key=>({key:key,objects:groupedByDate[key]})))}.groups},{html:html,js:js}=await _templates.default.renderForPromise("block_ai_chat/history",templateData);_templates.default.appendNodeContents(".ai_chat_modal .block_ai_chat-output",html,js);document.getElementById("ai_chat_history_new_dialog").addEventListener("mousedown",(()=>{newDialog()}))},removeFromHistory=()=>{0!==conversation.id&&void 0!==allConversations.find((x=>x.id===conversation.id))&&(allConversations=allConversations.filter((obj=>obj.id!==conversation.id)))},saveConversationLocally=(question,reply)=>{let message={message:question,sender:"user"};conversation.messages.push(message),message={message:reply,sender:"ai"},conversation.messages.push(message)},clearMessages=function(){let hideinput=arguments.length>0&&void 0!==arguments[0]&&arguments[0];console.log("clearMessages called");const output=document.querySelector(".block_ai_chat-output");output.innerHTML="";let input=document.querySelector(".block_ai_chat-input");input.style.display=hideinput?"none":"flex"},setModalHeader=function(){let setTitle=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"",modalheader=document.querySelector(".ai_chat_modal .modal-title div"),title="";null!==modalheader&&(conversation.messages.length>0||setTitle.length)&&(title=setTitle.length?setTitle:conversation.messages[1].message,modalheader.innerHTML=title);let modal=document.querySelector(".ai_chat_modal");modal.classList.remove("onhistorypage")},addTextareaListener=textarea=>{textarea.addEventListener("keydown",(event=>{textareaOnKeydown(event),textarea.style.height="auto";const computedStyles=window.getComputedStyle(textarea),lineHeight=parseFloat(computedStyles.lineHeight),paddingTop=parseFloat(computedStyles.paddingTop),paddingBottom=parseFloat(computedStyles.paddingBottom),borderTop=parseFloat(computedStyles.borderTopWidth),borderBottom=parseFloat(computedStyles.borderBottomWidth),maxHeight=4*lineHeight+paddingTop+paddingBottom+borderTop+borderBottom,newHeight=Math.min(textarea.scrollHeight+borderTop+borderBottom,maxHeight);textarea.style.height=newHeight+"px"}))},textareaOnKeydown=event=>{"Enter"!==event.key||aiAtWork||event.shiftKey||(aiAtWork=!0,enterQuestion(event.target.value),event.preventDefault(),event.target.value="")},clickSubmitButton=()=>{if(!aiAtWork){aiAtWork=!0;const textarea=document.getElementById("block_ai_chat-input-id");enterQuestion(textarea.value),textarea.value=""}},errorHandling=async(requestresult,question,options)=>{if(409==requestresult.code)for(;409==requestresult.code;){try{let idresult=await externalServices.getNewConversationId(contextid);conversation.id=idresult.id,options.itemid=conversation.id}catch(error){(0,_notification.exception)(error)}return requestresult=await manager.askLocalAiManager("chat",question,options)}const errorString=await(0,_str.getString)("errorwithcode","block_ai_chat",requestresult.code),result=JSON.parse(requestresult.result);await(0,_notification.alert)(errorString,result.message);const answerdivs=document.querySelectorAll(".awaitanswer");return answerdivs[answerdivs.length-1].closest(".message").classList.add("text-danger"),requestresult.result=await(0,_str.getString)("error","block_ai_chat"),console.log(requestresult),requestresult},checkMessageHistoryLengthLimit=async messages=>{const length=messages.length;if(console.log("checkHistoryLengthLimit called"),length>maxHistory){let shortenedMessages=[messages[0],...messages.slice(-maxHistory)];if(console.log(shortenedMessages),!maxHistoryWarnings.has(conversation.id)){const maxHistoryString=await(0,_str.getString)("maxhistory","block_ai_chat",maxHistory),warningErrorString=await(0,_str.getString)("maxhistoryreached","block_ai_chat",maxHistory);await(0,_notification.alert)(maxHistoryString,warningErrorString),maxHistoryWarnings.add(conversation.id)}return shortenedMessages}return messages},checkOutsideClick=event=>{viewmode!=VIEW_OPENFULL&&event.preventDefault()},setView=async function(){let mode=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"";const key=await(0,_helper2.hash)("chatmode"+userid);let savedmode=_localstorage.default.get(key);""==mode&&(mode=savedmode||VIEW_CHATWINDOW),_localstorage.default.set(key,mode),viewmode=mode;const body=document.querySelector("body");body.classList.remove(VIEW_CHATWINDOW,VIEW_OPENFULL,VIEW_DOCKRIGHT),body.classList.add(mode)},userAllowed=async()=>{if(!1===tenantConfig.tenantenabled)return message=await(0,_str.getString)("error_http403disabled","local_ai_manager"),message;if(!1===tenantConfig.userconfirmed){message=await(0,_str.getString)("error_http403notconfirmed","local_ai_manager"),message+=". ";const link=window.location.origin+"/local/ai_manager/confirm_ai_usage.php";return message+=await(0,_str.getString)("confirm_ai_usage","block_ai_chat",link),message}return!0===tenantConfig.userlocked?(message=await(0,_str.getString)("error_http403blocked","local_ai_manager"),message):!1===chatConfig.isconfigured?(message=await(0,_str.getString)("error_purposenotconfigured","local_ai_manager"),message):!0===chatConfig.lockedforrole?(message=await(0,_str.getString)("error_http403blocked","local_ai_manager"),message):!0===chatConfig.limitreached?(message=await(0,_str.getString)("error_limitreached","local_ai_manager"),message):""},handleScreenWidthChange=e=>{const body=document.querySelector("body");e.matches?(body.classList.remove(VIEW_CHATWINDOW,VIEW_OPENFULL,VIEW_DOCKRIGHT),body.classList.add(VIEW_OPENFULL)):(body.classList.remove(VIEW_CHATWINDOW,VIEW_OPENFULL,VIEW_DOCKRIGHT),body.classList.add(viewmode))}})); +define("block_ai_chat/dialog",["exports","core/modal","block_ai_chat/webservices","core/templates","core/notification","core/modal_events","block_ai_chat/helper","block_ai_chat/ai_manager","core/str","local_ai_manager/infobox","local_ai_manager/userquota","local_ai_manager/config","core/localstorage","./helper","core/config"],(function(_exports,_modal,externalServices,_templates,_notification,_modal_events,helper,manager,_str,_infobox,_userquota,_config,_localstorage,_helper2,_config2){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)}function _interopRequireWildcard(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]}return newObj.default=obj,cache&&cache.set(obj,newObj),newObj}function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}function _defineProperty(obj,key,value){return key in obj?Object.defineProperty(obj,key,{value:value,enumerable:!0,configurable:!0,writable:!0}):obj[key]=value,obj}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_modal=_interopRequireDefault(_modal),externalServices=_interopRequireWildcard(externalServices),_templates=_interopRequireDefault(_templates),_modal_events=_interopRequireDefault(_modal_events),helper=_interopRequireWildcard(helper),manager=_interopRequireWildcard(manager),_localstorage=_interopRequireDefault(_localstorage),_config2=_interopRequireDefault(_config2);const VIEW_CHATWINDOW="block_ai_chat_chatwindow",VIEW_OPENFULL="block_ai_chat_openfull",VIEW_DOCKRIGHT="block_ai_chat_dockright";let strHistory,strNewDialog,strToday,strYesterday,badge,viewmode,modal={},modalopen=!1,conversation={id:0,messages:[]},allConversations=[],userid=0,contextid=0,firstLoad=!0,aiAtWork=!1,maxHistory=5,maxHistoryWarnings=new Set,tenantConfig={},chatConfig={};class DialogModal extends _modal.default{configure(modalConfig){modalConfig.show=!1,modalConfig.removeOnClose=!1,modalConfig.isVerticallyCentered=!1,super.configure(modalConfig),modalConfig.titletest&&this.setTitletest(modalConfig.titletest)}setTitletest(value){this.titletest=value}hide(){super.hide(),modalopen=!1;document.querySelector("body").classList.remove("block_ai_chat_open")}}_defineProperty(DialogModal,"TYPE","block_ai_chat/dialog_modal"),_defineProperty(DialogModal,"TEMPLATE","block_ai_chat/dialog_modal");_exports.init=async params=>{userid=params.userid,contextid=params.contextid,strNewDialog=params.new,strHistory=params.history,badge=params.badge,badge=!1;const aiConfig=await(0,_config.getAiConfig)();tenantConfig=aiConfig,chatConfig=aiConfig.purposes.find((p=>"chat"===p.purpose)),modal=await DialogModal.create({templateContext:{title:strNewDialog,badge:false}}),modal.getRoot().on("modal:shown",(function(e){e.target.classList.add("ai_chat_modal")})),modal.getRoot().on(_modal_events.default.outsideClick,(event=>{checkOutsideClick(event)})),setView(),document.getElementById("ai_chat_button").addEventListener("mousedown",(async()=>{!async function(){if(modalopen)return void modal.hide();await modal.show(),modalopen=!0;document.querySelector("body").classList.add("block_ai_chat_open");const textarea=document.getElementById("block_ai_chat-input-id");addTextareaListener(textarea);if(document.getElementById("block_ai_chat-submit-id").addEventListener("click",(event=>{clickSubmitButton(event)})),firstLoad){await getConversations(),showConversation();let conversationcontextLimit=await externalServices.getConversationcontextLimit(contextid);maxHistory=conversationcontextLimit.limit;document.getElementById("block_ai_chat_new_dialog").addEventListener("click",(()=>{newDialog()}));document.getElementById("block_ai_chat_delete_dialog").addEventListener("click",(()=>{deleteCurrentDialog()}));document.getElementById("block_ai_chat_show_history").addEventListener("click",(()=>{showHistory()}));document.getElementById(VIEW_CHATWINDOW).addEventListener("click",(()=>{setView(VIEW_CHATWINDOW)}));document.getElementById(VIEW_OPENFULL).addEventListener("click",(()=>{setView(VIEW_OPENFULL)}));document.getElementById(VIEW_DOCKRIGHT).addEventListener("click",(()=>{setView(VIEW_DOCKRIGHT)})),await(0,_userquota.renderUserQuota)("#block_ai_chat_userquota",["chat"]),await(0,_infobox.renderInfoBox)("block_ai_chat",userid,'.ai_chat_modal_body [data-content="local_ai_manager_infobox"]',["chat"]);const message=await userAllowed();if(""!==message){const notice=await(0,_str.getString)("notice","block_ai_chat");await(0,_notification.alert)(notice,message)}firstLoad=!1}helper.focustextarea()}()})),strToday=await(0,_str.getString)("today","core"),strYesterday=await(0,_str.getString)("yesterday","block_ai_chat");window.matchMedia("(max-width: 576px)").addEventListener("change",handleScreenWidthChange),window.innerWidth<=576&&setView(VIEW_OPENFULL)};const getConversations=async()=>{try{allConversations=await externalServices.getAllConversations(userid,contextid)}catch(error){(0,_notification.exception)(error)}},showConversation=function(){let id=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0;aiAtWork||(0!==id?conversation=allConversations.find((x=>x.id===id)):void 0!==allConversations[0]?conversation=allConversations.at(allConversations.length-1):0===allConversations.length&&newDialog(!0),clearMessages(),setModalHeader(),showMessages())};document.showConversation=showConversation;const enterQuestion=async question=>{if(""==question)return void(aiAtWork=!1);const message=await userAllowed();if(""!==message){const notice=await(0,_str.getString)("noticenewquestion","block_ai_chat");return await(0,_notification.alert)(notice,message),void(aiAtWork=!1)}if(showMessage(question,"self",!1),0===conversation.messages.length){const currentUserLanguage=_config2.default.language.substring(0,2),LangNames=new Intl.DisplayNames("en",{type:"language"});conversation.messages.push({message:"Answer in "+LangNames.of(currentUserLanguage),sender:"system"})}const convHistory=await checkMessageHistoryLengthLimit(conversation.messages),options={component:"block_ai_chat",contextid:contextid,conversationcontext:convHistory};if(0===conversation.id){try{let idresult=await externalServices.getNewConversationId(contextid);conversation.id=idresult.id,conversation.timecreated=Math.floor(Date.now()/1e3),setModalHeader((0,_helper2.escapeHTML)(question))}catch(error){(0,_notification.exception)(error)}options.forcenewitemid=!0}options.itemid=conversation.id;let requestresult=await manager.askLocalAiManager("chat",question,options);200!=requestresult.code&&(requestresult=await errorHandling(requestresult,question,options));let copy=document.querySelector(".ai_chat_modal .awaitanswer .copy");copy.addEventListener("mousedown",(()=>{helper.copyToClipboard(copy)})),showReply(requestresult.result),aiAtWork=!1,saveConversationLocally(question,requestresult.result);document.getElementById("block_ai_chat_userquota").innerHTML="",(0,_userquota.renderUserQuota)("#block_ai_chat_userquota",["chat"])},showReply=async text=>{let fields=document.querySelectorAll(".ai_chat_modal .awaitanswer .text");const field=fields[fields.length-1];field.innerHTML=text,field.classList.remove("small");let awaitdivs=document.querySelectorAll(".ai_chat_modal .awaitanswer");awaitdivs[awaitdivs.length-1].classList.remove("awaitanswer")},showMessages=()=>{conversation.messages.forEach((val=>{showMessage(val.message,val.sender)}))},showMessage=async function(text){let sender=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",answer=!(arguments.length>2&&void 0!==arguments[2])||arguments[2];if("system"===sender)return;"ai"===sender&&(sender=""),answer||(text=(0,_helper2.escapeHTML)(text));const templateData={sender:sender,content:text,answer:answer},{html:html,js:js}=await _templates.default.renderForPromise("block_ai_chat/message",templateData);_templates.default.appendNodeContents(".block_ai_chat-output",html,js),""===sender&&helper.attachCopyListenerLast(),helper.scrollToBottom()},newDialog=async function(){let deleted=arguments.length>0&&void 0!==arguments[0]&&arguments[0];aiAtWork||(void 0!==allConversations.find((x=>x.id===conversation.id))||deleted||allConversations.push(conversation),conversation={id:0,messages:[]},clearMessages(),setModalHeader(strNewDialog),helper.focustextarea())},deleteCurrentDialog=()=>{(0,_notification.deleteCancelPromise)((0,_str.getString)("delete","block_ai_chat"),(0,_str.getString)("deletewarning","block_ai_chat")).then((async()=>{if(0!==conversation.id)try{await externalServices.deleteConversation(contextid,userid,conversation.id)&&(removeFromHistory(),showConversation())}catch(error){(0,_notification.exception)(error)}})).catch((()=>{}))},showHistory=async()=>{void 0===allConversations.find((x=>x.id===conversation.id))&&allConversations.push(conversation);let title=''+strHistory+"";clearMessages(!0),setModalHeader(title);document.getElementById("block_ai_chat_backlink").addEventListener("click",(()=>{0!==conversation.id?showConversation(conversation.id):newDialog(),clearMessages(),setModalHeader()})),document.querySelector(".ai_chat_modal").classList.add("onhistorypage");let groupedByDate={};allConversations.forEach((convo=>{if(void 0!==convo.messages[1]){let title=convo.messages[1].message;const now=new Date,date=new Date(1e3*convo.timecreated),today=new Date(now.getFullYear(),now.getMonth(),now.getDate()),yesterday=new Date(now.getFullYear(),now.getMonth(),now.getDate()-1),twoWeeksAgo=new Date(now);twoWeeksAgo.setDate(now.getDate()-14);const options={weekday:"long",day:"2-digit",month:"2-digit"},monthOptions={month:"long",year:"2-digit"};let dateString="";dateString=date>=today?strToday:date>=yesterday?strYesterday:date>=twoWeeksAgo?date.toLocaleDateString(void 0,options):date.toLocaleDateString(void 0,monthOptions);const hours=date.getHours(),minutes=date.getMinutes().toString().padStart(2,"0");let convItem={title:title,conversationid:convo.id,time:hours+":"+minutes};groupedByDate[dateString]||(groupedByDate[dateString]=[]),groupedByDate[dateString].push(convItem)}}));const templateData={dates:{groups:Object.keys(groupedByDate).map((key=>({key:key,objects:groupedByDate[key]})))}.groups},{html:html,js:js}=await _templates.default.renderForPromise("block_ai_chat/history",templateData);_templates.default.appendNodeContents(".ai_chat_modal .block_ai_chat-output",html,js);document.getElementById("ai_chat_history_new_dialog").addEventListener("mousedown",(()=>{newDialog()}))},removeFromHistory=()=>{0!==conversation.id&&void 0!==allConversations.find((x=>x.id===conversation.id))&&(allConversations=allConversations.filter((obj=>obj.id!==conversation.id)))},saveConversationLocally=(question,reply)=>{let message={message:question,sender:"user"};conversation.messages.push(message),message={message:reply,sender:"ai"},conversation.messages.push(message)},clearMessages=function(){let hideinput=arguments.length>0&&void 0!==arguments[0]&&arguments[0];const output=document.querySelector(".block_ai_chat-output");output.innerHTML="";let input=document.querySelector(".block_ai_chat-input");input.style.display=hideinput?"none":"flex"},setModalHeader=function(){let setTitle=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"",modalheader=document.querySelector(".ai_chat_modal .modal-title div"),title="";null!==modalheader&&(conversation.messages.length>0||setTitle.length)&&(title=setTitle.length?setTitle:conversation.messages[1].message,modalheader.innerHTML=title);let modal=document.querySelector(".ai_chat_modal");modal.classList.remove("onhistorypage")},addTextareaListener=textarea=>{textarea.addEventListener("keydown",(event=>{textareaOnKeydown(event),textarea.style.height="auto";const computedStyles=window.getComputedStyle(textarea),lineHeight=parseFloat(computedStyles.lineHeight),paddingTop=parseFloat(computedStyles.paddingTop),paddingBottom=parseFloat(computedStyles.paddingBottom),borderTop=parseFloat(computedStyles.borderTopWidth),borderBottom=parseFloat(computedStyles.borderBottomWidth),maxHeight=4*lineHeight+paddingTop+paddingBottom+borderTop+borderBottom,newHeight=Math.min(textarea.scrollHeight+borderTop+borderBottom,maxHeight);textarea.style.height=newHeight+"px"}))},textareaOnKeydown=event=>{"Enter"!==event.key||aiAtWork||event.shiftKey||(aiAtWork=!0,enterQuestion(event.target.value),event.preventDefault(),event.target.value="")},clickSubmitButton=()=>{if(!aiAtWork){aiAtWork=!0;const textarea=document.getElementById("block_ai_chat-input-id");enterQuestion(textarea.value),textarea.value=""}},errorHandling=async(requestresult,question,options)=>{if(409==requestresult.code)for(;409==requestresult.code;){try{let idresult=await externalServices.getNewConversationId(contextid);conversation.id=idresult.id,options.itemid=conversation.id}catch(error){(0,_notification.exception)(error)}return requestresult=await manager.askLocalAiManager("chat",question,options)}const errorString=await(0,_str.getString)("errorwithcode","block_ai_chat",requestresult.code),result=JSON.parse(requestresult.result);await(0,_notification.alert)(errorString,result.message);const answerdivs=document.querySelectorAll(".awaitanswer");return answerdivs[answerdivs.length-1].closest(".message").classList.add("text-danger"),requestresult.result=await(0,_str.getString)("error","block_ai_chat"),requestresult},checkMessageHistoryLengthLimit=async messages=>{if(messages.length>maxHistory){let shortenedMessages=[messages[0],...messages.slice(-maxHistory)];if(!maxHistoryWarnings.has(conversation.id)){const maxHistoryString=await(0,_str.getString)("maxhistory","block_ai_chat",maxHistory),warningErrorString=await(0,_str.getString)("maxhistoryreached","block_ai_chat",maxHistory);await(0,_notification.alert)(maxHistoryString,warningErrorString),maxHistoryWarnings.add(conversation.id)}return shortenedMessages}return messages},checkOutsideClick=event=>{viewmode!=VIEW_OPENFULL&&event.preventDefault()},setView=async function(){let mode=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"";const key=await(0,_helper2.hash)("chatmode"+userid);let savedmode=_localstorage.default.get(key);""==mode&&(mode=savedmode||VIEW_CHATWINDOW),_localstorage.default.set(key,mode),viewmode=mode;const body=document.querySelector("body");body.classList.remove(VIEW_CHATWINDOW,VIEW_OPENFULL,VIEW_DOCKRIGHT),body.classList.add(mode)},userAllowed=async()=>{let message;if(!1===tenantConfig.tenantenabled)return message=await(0,_str.getString)("error_http403disabled","local_ai_manager"),message;if(!1===tenantConfig.userconfirmed){message=await(0,_str.getString)("error_http403notconfirmed","local_ai_manager"),message+=". ";const link=window.location.origin+"/local/ai_manager/confirm_ai_usage.php";return message+=await(0,_str.getString)("confirm_ai_usage","block_ai_chat",link),message}return!0===tenantConfig.userlocked?(message=await(0,_str.getString)("error_http403blocked","local_ai_manager"),message):!1===chatConfig.isconfigured?(message=await(0,_str.getString)("error_purposenotconfigured","local_ai_manager"),message):!0===chatConfig.lockedforrole?(message=await(0,_str.getString)("error_http403blocked","local_ai_manager"),message):!0===chatConfig.limitreached?(message=await(0,_str.getString)("error_limitreached","local_ai_manager"),message):""},handleScreenWidthChange=e=>{const body=document.querySelector("body");e.matches?(body.classList.remove(VIEW_CHATWINDOW,VIEW_OPENFULL,VIEW_DOCKRIGHT),body.classList.add(VIEW_OPENFULL)):(body.classList.remove(VIEW_CHATWINDOW,VIEW_OPENFULL,VIEW_DOCKRIGHT),body.classList.add(viewmode))}})); //# sourceMappingURL=dialog.min.js.map \ No newline at end of file diff --git a/amd/build/dialog.min.js.map b/amd/build/dialog.min.js.map index d98c112..f03a690 100644 --- a/amd/build/dialog.min.js.map +++ b/amd/build/dialog.min.js.map @@ -1 +1 @@ -{"version":3,"file":"dialog.min.js","sources":["../src/dialog.js"],"sourcesContent":["import Modal from 'core/modal';\nimport * as externalServices from 'block_ai_chat/webservices';\nimport Templates from 'core/templates';\nimport {alert as displayAlert, exception as displayException, deleteCancelPromise} from 'core/notification';\nimport ModalEvents from 'core/modal_events';\nimport * as helper from 'block_ai_chat/helper';\nimport * as manager from 'block_ai_chat/ai_manager';\nimport {getString} from 'core/str';\nimport {renderInfoBox} from 'local_ai_manager/infobox';\nimport {renderUserQuota} from 'local_ai_manager/userquota';\nimport {getAiConfig} from 'local_ai_manager/config';\nimport LocalStorage from 'core/localstorage';\nimport {escapeHTML, hash} from './helper';\nimport Config from 'core/config';\n\n// Declare variables.\nconst VIEW_CHATWINDOW = 'block_ai_chat_chatwindow';\nconst VIEW_OPENFULL = 'block_ai_chat_openfull';\nconst VIEW_DOCKRIGHT = 'block_ai_chat_dockright';\nconst MODAL_OPEN = 'block_ai_chat_open';\n\n// Modal.\nlet modal = {};\nlet strHistory;\nlet strNewDialog;\nlet strToday;\nlet strYesterday;\nlet badge;\nlet viewmode;\nlet modalopen = false;\n\n// Current conversation.\nlet conversation = {\n id: 0,\n messages: [],\n};\n// All conversations.\nlet allConversations = [];\n// Userid.\nlet userid = 0;\n// Course context id.\nlet contextid = 0;\n// First load.\nlet firstLoad = true;\n// AI in process of answering.\nlet aiAtWork = false;\n// Maximum history included in query.\nlet maxHistory = 5;\n// Remember warnings for maximum history in this session.\nlet maxHistoryWarnings = new Set();\n// Tenantconfig.\nlet tenantConfig = {};\nlet chatConfig = {};\n\nclass DialogModal extends Modal {\n static TYPE = \"block_ai_chat/dialog_modal\";\n static TEMPLATE = \"block_ai_chat/dialog_modal\";\n\n configure(modalConfig) {\n // Show this modal on instantiation.\n modalConfig.show = false;\n\n // Remove from the DOM on close.\n modalConfig.removeOnClose = false;\n\n modalConfig.isVerticallyCentered = false;\n // returnFocus: target,\n\n super.configure(modalConfig);\n\n // Accept our own custom arguments too.\n if (modalConfig.titletest) {\n this.setTitletest(modalConfig.titletest);\n }\n }\n\n setTitletest(value) {\n this.titletest = value;\n }\n\n hide() {\n super.hide();\n // Keep track of state, to restrict changes to block_ai_chat modal.\n modalopen = false;\n const body = document.querySelector('body');\n body.classList.remove(MODAL_OPEN);\n }\n}\n\nexport const init = async(params) => {\n // Read params.\n userid = params.userid;\n contextid = params.contextid;\n strNewDialog = params.new;\n strHistory = params.history;\n badge = params.badge;\n // Disable bdage.\n badge = false;\n\n // Get configuration.\n const aiConfig = await getAiConfig();\n tenantConfig = aiConfig;\n chatConfig = aiConfig.purposes.find(p => p.purpose === \"chat\");\n\n // Build modal.\n modal = await DialogModal.create({\n templateContext: {\n title: strNewDialog,\n badge: badge,\n // history: history, // history dynamically added.\n },\n });\n\n // Add class for styling when modal is displayed.\n modal.getRoot().on('modal:shown', function(e) {\n e.target.classList.add(\"ai_chat_modal\");\n });\n\n // Conditionally prevent outside click event.\n modal.getRoot().on(ModalEvents.outsideClick, event => {\n checkOutsideClick(event);\n });\n\n // Check and set viewmode.\n setView();\n\n // Attach listener to the ai button to call modal.\n let button = document.getElementById('ai_chat_button');\n button.addEventListener('mousedown', async() => {\n showModal(params);\n });\n\n // Get strings.\n strToday = await getString('today', 'core');\n strYesterday = await getString('yesterday', 'block_ai_chat');\n\n // Create a MediaQueryList object to check for small screens.\n const mediaQuery = window.matchMedia(\"(max-width: 576px)\");\n\n // Attach the event listener to handle changes.\n mediaQuery.addEventListener('change', handleScreenWidthChange);\n\n // Initial check for screenwidth.\n if (window.innerWidth <= 576) {\n setView(VIEW_OPENFULL);\n }\n};\n\n/**\n * Show ai_chat modal.\n */\nasync function showModal() {\n // Switch for repeated clicking.\n if (modalopen) {\n modal.hide();\n return;\n }\n\n // Show modal.\n await modal.show();\n modalopen = true;\n const body = document.querySelector('body');\n body.classList.add(MODAL_OPEN);\n\n // Add listener for input submission.\n const textarea = document.getElementById('block_ai_chat-input-id');\n addTextareaListener(textarea);\n const button = document.getElementById('block_ai_chat-submit-id');\n button.addEventListener(\"click\", (event) => {\n clickSubmitButton(event);\n });\n\n if (firstLoad) {\n // Load conversations.\n await getConversations();\n\n // Show conversation.\n // Todo - Evtl. noch firstload verschönern, spinner für header und content z.b.\n showConversation();\n\n // Get conversationcontext message limit.\n let conversationcontextLimit = await externalServices.getConversationcontextLimit(contextid);\n maxHistory = conversationcontextLimit.limit;\n\n // Add listeners for dropdownmenus.\n // Actions.\n const btnNewDialog = document.getElementById('block_ai_chat_new_dialog');\n btnNewDialog.addEventListener('click', () => {\n newDialog();\n });\n const btnDeleteDialog = document.getElementById('block_ai_chat_delete_dialog');\n btnDeleteDialog.addEventListener('click', () => {\n deleteCurrentDialog();\n });\n const btnShowHistory = document.getElementById('block_ai_chat_show_history');\n btnShowHistory.addEventListener('click', () => {\n showHistory();\n });\n // Views.\n const btnChatwindow = document.getElementById(VIEW_CHATWINDOW);\n btnChatwindow.addEventListener('click', () => {\n setView(VIEW_CHATWINDOW);\n });\n const btnFullWidth = document.getElementById(VIEW_OPENFULL);\n btnFullWidth.addEventListener('click', () => {\n setView(VIEW_OPENFULL);\n });\n const btnDockRight = document.getElementById(VIEW_DOCKRIGHT);\n btnDockRight.addEventListener('click', () => {\n setView(VIEW_DOCKRIGHT);\n });\n\n // Show userquota.\n await renderUserQuota('#block_ai_chat_userquota', ['chat']);\n // Show infobox.\n await renderInfoBox('block_ai_chat', userid, '.ai_chat_modal_body [data-content=\"local_ai_manager_infobox\"]', ['chat']);\n\n // Check if all permissions and settings are correct.\n const message = await userAllowed();\n if (message !== '') {\n const notice = await getString('notice', 'block_ai_chat');\n await displayAlert(notice, message);\n }\n firstLoad = false;\n }\n\n helper.focustextarea();\n}\n\n\n/**\n * Webservice Get all conversations.\n */\nconst getConversations = async() => {\n console.log(\"allConversations called\");\n try {\n allConversations = await externalServices.getAllConversations(userid, contextid);\n console.log(allConversations);\n } catch (error) {\n console.log(allConversations);\n displayException(error);\n }\n};\n\n/**\n * Function to set conversation.\n * @param {*} id\n */\nconst showConversation = (id = 0) => {\n console.log(\"showConversation called\");\n // Dissallow changing conversations when question running.\n if (aiAtWork) {\n return;\n }\n // Change conversation or get last conversation.\n if (id !== 0) {\n // Set selected conversation.\n conversation = allConversations.find(x => x.id === id);\n } else if (typeof allConversations[0] !== 'undefined') {\n // Set last conversation.\n conversation = allConversations.at(allConversations.length - 1);\n } else if (allConversations.length === 0) {\n // Last conversation has been deleted.\n newDialog(true);\n }\n clearMessages();\n setModalHeader();\n showMessages();\n};\n// Make globally accessible since it is used to show history in dropdownmenuitem.mustache.\ndocument.showConversation = showConversation;\n\n\n/**\n * Send input to ai connector.\n * @param {*} question\n */\nconst enterQuestion = async(question) => {\n\n // Deny changing dialogs until answer present?\n if (question == '') {\n aiAtWork = false;\n return;\n }\n const message = await userAllowed();\n if (message !== '') {\n console.log(\"User not allowed\");\n const notice = await getString('noticenewquestion', 'block_ai_chat');\n await displayAlert(notice, message);\n aiAtWork = false;\n return;\n }\n\n // Add to conversation, answer not yet available.\n showMessage(question, 'self', false);\n\n // For first message, add a system message.\n if (conversation.messages.length === 0) {\n const currentUserLanguage = Config.language.substring(0, 2);\n const LangNames = new Intl.DisplayNames('en', {type: 'language'});\n conversation.messages.push({\n 'message': 'Answer in ' + LangNames.of(currentUserLanguage),\n 'sender': 'system',\n });\n }\n\n // Ceck history for length limit.\n const convHistory = await checkMessageHistoryLengthLimit(conversation.messages);\n\n // Options, with conversation history.\n const options = {\n 'component': 'block_ai_chat',\n 'contextid': contextid,\n 'conversationcontext': convHistory,\n };\n\n // For a new conversation, get an id.\n if (conversation.id === 0) {\n try {\n let idresult = await externalServices.getNewConversationId(contextid);\n conversation.id = idresult.id;\n conversation.timecreated = Math.floor(Date.now() / 1000);\n setModalHeader(escapeHTML(question));\n } catch (error) {\n displayException(error);\n }\n options.forcenewitemid = true;\n }\n\n // Pass itemid / conversationid.\n options.itemid = conversation.id;\n\n // Send to local_ai_manager.\n let requestresult = await manager.askLocalAiManager('chat', question, options);\n\n // Handle errors.\n if (requestresult.code != 200) {\n requestresult = await errorHandling(requestresult, question, options);\n }\n\n // Attach copy listener.\n let copy = document.querySelector('.ai_chat_modal .awaitanswer .copy');\n copy.addEventListener('mousedown', () => {\n helper.copyToClipboard(copy);\n });\n\n // Write back answer.\n showReply(requestresult.result);\n\n // Ai is done.\n aiAtWork = false;\n\n // Save new question and answer.\n saveConversationLocally(question, requestresult.result);\n\n // Update userquota.\n const userquota = document.getElementById('block_ai_chat_userquota');\n userquota.innerHTML = '';\n renderUserQuota('#block_ai_chat_userquota', ['chat']);\n};\n\n/**\n * Render reply.\n * @param {string} text\n */\nconst showReply = async (text) => {\n // Get textblock.\n let fields = document.querySelectorAll('.ai_chat_modal .awaitanswer .text');\n const field = fields[fields.length - 1];\n // Render the reply.\n field.innerHTML = text;\n field.classList.remove('small');\n\n // Remove awaitanswer class.\n let awaitdivs = document.querySelectorAll('.ai_chat_modal .awaitanswer');\n const awaitdiv = awaitdivs[awaitdivs.length - 1];\n awaitdiv.classList.remove('awaitanswer');\n};\n\nconst showMessages = () => {\n console.log(\"showMessages called\");\n conversation.messages.forEach((val) => {\n showMessage(val.message, val.sender);\n });\n};\n\n/**\n * Show answer from local_ai_manager.\n * @param {*} text\n * @param {*} sender User or Ai\n * @param {*} answer Is answer in history\n */\nconst showMessage = async(text, sender = '', answer = true) => {\n // Skip if sender is system.\n if (sender === 'system') {\n return;\n }\n // Imitate bool for message.mustache logic {{#sender}}.\n if (sender === 'ai') {\n sender = '';\n }\n // Escape chars for immediate rendering.\n if (!answer) {\n text = escapeHTML(text);\n }\n\n const templateData = {\n \"sender\": sender,\n \"content\": text,\n \"answer\": answer,\n };\n // Call the function to load and render our template.\n const {html, js} = await Templates.renderForPromise('block_ai_chat/message', templateData);\n Templates.appendNodeContents('.block_ai_chat-output', html, js);\n\n // Add copy listener for replys.\n if (sender === '') {\n helper.attachCopyListenerLast();\n }\n\n // Scroll the modal content to the bottom.\n helper.scrollToBottom();\n};\n\n/**\n * Create new / Reset dialog.\n * @param {bool} deleted\n */\nconst newDialog = async(deleted = false) => {\n console.log(\"newDialog called\");\n if (aiAtWork) {\n return;\n }\n // Add current convo local representation, if not already there.\n if (allConversations.find(x => x.id === conversation.id) === undefined && !deleted) {\n allConversations.push(conversation);\n }\n // Reset local conservation.\n conversation = {\n id: 0,\n messages: [],\n };\n clearMessages();\n setModalHeader(strNewDialog);\n helper.focustextarea();\n};\n\n/**\n * Delete /hide current dialog.\n */\nconst deleteCurrentDialog = () => {\n console.log(\"deleteCurrentDialog called\");\n deleteCancelPromise(\n getString('delete', 'block_ai_chat'),\n getString('deletewarning', 'block_ai_chat'),\n ).then(async() => {\n if (conversation.id !== 0) {\n try {\n const deleted = await externalServices.deleteConversation(contextid, userid, conversation.id);\n if (deleted) {\n removeFromHistory();\n showConversation();\n }\n } catch (error) {\n displayException(error);\n }\n }\n return;\n }).catch(() => {\n return;\n });\n};\n\n/**\n * Show conversation history.\n */\nconst showHistory = async() => {\n console.log(\"showHistory called\");\n // Add current convo local representation, if not already there.\n if (allConversations.find(x => x.id === conversation.id) === undefined) {\n allConversations.push(conversation);\n }\n // Change title and add backlink.\n let title = '' + strHistory + '';\n clearMessages(true);\n setModalHeader(title);\n const btnBacklink = document.getElementById('block_ai_chat_backlink');\n btnBacklink.addEventListener('click', () => {\n if (conversation.id !== 0) {\n showConversation(conversation.id);\n } else {\n newDialog();\n }\n clearMessages();\n setModalHeader();\n });\n\n // Set modal class to hide info about ratelimits and infobox.\n let modal = document.querySelector('.ai_chat_modal');\n modal.classList.add('onhistorypage');\n\n // Iterate over conversations and group by date.\n let groupedByDate = {};\n allConversations.forEach((convo) => {\n if (typeof convo.messages[1] !== 'undefined') {\n // Get first prompt.\n let title = convo.messages[1].message;\n\n // Get date and sort convos into a date array.\n const now = new Date();\n const date = new Date(convo.timecreated * 1000);\n const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());\n const yesterday = new Date(now.getFullYear(), now.getMonth(), now.getDate() - 1);\n const twoWeeksAgo = new Date(now);\n twoWeeksAgo.setDate(now.getDate() - 14);\n\n const options = {weekday: 'long', day: '2-digit', month: '2-digit'};\n const monthOptions = {month: 'long', year: '2-digit'};\n\n // Create a date string.\n let dateString = '';\n if (date >= today) {\n dateString = strToday;\n } else if (date >= yesterday) {\n dateString = strYesterday;\n } else if (date >= twoWeeksAgo) {\n dateString = date.toLocaleDateString(undefined, options);\n } else {\n dateString = date.toLocaleDateString(undefined, monthOptions);\n }\n\n // Create a time string.\n const hours = date.getHours();\n const minutes = date.getMinutes().toString().padStart(2, '0');\n\n let convItem = {\n \"title\": title,\n \"conversationid\": convo.id,\n \"time\": hours + ':' + minutes,\n };\n\n // Save entry under the date.\n if (!groupedByDate[dateString]) {\n groupedByDate[dateString] = [];\n }\n groupedByDate[dateString].push(convItem);\n }\n });\n\n // Convert the grouped objects into an array format that Mustache can iterate over.\n let convert = {\n groups: Object.keys(groupedByDate).map(key => ({\n key: key,\n objects: groupedByDate[key]\n }))\n };\n\n // Render history.\n const templateData = {\n \"dates\": convert.groups,\n };\n const {html, js} = await Templates.renderForPromise('block_ai_chat/history', templateData);\n Templates.appendNodeContents('.ai_chat_modal .block_ai_chat-output', html, js);\n\n // Add a listener for the new dialog button.\n const btnNewDialog = document.getElementById('ai_chat_history_new_dialog');\n btnNewDialog.addEventListener('mousedown', () => {\n newDialog();\n });\n};\n\n/**\n * Remove currrent conversation from history.\n */\nconst removeFromHistory = () => {\n // Cant remove if new or not yet in history.\n if (conversation.id !== 0 && allConversations.find(x => x.id === conversation.id) !== undefined) {\n // Build new allConversations array without deleted one.\n allConversations = allConversations.filter(obj => obj.id !== conversation.id);\n }\n};\n\n/**\n * Webservice Save conversation.\n * @param {*} question\n * @param {*} reply\n */\nconst saveConversationLocally = (question, reply) => {\n // Add to local representation.\n let message = {'message': question, 'sender': 'user'};\n conversation.messages.push(message);\n message = {'message': reply, 'sender': 'ai'};\n conversation.messages.push(message);\n};\n\n/**\n * Clear output div.\n * @param {*} hideinput\n */\nconst clearMessages = (hideinput = false) => {\n console.log(\"clearMessages called\");\n const output = document.querySelector('.block_ai_chat-output');\n output.innerHTML = '';\n // For showing history.\n let input = document.querySelector('.block_ai_chat-input');\n if (hideinput) {\n input.style.display = 'none';\n } else {\n input.style.display = 'flex';\n }\n};\n\n/**\n * Set modal header title.\n * @param {*} setTitle\n */\nconst setModalHeader = (setTitle = '') => {\n let modalheader = document.querySelector('.ai_chat_modal .modal-title div');\n let title = '';\n if (modalheader !== null && (conversation.messages.length > 0 || setTitle.length)) {\n if (!setTitle.length) {\n title = conversation.messages[1].message;\n } else {\n title = setTitle;\n }\n modalheader.innerHTML = title;\n }\n // Remove onhistorypage, since history page is setting it.\n let modal = document.querySelector('.ai_chat_modal');\n modal.classList.remove('onhistorypage');\n};\n\n/**\n * Attach event listener.\n * @param {*} textarea\n */\nconst addTextareaListener = (textarea) => {\n textarea.addEventListener('keydown', (event) => {\n // Handle submission.\n textareaOnKeydown(event);\n\n // Handle autgrow.\n // Reset the height to auto to get the correct scrollHeight.\n textarea.style.height = 'auto';\n\n // Fetch the computed styles.\n const computedStyles = window.getComputedStyle(textarea);\n const lineHeight = parseFloat(computedStyles.lineHeight);\n const paddingTop = parseFloat(computedStyles.paddingTop);\n const paddingBottom = parseFloat(computedStyles.paddingBottom);\n const borderTop = parseFloat(computedStyles.borderTopWidth);\n const borderBottom = parseFloat(computedStyles.borderBottomWidth);\n\n // Calculate the maximum height for four rows plus padding and borders.\n const maxHeight = (lineHeight * 4) + paddingTop + paddingBottom + borderTop + borderBottom;\n\n // Calculate the new height based on the scrollHeight.\n const newHeight = Math.min(textarea.scrollHeight + borderTop + borderBottom, maxHeight);\n\n // Set the new height.\n textarea.style.height = newHeight + 'px';\n });\n};\n\n/**\n * Action for textarea submission.\n * @param {*} event\n */\nconst textareaOnKeydown = (event) => {\n // TODO check for mobile devices.\n if (event.key === 'Enter' && !aiAtWork && !event.shiftKey) {\n aiAtWork = true;\n enterQuestion(event.target.value);\n event.preventDefault();\n event.target.value = '';\n }\n};\n\n/**\n * Submit form.\n */\nconst clickSubmitButton = () => {\n // Var aiAtWork to make it impossible to submit multiple questions at once.\n if (!aiAtWork) {\n aiAtWork = true;\n const textarea = document.getElementById('block_ai_chat-input-id');\n enterQuestion(textarea.value);\n textarea.value = '';\n }\n};\n\n/**\n * Handle error from local_ai_manager.\n * @param {*} requestresult\n * @param {*} question\n * @param {*} options\n * @returns {object}\n */\nconst errorHandling = async(requestresult, question, options) => {\n\n // If code 409, conversationid is already taken, try get new a one.\n if (requestresult.code == 409) {\n while (requestresult.code == 409) {\n try {\n let idresult = await externalServices.getNewConversationId(contextid);\n conversation.id = idresult.id;\n options.itemid = conversation.id;\n } catch (error) {\n displayException(error);\n }\n // Retry with new id.\n requestresult = await manager.askLocalAiManager('chat', question, options);\n return requestresult;\n }\n }\n\n // If any other errorcode, alert with errormessage.\n const errorString = await getString('errorwithcode', 'block_ai_chat', requestresult.code);\n const result = JSON.parse(requestresult.result);\n await displayAlert(errorString, result.message);\n\n // Change answer styling to differentiate from ai.\n const answerdivs = document.querySelectorAll('.awaitanswer');\n const answerdiv = answerdivs[answerdivs.length - 1];\n const messagediv = answerdiv.closest('.message');\n messagediv.classList.add('text-danger');\n\n // And write generic error message in chatbot.\n requestresult.result = await getString('error', 'block_ai_chat');\n console.log(requestresult);\n return requestresult;\n};\n\n/**\n * Check historic messages for max length.\n * @param {array} messages\n * @returns {array}\n */\nconst checkMessageHistoryLengthLimit = async(messages) => {\n const length = messages.length;\n console.log(\"checkHistoryLengthLimit called\");\n if (length > maxHistory) {\n // Cut history.\n let shortenedMessages = [messages[0], ...messages.slice(-maxHistory)];\n console.log(shortenedMessages);\n\n // Show warning once per session.\n if (!maxHistoryWarnings.has(conversation.id)) {\n const maxHistoryString = await getString('maxhistory', 'block_ai_chat', maxHistory);\n const warningErrorString = await getString('maxhistoryreached', 'block_ai_chat', maxHistory);\n await displayAlert(maxHistoryString, warningErrorString);\n // Remember warning.\n maxHistoryWarnings.add(conversation.id);\n }\n return shortenedMessages;\n }\n // Limit not reached, return messages.\n return messages;\n};\n\n/**\n * Check if modal should close on outside click.\n * @param {*} event\n */\nconst checkOutsideClick = (event) => {\n // View openfull acts like a normal modal.\n if (viewmode != VIEW_OPENFULL) {\n event.preventDefault();\n }\n};\n\n/**\n * Set different viewmodes and save in local storage.\n * @param {string} mode\n */\nconst setView = async(mode = '') => {\n const key = await hash('chatmode' + userid);\n // Check for saved viewmode.\n let savedmode = LocalStorage.get(key);\n if (mode == '') {\n if (!savedmode) {\n // Set default.\n mode = VIEW_CHATWINDOW;\n } else {\n mode = savedmode;\n }\n }\n // Save viewmode and set global var.\n LocalStorage.set(key, mode);\n viewmode = mode;\n\n // Set viewmode as bodyclass.\n const body = document.querySelector('body');\n body.classList.remove(VIEW_CHATWINDOW, VIEW_OPENFULL, VIEW_DOCKRIGHT);\n body.classList.add(mode);\n};\n\n/**\n * Is user allowed new queries.\n * @returns {message}\n */\nconst userAllowed = async() => {\n if (tenantConfig.tenantenabled === false) {\n message = await getString('error_http403disabled', 'local_ai_manager');\n return message;\n }\n if (tenantConfig.userconfirmed === false) {\n message = await getString('error_http403notconfirmed', 'local_ai_manager');\n message += \". \";\n const link = window.location.origin + '/local/ai_manager/confirm_ai_usage.php';\n message += await getString('confirm_ai_usage', 'block_ai_chat', link);\n return message;\n }\n if (tenantConfig.userlocked === true) {\n message = await getString('error_http403blocked', 'local_ai_manager');\n return message;\n }\n if (chatConfig.isconfigured === false) {\n message = await getString('error_purposenotconfigured', 'local_ai_manager');\n return message;\n }\n if (chatConfig.lockedforrole === true) {\n message = await getString('error_http403blocked', 'local_ai_manager');\n return message;\n }\n if (chatConfig.limitreached === true) {\n message = await getString('error_limitreached', 'local_ai_manager');\n return message;\n }\n return '';\n};\n\n/**\n * Change to openfull view when screen is small.\n * @param {*} e\n */\nconst handleScreenWidthChange = (e) => {\n const body = document.querySelector('body');\n if (e.matches) {\n // Screen width is less than 576px\n body.classList.remove(VIEW_CHATWINDOW, VIEW_OPENFULL, VIEW_DOCKRIGHT);\n body.classList.add(VIEW_OPENFULL);\n } else {\n body.classList.remove(VIEW_CHATWINDOW, VIEW_OPENFULL, VIEW_DOCKRIGHT);\n body.classList.add(viewmode);\n }\n};\n"],"names":["VIEW_CHATWINDOW","VIEW_OPENFULL","VIEW_DOCKRIGHT","strHistory","strNewDialog","strToday","strYesterday","badge","viewmode","modal","modalopen","conversation","id","messages","allConversations","userid","contextid","firstLoad","aiAtWork","maxHistory","maxHistoryWarnings","Set","tenantConfig","chatConfig","DialogModal","Modal","configure","modalConfig","show","removeOnClose","isVerticallyCentered","titletest","setTitletest","value","hide","document","querySelector","classList","remove","async","params","new","history","aiConfig","purposes","find","p","purpose","create","templateContext","title","getRoot","on","e","target","add","ModalEvents","outsideClick","event","checkOutsideClick","setView","getElementById","addEventListener","textarea","addTextareaListener","clickSubmitButton","getConversations","showConversation","conversationcontextLimit","externalServices","getConversationcontextLimit","limit","newDialog","deleteCurrentDialog","showHistory","message","userAllowed","notice","helper","focustextarea","showModal","window","matchMedia","handleScreenWidthChange","innerWidth","console","log","getAllConversations","error","x","at","length","clearMessages","setModalHeader","showMessages","enterQuestion","question","showMessage","currentUserLanguage","Config","language","substring","LangNames","Intl","DisplayNames","type","push","of","convHistory","checkMessageHistoryLengthLimit","options","idresult","getNewConversationId","timecreated","Math","floor","Date","now","forcenewitemid","itemid","requestresult","manager","askLocalAiManager","code","errorHandling","copy","copyToClipboard","showReply","result","saveConversationLocally","innerHTML","fields","querySelectorAll","field","text","awaitdivs","forEach","val","sender","answer","templateData","html","js","Templates","renderForPromise","appendNodeContents","attachCopyListenerLast","scrollToBottom","deleted","undefined","then","deleteConversation","removeFromHistory","catch","groupedByDate","convo","date","today","getFullYear","getMonth","getDate","yesterday","twoWeeksAgo","setDate","weekday","day","month","monthOptions","year","dateString","toLocaleDateString","hours","getHours","minutes","getMinutes","toString","padStart","convItem","groups","Object","keys","map","key","objects","filter","obj","reply","hideinput","output","input","style","display","setTitle","modalheader","textareaOnKeydown","height","computedStyles","getComputedStyle","lineHeight","parseFloat","paddingTop","paddingBottom","borderTop","borderTopWidth","borderBottom","borderBottomWidth","maxHeight","newHeight","min","scrollHeight","shiftKey","preventDefault","errorString","JSON","parse","answerdivs","closest","shortenedMessages","slice","has","maxHistoryString","warningErrorString","mode","savedmode","LocalStorage","get","set","body","tenantenabled","userconfirmed","link","location","origin","userlocked","isconfigured","lockedforrole","limitreached","matches"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"dialog.min.js","sources":["../src/dialog.js"],"sourcesContent":["import Modal from 'core/modal';\nimport * as externalServices from 'block_ai_chat/webservices';\nimport Templates from 'core/templates';\nimport {alert as displayAlert, exception as displayException, deleteCancelPromise} from 'core/notification';\nimport ModalEvents from 'core/modal_events';\nimport * as helper from 'block_ai_chat/helper';\nimport * as manager from 'block_ai_chat/ai_manager';\nimport {getString} from 'core/str';\nimport {renderInfoBox} from 'local_ai_manager/infobox';\nimport {renderUserQuota} from 'local_ai_manager/userquota';\nimport {getAiConfig} from 'local_ai_manager/config';\nimport LocalStorage from 'core/localstorage';\nimport {escapeHTML, hash} from './helper';\nimport Config from 'core/config';\n\n// Declare variables.\nconst VIEW_CHATWINDOW = 'block_ai_chat_chatwindow';\nconst VIEW_OPENFULL = 'block_ai_chat_openfull';\nconst VIEW_DOCKRIGHT = 'block_ai_chat_dockright';\nconst MODAL_OPEN = 'block_ai_chat_open';\n\n// Modal.\nlet modal = {};\nlet strHistory;\nlet strNewDialog;\nlet strToday;\nlet strYesterday;\nlet badge;\nlet viewmode;\nlet modalopen = false;\n\n// Current conversation.\nlet conversation = {\n id: 0,\n messages: [],\n};\n// All conversations.\nlet allConversations = [];\n// Userid.\nlet userid = 0;\n// Course context id.\nlet contextid = 0;\n// First load.\nlet firstLoad = true;\n// AI in process of answering.\nlet aiAtWork = false;\n// Maximum history included in query.\nlet maxHistory = 5;\n// Remember warnings for maximum history in this session.\nlet maxHistoryWarnings = new Set();\n// Tenantconfig.\nlet tenantConfig = {};\nlet chatConfig = {};\n\nclass DialogModal extends Modal {\n static TYPE = \"block_ai_chat/dialog_modal\";\n static TEMPLATE = \"block_ai_chat/dialog_modal\";\n\n configure(modalConfig) {\n // Show this modal on instantiation.\n modalConfig.show = false;\n\n // Remove from the DOM on close.\n modalConfig.removeOnClose = false;\n\n modalConfig.isVerticallyCentered = false;\n\n super.configure(modalConfig);\n\n // Accept our own custom arguments too.\n if (modalConfig.titletest) {\n this.setTitletest(modalConfig.titletest);\n }\n }\n\n setTitletest(value) {\n this.titletest = value;\n }\n\n hide() {\n super.hide();\n // Keep track of state, to restrict changes to block_ai_chat modal.\n modalopen = false;\n const body = document.querySelector('body');\n body.classList.remove(MODAL_OPEN);\n }\n}\n\nexport const init = async(params) => {\n // Read params.\n userid = params.userid;\n contextid = params.contextid;\n strNewDialog = params.new;\n strHistory = params.history;\n badge = params.badge;\n // Disable bdage.\n badge = false;\n\n // Get configuration.\n const aiConfig = await getAiConfig();\n tenantConfig = aiConfig;\n chatConfig = aiConfig.purposes.find(p => p.purpose === \"chat\");\n\n // Build modal.\n modal = await DialogModal.create({\n templateContext: {\n title: strNewDialog,\n badge: badge,\n },\n });\n\n // Add class for styling when modal is displayed.\n modal.getRoot().on('modal:shown', function(e) {\n e.target.classList.add(\"ai_chat_modal\");\n });\n\n // Conditionally prevent outside click event.\n modal.getRoot().on(ModalEvents.outsideClick, event => {\n checkOutsideClick(event);\n });\n\n // Check and set viewmode.\n setView();\n\n // Attach listener to the ai button to call modal.\n let button = document.getElementById('ai_chat_button');\n button.addEventListener('mousedown', async() => {\n showModal(params);\n });\n\n // Get strings.\n strToday = await getString('today', 'core');\n strYesterday = await getString('yesterday', 'block_ai_chat');\n\n // Create a MediaQueryList object to check for small screens.\n const mediaQuery = window.matchMedia(\"(max-width: 576px)\");\n\n // Attach the event listener to handle changes.\n mediaQuery.addEventListener('change', handleScreenWidthChange);\n\n // Initial check for screenwidth.\n if (window.innerWidth <= 576) {\n setView(VIEW_OPENFULL);\n }\n};\n\n/**\n * Show ai_chat modal.\n */\nasync function showModal() {\n // Switch for repeated clicking.\n if (modalopen) {\n modal.hide();\n return;\n }\n\n // Show modal.\n await modal.show();\n modalopen = true;\n const body = document.querySelector('body');\n body.classList.add(MODAL_OPEN);\n\n // Add listener for input submission.\n const textarea = document.getElementById('block_ai_chat-input-id');\n addTextareaListener(textarea);\n const button = document.getElementById('block_ai_chat-submit-id');\n button.addEventListener(\"click\", (event) => {\n clickSubmitButton(event);\n });\n\n if (firstLoad) {\n // Load conversations.\n await getConversations();\n\n // Show conversation.\n // Todo - Evtl. noch firstload verschönern, spinner für header und content z.b.\n showConversation();\n\n // Get conversationcontext message limit.\n let conversationcontextLimit = await externalServices.getConversationcontextLimit(contextid);\n maxHistory = conversationcontextLimit.limit;\n\n // Add listeners for dropdownmenus.\n // Actions.\n const btnNewDialog = document.getElementById('block_ai_chat_new_dialog');\n btnNewDialog.addEventListener('click', () => {\n newDialog();\n });\n const btnDeleteDialog = document.getElementById('block_ai_chat_delete_dialog');\n btnDeleteDialog.addEventListener('click', () => {\n deleteCurrentDialog();\n });\n const btnShowHistory = document.getElementById('block_ai_chat_show_history');\n btnShowHistory.addEventListener('click', () => {\n showHistory();\n });\n // Views.\n const btnChatwindow = document.getElementById(VIEW_CHATWINDOW);\n btnChatwindow.addEventListener('click', () => {\n setView(VIEW_CHATWINDOW);\n });\n const btnFullWidth = document.getElementById(VIEW_OPENFULL);\n btnFullWidth.addEventListener('click', () => {\n setView(VIEW_OPENFULL);\n });\n const btnDockRight = document.getElementById(VIEW_DOCKRIGHT);\n btnDockRight.addEventListener('click', () => {\n setView(VIEW_DOCKRIGHT);\n });\n\n // Show userquota.\n await renderUserQuota('#block_ai_chat_userquota', ['chat']);\n // Show infobox.\n await renderInfoBox('block_ai_chat', userid, '.ai_chat_modal_body [data-content=\"local_ai_manager_infobox\"]', ['chat']);\n\n // Check if all permissions and settings are correct.\n const message = await userAllowed();\n if (message !== '') {\n const notice = await getString('notice', 'block_ai_chat');\n await displayAlert(notice, message);\n }\n firstLoad = false;\n }\n\n helper.focustextarea();\n}\n\n\n/**\n * Webservice Get all conversations.\n */\nconst getConversations = async() => {\n try {\n allConversations = await externalServices.getAllConversations(userid, contextid);\n } catch (error) {\n displayException(error);\n }\n};\n\n/**\n * Function to set conversation.\n * @param {*} id\n */\nconst showConversation = (id = 0) => {\n // Dissallow changing conversations when question running.\n if (aiAtWork) {\n return;\n }\n // Change conversation or get last conversation.\n if (id !== 0) {\n // Set selected conversation.\n conversation = allConversations.find(x => x.id === id);\n } else if (typeof allConversations[0] !== 'undefined') {\n // Set last conversation.\n conversation = allConversations.at(allConversations.length - 1);\n } else if (allConversations.length === 0) {\n // Last conversation has been deleted.\n newDialog(true);\n }\n clearMessages();\n setModalHeader();\n showMessages();\n};\n// Make globally accessible since it is used to show history in dropdownmenuitem.mustache.\ndocument.showConversation = showConversation;\n\n\n/**\n * Send input to ai connector.\n * @param {*} question\n */\nconst enterQuestion = async(question) => {\n\n // Deny changing dialogs until answer present?\n if (question == '') {\n aiAtWork = false;\n return;\n }\n const message = await userAllowed();\n if (message !== '') {\n const notice = await getString('noticenewquestion', 'block_ai_chat');\n await displayAlert(notice, message);\n aiAtWork = false;\n return;\n }\n\n // Add to conversation, answer not yet available.\n showMessage(question, 'self', false);\n\n // For first message, add a system message.\n if (conversation.messages.length === 0) {\n const currentUserLanguage = Config.language.substring(0, 2);\n const LangNames = new Intl.DisplayNames('en', {type: 'language'});\n conversation.messages.push({\n 'message': 'Answer in ' + LangNames.of(currentUserLanguage),\n 'sender': 'system',\n });\n }\n\n // Ceck history for length limit.\n const convHistory = await checkMessageHistoryLengthLimit(conversation.messages);\n\n // Options, with conversation history.\n const options = {\n 'component': 'block_ai_chat',\n 'contextid': contextid,\n 'conversationcontext': convHistory,\n };\n\n // For a new conversation, get an id.\n if (conversation.id === 0) {\n try {\n let idresult = await externalServices.getNewConversationId(contextid);\n conversation.id = idresult.id;\n conversation.timecreated = Math.floor(Date.now() / 1000);\n setModalHeader(escapeHTML(question));\n } catch (error) {\n displayException(error);\n }\n options.forcenewitemid = true;\n }\n\n // Pass itemid / conversationid.\n options.itemid = conversation.id;\n\n // Send to local_ai_manager.\n let requestresult = await manager.askLocalAiManager('chat', question, options);\n\n // Handle errors.\n if (requestresult.code != 200) {\n requestresult = await errorHandling(requestresult, question, options);\n }\n\n // Attach copy listener.\n let copy = document.querySelector('.ai_chat_modal .awaitanswer .copy');\n copy.addEventListener('mousedown', () => {\n helper.copyToClipboard(copy);\n });\n\n // Write back answer.\n showReply(requestresult.result);\n\n // Ai is done.\n aiAtWork = false;\n\n // Save new question and answer.\n saveConversationLocally(question, requestresult.result);\n\n // Update userquota.\n const userquota = document.getElementById('block_ai_chat_userquota');\n userquota.innerHTML = '';\n renderUserQuota('#block_ai_chat_userquota', ['chat']);\n};\n\n/**\n * Render reply.\n * @param {string} text\n */\nconst showReply = async(text) => {\n // Get textblock.\n let fields = document.querySelectorAll('.ai_chat_modal .awaitanswer .text');\n const field = fields[fields.length - 1];\n // Render the reply.\n field.innerHTML = text;\n field.classList.remove('small');\n\n // Remove awaitanswer class.\n let awaitdivs = document.querySelectorAll('.ai_chat_modal .awaitanswer');\n const awaitdiv = awaitdivs[awaitdivs.length - 1];\n awaitdiv.classList.remove('awaitanswer');\n};\n\nconst showMessages = () => {\n conversation.messages.forEach((val) => {\n showMessage(val.message, val.sender);\n });\n};\n\n/**\n * Show answer from local_ai_manager.\n * @param {*} text\n * @param {*} sender User or Ai\n * @param {*} answer Is answer in history\n */\nconst showMessage = async(text, sender = '', answer = true) => {\n // Skip if sender is system.\n if (sender === 'system') {\n return;\n }\n // Imitate bool for message.mustache logic {{#sender}}.\n if (sender === 'ai') {\n sender = '';\n }\n // Escape chars for immediate rendering.\n if (!answer) {\n text = escapeHTML(text);\n }\n\n const templateData = {\n \"sender\": sender,\n \"content\": text,\n \"answer\": answer,\n };\n // Call the function to load and render our template.\n const {html, js} = await Templates.renderForPromise('block_ai_chat/message', templateData);\n Templates.appendNodeContents('.block_ai_chat-output', html, js);\n\n // Add copy listener for replys.\n if (sender === '') {\n helper.attachCopyListenerLast();\n }\n\n // Scroll the modal content to the bottom.\n helper.scrollToBottom();\n};\n\n/**\n * Create new / Reset dialog.\n * @param {bool} deleted\n */\nconst newDialog = async(deleted = false) => {\n if (aiAtWork) {\n return;\n }\n // Add current convo local representation, if not already there.\n if (allConversations.find(x => x.id === conversation.id) === undefined && !deleted) {\n allConversations.push(conversation);\n }\n // Reset local conservation.\n conversation = {\n id: 0,\n messages: [],\n };\n clearMessages();\n setModalHeader(strNewDialog);\n helper.focustextarea();\n};\n\n/**\n * Delete /hide current dialog.\n */\nconst deleteCurrentDialog = () => {\n deleteCancelPromise(\n getString('delete', 'block_ai_chat'),\n getString('deletewarning', 'block_ai_chat'),\n ).then(async() => {\n if (conversation.id !== 0) {\n try {\n const deleted = await externalServices.deleteConversation(contextid, userid, conversation.id);\n if (deleted) {\n removeFromHistory();\n showConversation();\n }\n } catch (error) {\n displayException(error);\n }\n }\n return;\n }).catch(() => {\n return;\n });\n};\n\n/**\n * Show conversation history.\n */\nconst showHistory = async() => {\n // Add current convo local representation, if not already there.\n if (allConversations.find(x => x.id === conversation.id) === undefined) {\n allConversations.push(conversation);\n }\n // Change title and add backlink.\n let title = '' + strHistory + '';\n clearMessages(true);\n setModalHeader(title);\n const btnBacklink = document.getElementById('block_ai_chat_backlink');\n btnBacklink.addEventListener('click', () => {\n if (conversation.id !== 0) {\n showConversation(conversation.id);\n } else {\n newDialog();\n }\n clearMessages();\n setModalHeader();\n });\n\n // Set modal class to hide info about ratelimits and infobox.\n let modal = document.querySelector('.ai_chat_modal');\n modal.classList.add('onhistorypage');\n\n // Iterate over conversations and group by date.\n let groupedByDate = {};\n allConversations.forEach((convo) => {\n if (typeof convo.messages[1] !== 'undefined') {\n // Get first prompt.\n let title = convo.messages[1].message;\n\n // Get date and sort convos into a date array.\n const now = new Date();\n const date = new Date(convo.timecreated * 1000);\n const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());\n const yesterday = new Date(now.getFullYear(), now.getMonth(), now.getDate() - 1);\n const twoWeeksAgo = new Date(now);\n twoWeeksAgo.setDate(now.getDate() - 14);\n\n const options = {weekday: 'long', day: '2-digit', month: '2-digit'};\n const monthOptions = {month: 'long', year: '2-digit'};\n\n // Create a date string.\n let dateString = '';\n if (date >= today) {\n dateString = strToday;\n } else if (date >= yesterday) {\n dateString = strYesterday;\n } else if (date >= twoWeeksAgo) {\n dateString = date.toLocaleDateString(undefined, options);\n } else {\n dateString = date.toLocaleDateString(undefined, monthOptions);\n }\n\n // Create a time string.\n const hours = date.getHours();\n const minutes = date.getMinutes().toString().padStart(2, '0');\n\n let convItem = {\n \"title\": title,\n \"conversationid\": convo.id,\n \"time\": hours + ':' + minutes,\n };\n\n // Save entry under the date.\n if (!groupedByDate[dateString]) {\n groupedByDate[dateString] = [];\n }\n groupedByDate[dateString].push(convItem);\n }\n });\n\n // Convert the grouped objects into an array format that Mustache can iterate over.\n let convert = {\n groups: Object.keys(groupedByDate).map(key => ({\n key: key,\n objects: groupedByDate[key]\n }))\n };\n\n // Render history.\n const templateData = {\n \"dates\": convert.groups,\n };\n const {html, js} = await Templates.renderForPromise('block_ai_chat/history', templateData);\n Templates.appendNodeContents('.ai_chat_modal .block_ai_chat-output', html, js);\n\n // Add a listener for the new dialog button.\n const btnNewDialog = document.getElementById('ai_chat_history_new_dialog');\n btnNewDialog.addEventListener('mousedown', () => {\n newDialog();\n });\n};\n\n/**\n * Remove currrent conversation from history.\n */\nconst removeFromHistory = () => {\n // Cant remove if new or not yet in history.\n if (conversation.id !== 0 && allConversations.find(x => x.id === conversation.id) !== undefined) {\n // Build new allConversations array without deleted one.\n allConversations = allConversations.filter(obj => obj.id !== conversation.id);\n }\n};\n\n/**\n * Webservice Save conversation.\n * @param {*} question\n * @param {*} reply\n */\nconst saveConversationLocally = (question, reply) => {\n // Add to local representation.\n let message = {'message': question, 'sender': 'user'};\n conversation.messages.push(message);\n message = {'message': reply, 'sender': 'ai'};\n conversation.messages.push(message);\n};\n\n/**\n * Clear output div.\n * @param {*} hideinput\n */\nconst clearMessages = (hideinput = false) => {\n const output = document.querySelector('.block_ai_chat-output');\n output.innerHTML = '';\n // For showing history.\n let input = document.querySelector('.block_ai_chat-input');\n if (hideinput) {\n input.style.display = 'none';\n } else {\n input.style.display = 'flex';\n }\n};\n\n/**\n * Set modal header title.\n * @param {*} setTitle\n */\nconst setModalHeader = (setTitle = '') => {\n let modalheader = document.querySelector('.ai_chat_modal .modal-title div');\n let title = '';\n if (modalheader !== null && (conversation.messages.length > 0 || setTitle.length)) {\n if (!setTitle.length) {\n title = conversation.messages[1].message;\n } else {\n title = setTitle;\n }\n modalheader.innerHTML = title;\n }\n // Remove onhistorypage, since history page is setting it.\n let modal = document.querySelector('.ai_chat_modal');\n modal.classList.remove('onhistorypage');\n};\n\n/**\n * Attach event listener.\n * @param {*} textarea\n */\nconst addTextareaListener = (textarea) => {\n textarea.addEventListener('keydown', (event) => {\n // Handle submission.\n textareaOnKeydown(event);\n\n // Handle autgrow.\n // Reset the height to auto to get the correct scrollHeight.\n textarea.style.height = 'auto';\n\n // Fetch the computed styles.\n const computedStyles = window.getComputedStyle(textarea);\n const lineHeight = parseFloat(computedStyles.lineHeight);\n const paddingTop = parseFloat(computedStyles.paddingTop);\n const paddingBottom = parseFloat(computedStyles.paddingBottom);\n const borderTop = parseFloat(computedStyles.borderTopWidth);\n const borderBottom = parseFloat(computedStyles.borderBottomWidth);\n\n // Calculate the maximum height for four rows plus padding and borders.\n const maxHeight = (lineHeight * 4) + paddingTop + paddingBottom + borderTop + borderBottom;\n\n // Calculate the new height based on the scrollHeight.\n const newHeight = Math.min(textarea.scrollHeight + borderTop + borderBottom, maxHeight);\n\n // Set the new height.\n textarea.style.height = newHeight + 'px';\n });\n};\n\n/**\n * Action for textarea submission.\n * @param {*} event\n */\nconst textareaOnKeydown = (event) => {\n // TODO check for mobile devices.\n if (event.key === 'Enter' && !aiAtWork && !event.shiftKey) {\n aiAtWork = true;\n enterQuestion(event.target.value);\n event.preventDefault();\n event.target.value = '';\n }\n};\n\n/**\n * Submit form.\n */\nconst clickSubmitButton = () => {\n // Var aiAtWork to make it impossible to submit multiple questions at once.\n if (!aiAtWork) {\n aiAtWork = true;\n const textarea = document.getElementById('block_ai_chat-input-id');\n enterQuestion(textarea.value);\n textarea.value = '';\n }\n};\n\n/**\n * Handle error from local_ai_manager.\n * @param {*} requestresult\n * @param {*} question\n * @param {*} options\n * @returns {object}\n */\nconst errorHandling = async(requestresult, question, options) => {\n\n // If code 409, conversationid is already taken, try get new a one.\n if (requestresult.code == 409) {\n while (requestresult.code == 409) {\n try {\n let idresult = await externalServices.getNewConversationId(contextid);\n conversation.id = idresult.id;\n options.itemid = conversation.id;\n } catch (error) {\n displayException(error);\n }\n // Retry with new id.\n requestresult = await manager.askLocalAiManager('chat', question, options);\n return requestresult;\n }\n }\n\n // If any other errorcode, alert with errormessage.\n const errorString = await getString('errorwithcode', 'block_ai_chat', requestresult.code);\n const result = JSON.parse(requestresult.result);\n await displayAlert(errorString, result.message);\n\n // Change answer styling to differentiate from ai.\n const answerdivs = document.querySelectorAll('.awaitanswer');\n const answerdiv = answerdivs[answerdivs.length - 1];\n const messagediv = answerdiv.closest('.message');\n messagediv.classList.add('text-danger');\n\n // And write generic error message in chatbot.\n requestresult.result = await getString('error', 'block_ai_chat');\n return requestresult;\n};\n\n/**\n * Check historic messages for max length.\n * @param {array} messages\n * @returns {array}\n */\nconst checkMessageHistoryLengthLimit = async(messages) => {\n const length = messages.length;\n if (length > maxHistory) {\n // Cut history.\n let shortenedMessages = [messages[0], ...messages.slice(-maxHistory)];\n\n // Show warning once per session.\n if (!maxHistoryWarnings.has(conversation.id)) {\n const maxHistoryString = await getString('maxhistory', 'block_ai_chat', maxHistory);\n const warningErrorString = await getString('maxhistoryreached', 'block_ai_chat', maxHistory);\n await displayAlert(maxHistoryString, warningErrorString);\n // Remember warning.\n maxHistoryWarnings.add(conversation.id);\n }\n return shortenedMessages;\n }\n // Limit not reached, return messages.\n return messages;\n};\n\n/**\n * Check if modal should close on outside click.\n * @param {*} event\n */\nconst checkOutsideClick = (event) => {\n // View openfull acts like a normal modal.\n if (viewmode != VIEW_OPENFULL) {\n event.preventDefault();\n }\n};\n\n/**\n * Set different viewmodes and save in local storage.\n * @param {string} mode\n */\nconst setView = async(mode = '') => {\n const key = await hash('chatmode' + userid);\n // Check for saved viewmode.\n let savedmode = LocalStorage.get(key);\n if (mode == '') {\n if (!savedmode) {\n // Set default.\n mode = VIEW_CHATWINDOW;\n } else {\n mode = savedmode;\n }\n }\n // Save viewmode and set global var.\n LocalStorage.set(key, mode);\n viewmode = mode;\n\n // Set viewmode as bodyclass.\n const body = document.querySelector('body');\n body.classList.remove(VIEW_CHATWINDOW, VIEW_OPENFULL, VIEW_DOCKRIGHT);\n body.classList.add(mode);\n};\n\n/**\n * Is user allowed new queries.\n * @returns {message}\n */\nconst userAllowed = async() => {\n let message;\n if (tenantConfig.tenantenabled === false) {\n message = await getString('error_http403disabled', 'local_ai_manager');\n return message;\n }\n if (tenantConfig.userconfirmed === false) {\n message = await getString('error_http403notconfirmed', 'local_ai_manager');\n message += \". \";\n const link = window.location.origin + '/local/ai_manager/confirm_ai_usage.php';\n message += await getString('confirm_ai_usage', 'block_ai_chat', link);\n return message;\n }\n if (tenantConfig.userlocked === true) {\n message = await getString('error_http403blocked', 'local_ai_manager');\n return message;\n }\n if (chatConfig.isconfigured === false) {\n message = await getString('error_purposenotconfigured', 'local_ai_manager');\n return message;\n }\n if (chatConfig.lockedforrole === true) {\n message = await getString('error_http403blocked', 'local_ai_manager');\n return message;\n }\n if (chatConfig.limitreached === true) {\n message = await getString('error_limitreached', 'local_ai_manager');\n return message;\n }\n return '';\n};\n\n/**\n * Change to openfull view when screen is small.\n * @param {*} e\n */\nconst handleScreenWidthChange = (e) => {\n const body = document.querySelector('body');\n if (e.matches) {\n // Screen width is less than 576px\n body.classList.remove(VIEW_CHATWINDOW, VIEW_OPENFULL, VIEW_DOCKRIGHT);\n body.classList.add(VIEW_OPENFULL);\n } else {\n body.classList.remove(VIEW_CHATWINDOW, VIEW_OPENFULL, VIEW_DOCKRIGHT);\n body.classList.add(viewmode);\n }\n};\n"],"names":["VIEW_CHATWINDOW","VIEW_OPENFULL","VIEW_DOCKRIGHT","strHistory","strNewDialog","strToday","strYesterday","badge","viewmode","modal","modalopen","conversation","id","messages","allConversations","userid","contextid","firstLoad","aiAtWork","maxHistory","maxHistoryWarnings","Set","tenantConfig","chatConfig","DialogModal","Modal","configure","modalConfig","show","removeOnClose","isVerticallyCentered","titletest","setTitletest","value","hide","document","querySelector","classList","remove","async","params","new","history","aiConfig","purposes","find","p","purpose","create","templateContext","title","getRoot","on","e","target","add","ModalEvents","outsideClick","event","checkOutsideClick","setView","getElementById","addEventListener","textarea","addTextareaListener","clickSubmitButton","getConversations","showConversation","conversationcontextLimit","externalServices","getConversationcontextLimit","limit","newDialog","deleteCurrentDialog","showHistory","message","userAllowed","notice","helper","focustextarea","showModal","window","matchMedia","handleScreenWidthChange","innerWidth","getAllConversations","error","x","at","length","clearMessages","setModalHeader","showMessages","enterQuestion","question","showMessage","currentUserLanguage","Config","language","substring","LangNames","Intl","DisplayNames","type","push","of","convHistory","checkMessageHistoryLengthLimit","options","idresult","getNewConversationId","timecreated","Math","floor","Date","now","forcenewitemid","itemid","requestresult","manager","askLocalAiManager","code","errorHandling","copy","copyToClipboard","showReply","result","saveConversationLocally","innerHTML","fields","querySelectorAll","field","text","awaitdivs","forEach","val","sender","answer","templateData","html","js","Templates","renderForPromise","appendNodeContents","attachCopyListenerLast","scrollToBottom","deleted","undefined","then","deleteConversation","removeFromHistory","catch","groupedByDate","convo","date","today","getFullYear","getMonth","getDate","yesterday","twoWeeksAgo","setDate","weekday","day","month","monthOptions","year","dateString","toLocaleDateString","hours","getHours","minutes","getMinutes","toString","padStart","convItem","groups","Object","keys","map","key","objects","filter","obj","reply","hideinput","output","input","style","display","setTitle","modalheader","textareaOnKeydown","height","computedStyles","getComputedStyle","lineHeight","parseFloat","paddingTop","paddingBottom","borderTop","borderTopWidth","borderBottom","borderBottomWidth","maxHeight","newHeight","min","scrollHeight","shiftKey","preventDefault","errorString","JSON","parse","answerdivs","closest","shortenedMessages","slice","has","maxHistoryString","warningErrorString","mode","savedmode","LocalStorage","get","set","body","tenantenabled","userconfirmed","link","location","origin","userlocked","isconfigured","lockedforrole","limitreached","matches"],"mappings":"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"} \ No newline at end of file diff --git a/amd/build/helper.min.js b/amd/build/helper.min.js index 460aca8..acf1467 100644 --- a/amd/build/helper.min.js +++ b/amd/build/helper.min.js @@ -1,3 +1,3 @@ -define("block_ai_chat/helper",["exports"],(function(_exports){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.scrollToBottom=_exports.hash=_exports.focustextarea=_exports.escapeHTML=_exports.copyToClipboard=_exports.attachCopyListenerLast=void 0;const copyToClipboard=element=>{const textElement=element.nextElementSibling,textToCopy=textElement.innerText||textElement.textContent;navigator.clipboard.writeText(textToCopy);const toast=element.previousElementSibling;toast.style.visibility="visible",setTimeout((()=>{toast.style.visibility="hidden"}),750)};_exports.copyToClipboard=copyToClipboard;_exports.attachCopyListenerLast=()=>{const elements=document.querySelectorAll(".ai_chat_modal .copy"),last=elements[elements.length-1];last.addEventListener("click",(function(){copyToClipboard(last)}))};_exports.focustextarea=()=>{document.getElementById("block_ai_chat-input-id").focus()};_exports.scrollToBottom=()=>{console.log("scroll to bottom called");const modalContent=document.querySelector(".ai_chat_modal .modal-body .block_ai_chat-output-wrapper");modalContent.scrollTop=modalContent.scrollHeight};_exports.escapeHTML=str=>{if(null==str)return"";const escapeMap={"&":"&","<":"<",">":">",'"':""","'":"'","`":"`","/":"/"};return String(str).replace(/[&<>"'`\/]/g,(function(match){return escapeMap[match]}))};_exports.hash=async stringToHash=>{const data=(new TextEncoder).encode(stringToHash),hashAsArrayBuffer=await window.crypto.subtle.digest("SHA-256",data),uint8ViewOfHash=new Uint8Array(hashAsArrayBuffer);return Array.from(uint8ViewOfHash).map((b=>b.toString(16).padStart(2,"0"))).join("")}})); +define("block_ai_chat/helper",["exports"],(function(_exports){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.scrollToBottom=_exports.hash=_exports.focustextarea=_exports.escapeHTML=_exports.copyToClipboard=_exports.attachCopyListenerLast=void 0;const copyToClipboard=element=>{const textElement=element.nextElementSibling,textToCopy=textElement.innerText||textElement.textContent;navigator.clipboard.writeText(textToCopy);const toast=element.previousElementSibling;toast.style.visibility="visible",setTimeout((()=>{toast.style.visibility="hidden"}),750)};_exports.copyToClipboard=copyToClipboard;_exports.attachCopyListenerLast=()=>{const elements=document.querySelectorAll(".ai_chat_modal .copy"),last=elements[elements.length-1];last.addEventListener("click",(function(){copyToClipboard(last)}))};_exports.focustextarea=()=>{document.getElementById("block_ai_chat-input-id").focus()};_exports.scrollToBottom=()=>{const modalContent=document.querySelector(".ai_chat_modal .modal-body .block_ai_chat-output-wrapper");modalContent.scrollTop=modalContent.scrollHeight};_exports.escapeHTML=str=>{if(null==str)return"";const escapeMap={"&":"&","<":"<",">":">",'"':""","'":"'","`":"`","/":"/"};return String(str).replace(/[&<>"'`/]/g,(function(match){return escapeMap[match]}))};_exports.hash=async stringToHash=>{const data=(new TextEncoder).encode(stringToHash),hashAsArrayBuffer=await window.crypto.subtle.digest("SHA-256",data),uint8ViewOfHash=new Uint8Array(hashAsArrayBuffer);return Array.from(uint8ViewOfHash).map((b=>b.toString(16).padStart(2,"0"))).join("")}})); //# sourceMappingURL=helper.min.js.map \ No newline at end of file diff --git a/amd/build/helper.min.js.map b/amd/build/helper.min.js.map index ce3b10b..8bbdfc3 100644 --- a/amd/build/helper.min.js.map +++ b/amd/build/helper.min.js.map @@ -1 +1 @@ -{"version":3,"file":"helper.min.js","sources":["../src/helper.js"],"sourcesContent":["/**\n * Copy ai reply to clipboard.\n * @param {*} element\n */\nexport const copyToClipboard = (element) => {\n\n // Find the adjacent text container.\n const textElement = element.nextElementSibling;\n\n // Get the text content.\n const textToCopy = textElement.innerText || textElement.textContent;\n\n // Copy to clipboard using the Clipboard API.\n navigator.clipboard.writeText(textToCopy);\n\n // Briefly show toast.\n const toast = element.previousElementSibling;\n toast.style.visibility = 'visible';\n setTimeout(() => {\n toast.style.visibility = 'hidden';\n }, 750);\n\n};\n\n/**\n * Attach copy listener to all elements.\n */\nexport const attachCopyListenerLast = () => {\n const elements = document.querySelectorAll(\".ai_chat_modal .copy\");\n const last = elements[elements.length - 1];\n last.addEventListener('click', function() {\n copyToClipboard(last);\n });\n};\n\n\n/**\n * Focus textarea.\n */\nexport const focustextarea = () => {\n const textarea = document.getElementById('block_ai_chat-input-id');\n textarea.focus();\n};\n\n\n/**\n * Scroll to bottom of modal body.\n */\nexport const scrollToBottom = () => {\n console.log(\"scroll to bottom called\");\n const modalContent = document.querySelector('.ai_chat_modal .modal-body .block_ai_chat-output-wrapper');\n modalContent.scrollTop = modalContent.scrollHeight;\n};\n\n\n/**\n * Escape html.\n * @param {*} str\n */\nexport const escapeHTML = (str) => {\n if (str === null || str === undefined) {\n return '';\n }\n const escapeMap = {\n '&': '&',\n '<': '<',\n '>': '>',\n '\"': '"',\n \"'\": ''',\n '`': '`',\n '/': '/',\n };\n\n return String(str).replace(/[&<>\"'`\\/]/g, function(match) {\n return escapeMap[match];\n });\n};\n\n/**\n * Hash function to get a hash of a string.\n *\n * @param {string} stringToHash the string to hash\n * @returns {Promise} the promise containing a hex representation of the string encoded by SHA-256\n */\nexport const hash = async(stringToHash) => {\n const encoder = new TextEncoder();\n const data = encoder.encode(stringToHash);\n const hashAsArrayBuffer = await window.crypto.subtle.digest(\"SHA-256\", data);\n const uint8ViewOfHash = new Uint8Array(hashAsArrayBuffer);\n return Array.from(uint8ViewOfHash)\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\");\n};\n"],"names":["copyToClipboard","element","textElement","nextElementSibling","textToCopy","innerText","textContent","navigator","clipboard","writeText","toast","previousElementSibling","style","visibility","setTimeout","elements","document","querySelectorAll","last","length","addEventListener","getElementById","focus","console","log","modalContent","querySelector","scrollTop","scrollHeight","str","escapeMap","String","replace","match","async","data","TextEncoder","encode","stringToHash","hashAsArrayBuffer","window","crypto","subtle","digest","uint8ViewOfHash","Uint8Array","Array","from","map","b","toString","padStart","join"],"mappings":"6QAIaA,gBAAmBC,gBAGtBC,YAAcD,QAAQE,mBAGtBC,WAAaF,YAAYG,WAAaH,YAAYI,YAGxDC,UAAUC,UAAUC,UAAUL,kBAGxBM,MAAQT,QAAQU,uBACtBD,MAAME,MAAMC,WAAa,UACzBC,YAAW,KACRJ,MAAME,MAAMC,WAAa,WACzB,+EAO+B,WAC5BE,SAAWC,SAASC,iBAAiB,wBACrCC,KAAOH,SAASA,SAASI,OAAS,GACxCD,KAAKE,iBAAiB,SAAS,WAC3BpB,gBAAgBkB,iCAQK,KACRF,SAASK,eAAe,0BAChCC,iCAOiB,KAC1BC,QAAQC,IAAI,iCACNC,aAAeT,SAASU,cAAc,4DAC5CD,aAAaE,UAAYF,aAAaG,kCAQfC,SACnBA,MAAAA,UACO,SAELC,UAAY,KACT,YACA,WACA,WACA,aACA,YACA,aACA,iBAGFC,OAAOF,KAAKG,QAAQ,eAAe,SAASC,cACxCH,UAAUG,yBAULC,MAAAA,qBAEVC,MADU,IAAIC,aACCC,OAAOC,cACtBC,wBAA0BC,OAAOC,OAAOC,OAAOC,OAAO,UAAWR,MACjES,gBAAkB,IAAIC,WAAWN,0BAChCO,MAAMC,KAAKH,iBACbI,KAAKC,GAAMA,EAAEC,SAAS,IAAIC,SAAS,EAAG,OACtCC,KAAK"} \ No newline at end of file +{"version":3,"file":"helper.min.js","sources":["../src/helper.js"],"sourcesContent":["/**\n * Copy ai reply to clipboard.\n * @param {*} element\n */\nexport const copyToClipboard = (element) => {\n\n // Find the adjacent text container.\n const textElement = element.nextElementSibling;\n\n // Get the text content.\n const textToCopy = textElement.innerText || textElement.textContent;\n\n // Copy to clipboard using the Clipboard API.\n navigator.clipboard.writeText(textToCopy);\n\n // Briefly show toast.\n const toast = element.previousElementSibling;\n toast.style.visibility = 'visible';\n setTimeout(() => {\n toast.style.visibility = 'hidden';\n }, 750);\n\n};\n\n/**\n * Attach copy listener to all elements.\n */\nexport const attachCopyListenerLast = () => {\n const elements = document.querySelectorAll(\".ai_chat_modal .copy\");\n const last = elements[elements.length - 1];\n last.addEventListener('click', function() {\n copyToClipboard(last);\n });\n};\n\n\n/**\n * Focus textarea.\n */\nexport const focustextarea = () => {\n const textarea = document.getElementById('block_ai_chat-input-id');\n textarea.focus();\n};\n\n\n/**\n * Scroll to bottom of modal body.\n */\nexport const scrollToBottom = () => {\n const modalContent = document.querySelector('.ai_chat_modal .modal-body .block_ai_chat-output-wrapper');\n modalContent.scrollTop = modalContent.scrollHeight;\n};\n\n\n/**\n * Escape html.\n * @param {*} str\n */\nexport const escapeHTML = (str) => {\n if (str === null || str === undefined) {\n return '';\n }\n const escapeMap = {\n '&': '&',\n '<': '<',\n '>': '>',\n '\"': '"',\n \"'\": ''',\n '`': '`',\n '/': '/',\n };\n\n return String(str).replace(/[&<>\"'`/]/g, function(match) {\n return escapeMap[match];\n });\n};\n\n/**\n * Hash function to get a hash of a string.\n *\n * @param {string} stringToHash the string to hash\n * @returns {Promise} the promise containing a hex representation of the string encoded by SHA-256\n */\nexport const hash = async(stringToHash) => {\n const encoder = new TextEncoder();\n const data = encoder.encode(stringToHash);\n const hashAsArrayBuffer = await window.crypto.subtle.digest(\"SHA-256\", data);\n const uint8ViewOfHash = new Uint8Array(hashAsArrayBuffer);\n return Array.from(uint8ViewOfHash)\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\");\n};\n"],"names":["copyToClipboard","element","textElement","nextElementSibling","textToCopy","innerText","textContent","navigator","clipboard","writeText","toast","previousElementSibling","style","visibility","setTimeout","elements","document","querySelectorAll","last","length","addEventListener","getElementById","focus","modalContent","querySelector","scrollTop","scrollHeight","str","escapeMap","String","replace","match","async","data","TextEncoder","encode","stringToHash","hashAsArrayBuffer","window","crypto","subtle","digest","uint8ViewOfHash","Uint8Array","Array","from","map","b","toString","padStart","join"],"mappings":"6QAIaA,gBAAmBC,gBAGtBC,YAAcD,QAAQE,mBAGtBC,WAAaF,YAAYG,WAAaH,YAAYI,YAGxDC,UAAUC,UAAUC,UAAUL,kBAGxBM,MAAQT,QAAQU,uBACtBD,MAAME,MAAMC,WAAa,UACzBC,YAAW,KACRJ,MAAME,MAAMC,WAAa,WACzB,+EAO+B,WAC5BE,SAAWC,SAASC,iBAAiB,wBACrCC,KAAOH,SAASA,SAASI,OAAS,GACxCD,KAAKE,iBAAiB,SAAS,WAC3BpB,gBAAgBkB,iCAQK,KACRF,SAASK,eAAe,0BAChCC,iCAOiB,WACpBC,aAAeP,SAASQ,cAAc,4DAC5CD,aAAaE,UAAYF,aAAaG,kCAQfC,SACnBA,MAAAA,UACO,SAELC,UAAY,KACT,YACA,WACA,WACA,aACA,YACA,aACA,iBAGFC,OAAOF,KAAKG,QAAQ,cAAc,SAASC,cACvCH,UAAUG,yBAULC,MAAAA,qBAEVC,MADU,IAAIC,aACCC,OAAOC,cACtBC,wBAA0BC,OAAOC,OAAOC,OAAOC,OAAO,UAAWR,MACjES,gBAAkB,IAAIC,WAAWN,0BAChCO,MAAMC,KAAKH,iBACbI,KAAKC,GAAMA,EAAEC,SAAS,IAAIC,SAAS,EAAG,OACtCC,KAAK"} \ No newline at end of file diff --git a/amd/build/marked.esm.min.js b/amd/build/marked.esm.min.js deleted file mode 100644 index 8b233e7..0000000 --- a/amd/build/marked.esm.min.js +++ /dev/null @@ -1,3 +0,0 @@ -define("block_ai_chat/marked.esm",["exports"],(function(_exports){function _getDefaults(){return{async:!1,breaks:!1,extensions:null,gfm:!0,hooks:null,pedantic:!1,renderer:null,silent:!1,tokenizer:null,walkTokens:null}}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.defaults=_exports.Tokenizer=_exports.TextRenderer=_exports.Renderer=_exports.Parser=_exports.Marked=_exports.Lexer=_exports.Hooks=void 0,_exports.getDefaults=_getDefaults,_exports.lexer=void 0,_exports.marked=marked,_exports.walkTokens=_exports.use=_exports.setOptions=_exports.parser=_exports.parseInline=_exports.parse=_exports.options=void 0;let _defaults={async:!1,breaks:!1,extensions:null,gfm:!0,hooks:null,pedantic:!1,renderer:null,silent:!1,tokenizer:null,walkTokens:null};function changeDefaults(newDefaults){_exports.defaults=_defaults=newDefaults}_exports.defaults=_defaults;const escapeTest=/[&<>"']/,escapeReplace=new RegExp(escapeTest.source,"g"),escapeTestNoEncode=/[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/,escapeReplaceNoEncode=new RegExp(escapeTestNoEncode.source,"g"),escapeReplacements={"&":"&","<":"<",">":">",'"':""","'":"'"},getEscapeReplacement=ch=>escapeReplacements[ch];function escape$1(html,encode){if(encode){if(escapeTest.test(html))return html.replace(escapeReplace,getEscapeReplacement)}else if(escapeTestNoEncode.test(html))return html.replace(escapeReplaceNoEncode,getEscapeReplacement);return html}const unescapeTest=/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/gi;function unescape(html){return html.replace(unescapeTest,((_,n)=>"colon"===(n=n.toLowerCase())?":":"#"===n.charAt(0)?"x"===n.charAt(1)?String.fromCharCode(parseInt(n.substring(2),16)):String.fromCharCode(+n.substring(1)):""))}const caret=/(^|[^\[])\^/g;function edit(regex,opt){let source="string"==typeof regex?regex:regex.source;opt=opt||"";const obj={replace:(name,val)=>{let valSource="string"==typeof val?val:val.source;return valSource=valSource.replace(caret,"$1"),source=source.replace(name,valSource),obj},getRegex:()=>new RegExp(source,opt)};return obj}function cleanUrl(href){try{href=encodeURI(href).replace(/%25/g,"%")}catch(e){return null}return href}const noopTest={exec:()=>null};function splitCells(tableRow,count){const cells=tableRow.replace(/\|/g,((match,offset,str)=>{let escaped=!1,curr=offset;for(;--curr>=0&&"\\"===str[curr];)escaped=!escaped;return escaped?"|":" |"})).split(/ \|/);let i=0;if(cells[0].trim()||cells.shift(),cells.length>0&&!cells[cells.length-1].trim()&&cells.pop(),count)if(cells.length>count)cells.splice(count);else for(;cells.length0)return{type:"space",raw:cap[0]}}code(src){const cap=this.rules.block.code.exec(src);if(cap){const text=cap[0].replace(/^ {1,4}/gm,"");return{type:"code",raw:cap[0],codeBlockStyle:"indented",text:this.options.pedantic?text:rtrim(text,"\n")}}}fences(src){const cap=this.rules.block.fences.exec(src);if(cap){const raw=cap[0],text=function(raw,text){const matchIndentToCode=raw.match(/^(\s+)(?:```)/);if(null===matchIndentToCode)return text;const indentToCode=matchIndentToCode[1];return text.split("\n").map((node=>{const matchIndentInNode=node.match(/^\s+/);if(null===matchIndentInNode)return node;const[indentInNode]=matchIndentInNode;return indentInNode.length>=indentToCode.length?node.slice(indentToCode.length):node})).join("\n")}(raw,cap[3]||"");return{type:"code",raw:raw,lang:cap[2]?cap[2].trim().replace(this.rules.inline.anyPunctuation,"$1"):cap[2],text:text}}}heading(src){const cap=this.rules.block.heading.exec(src);if(cap){let text=cap[2].trim();if(/#$/.test(text)){const trimmed=rtrim(text,"#");this.options.pedantic?text=trimmed.trim():trimmed&&!/ $/.test(trimmed)||(text=trimmed.trim())}return{type:"heading",raw:cap[0],depth:cap[1].length,text:text,tokens:this.lexer.inline(text)}}}hr(src){const cap=this.rules.block.hr.exec(src);if(cap)return{type:"hr",raw:cap[0]}}blockquote(src){const cap=this.rules.block.blockquote.exec(src);if(cap){let text=cap[0].replace(/\n {0,3}((?:=+|-+) *)(?=\n|$)/g,"\n $1");text=rtrim(text.replace(/^ *>[ \t]?/gm,""),"\n");const top=this.lexer.state.top;this.lexer.state.top=!0;const tokens=this.lexer.blockTokens(text);return this.lexer.state.top=top,{type:"blockquote",raw:cap[0],tokens:tokens,text:text}}}list(src){let cap=this.rules.block.list.exec(src);if(cap){let bull=cap[1].trim();const isordered=bull.length>1,list={type:"list",raw:"",ordered:isordered,start:isordered?+bull.slice(0,-1):"",loose:!1,items:[]};bull=isordered?`\\d{1,9}\\${bull.slice(-1)}`:`\\${bull}`,this.options.pedantic&&(bull=isordered?bull:"[*+-]");const itemRegex=new RegExp(`^( {0,3}${bull})((?:[\t ][^\\n]*)?(?:\\n|$))`);let raw="",itemContents="",endsWithBlankLine=!1;for(;src;){let endEarly=!1;if(!(cap=itemRegex.exec(src)))break;if(this.rules.block.hr.test(src))break;raw=cap[0],src=src.substring(raw.length);let line=cap[2].split("\n",1)[0].replace(/^\t+/,(t=>" ".repeat(3*t.length))),nextLine=src.split("\n",1)[0],indent=0;this.options.pedantic?(indent=2,itemContents=line.trimStart()):(indent=cap[2].search(/[^ ]/),indent=indent>4?1:indent,itemContents=line.slice(indent),indent+=cap[1].length);let blankLine=!1;if(!line&&/^ *$/.test(nextLine)&&(raw+=nextLine+"\n",src=src.substring(nextLine.length+1),endEarly=!0),!endEarly){const nextBulletRegex=new RegExp(`^ {0,${Math.min(3,indent-1)}}(?:[*+-]|\\d{1,9}[.)])((?:[ \t][^\\n]*)?(?:\\n|$))`),hrRegex=new RegExp(`^ {0,${Math.min(3,indent-1)}}((?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$)`),fencesBeginRegex=new RegExp(`^ {0,${Math.min(3,indent-1)}}(?:\`\`\`|~~~)`),headingBeginRegex=new RegExp(`^ {0,${Math.min(3,indent-1)}}#`);for(;src;){const rawLine=src.split("\n",1)[0];if(nextLine=rawLine,this.options.pedantic&&(nextLine=nextLine.replace(/^ {1,4}(?=( {4})*[^ ])/g," ")),fencesBeginRegex.test(nextLine))break;if(headingBeginRegex.test(nextLine))break;if(nextBulletRegex.test(nextLine))break;if(hrRegex.test(src))break;if(nextLine.search(/[^ ]/)>=indent||!nextLine.trim())itemContents+="\n"+nextLine.slice(indent);else{if(blankLine)break;if(line.search(/[^ ]/)>=4)break;if(fencesBeginRegex.test(line))break;if(headingBeginRegex.test(line))break;if(hrRegex.test(line))break;itemContents+="\n"+nextLine}blankLine||nextLine.trim()||(blankLine=!0),raw+=rawLine+"\n",src=src.substring(rawLine.length+1),line=nextLine.slice(indent)}}list.loose||(endsWithBlankLine?list.loose=!0:/\n *\n *$/.test(raw)&&(endsWithBlankLine=!0));let ischecked,istask=null;this.options.gfm&&(istask=/^\[[ xX]\] /.exec(itemContents),istask&&(ischecked="[ ] "!==istask[0],itemContents=itemContents.replace(/^\[[ xX]\] +/,""))),list.items.push({type:"list_item",raw:raw,task:!!istask,checked:ischecked,loose:!1,text:itemContents,tokens:[]}),list.raw+=raw}list.items[list.items.length-1].raw=raw.trimEnd(),list.items[list.items.length-1].text=itemContents.trimEnd(),list.raw=list.raw.trimEnd();for(let i=0;i"space"===t.type)),hasMultipleLineBreaks=spacers.length>0&&spacers.some((t=>/\n.*\n/.test(t.raw)));list.loose=hasMultipleLineBreaks}if(list.loose)for(let i=0;i$/,"$1").replace(this.rules.inline.anyPunctuation,"$1"):"",title=cap[3]?cap[3].substring(1,cap[3].length-1).replace(this.rules.inline.anyPunctuation,"$1"):cap[3];return{type:"def",tag:tag,raw:cap[0],href:href,title:title}}}table(src){const cap=this.rules.block.table.exec(src);if(!cap)return;if(!/[:|]/.test(cap[2]))return;const headers=splitCells(cap[1]),aligns=cap[2].replace(/^\||\| *$/g,"").split("|"),rows=cap[3]&&cap[3].trim()?cap[3].replace(/\n[ \t]*$/,"").split("\n"):[],item={type:"table",raw:cap[0],header:[],align:[],rows:[]};if(headers.length===aligns.length){for(const align of aligns)/^ *-+: *$/.test(align)?item.align.push("right"):/^ *:-+: *$/.test(align)?item.align.push("center"):/^ *:-+ *$/.test(align)?item.align.push("left"):item.align.push(null);for(const header of headers)item.header.push({text:header,tokens:this.lexer.inline(header)});for(const row of rows)item.rows.push(splitCells(row,item.header.length).map((cell=>({text:cell,tokens:this.lexer.inline(cell)}))));return item}}lheading(src){const cap=this.rules.block.lheading.exec(src);if(cap)return{type:"heading",raw:cap[0],depth:"="===cap[2].charAt(0)?1:2,text:cap[1],tokens:this.lexer.inline(cap[1])}}paragraph(src){const cap=this.rules.block.paragraph.exec(src);if(cap){const text="\n"===cap[1].charAt(cap[1].length-1)?cap[1].slice(0,-1):cap[1];return{type:"paragraph",raw:cap[0],text:text,tokens:this.lexer.inline(text)}}}text(src){const cap=this.rules.block.text.exec(src);if(cap)return{type:"text",raw:cap[0],text:cap[0],tokens:this.lexer.inline(cap[0])}}escape(src){const cap=this.rules.inline.escape.exec(src);if(cap)return{type:"escape",raw:cap[0],text:escape$1(cap[1])}}tag(src){const cap=this.rules.inline.tag.exec(src);if(cap)return!this.lexer.state.inLink&&/^/i.test(cap[0])&&(this.lexer.state.inLink=!1),!this.lexer.state.inRawBlock&&/^<(pre|code|kbd|script)(\s|>)/i.test(cap[0])?this.lexer.state.inRawBlock=!0:this.lexer.state.inRawBlock&&/^<\/(pre|code|kbd|script)(\s|>)/i.test(cap[0])&&(this.lexer.state.inRawBlock=!1),{type:"html",raw:cap[0],inLink:this.lexer.state.inLink,inRawBlock:this.lexer.state.inRawBlock,block:!1,text:cap[0]}}link(src){const cap=this.rules.inline.link.exec(src);if(cap){const trimmedUrl=cap[2].trim();if(!this.options.pedantic&&/^$/.test(trimmedUrl))return;const rtrimSlash=rtrim(trimmedUrl.slice(0,-1),"\\");if((trimmedUrl.length-rtrimSlash.length)%2==0)return}else{const lastParenIndex=function(str,b){if(-1===str.indexOf(b[1]))return-1;let level=0;for(let i=0;i-1){const linkLen=(0===cap[0].indexOf("!")?5:4)+cap[1].length+lastParenIndex;cap[2]=cap[2].substring(0,lastParenIndex),cap[0]=cap[0].substring(0,linkLen).trim(),cap[3]=""}}let href=cap[2],title="";if(this.options.pedantic){const link=/^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(href);link&&(href=link[1],title=link[3])}else title=cap[3]?cap[3].slice(1,-1):"";return href=href.trim(),/^$/.test(trimmedUrl)?href.slice(1):href.slice(1,-1)),outputLink(cap,{href:href?href.replace(this.rules.inline.anyPunctuation,"$1"):href,title:title?title.replace(this.rules.inline.anyPunctuation,"$1"):title},cap[0],this.lexer)}}reflink(src,links){let cap;if((cap=this.rules.inline.reflink.exec(src))||(cap=this.rules.inline.nolink.exec(src))){const link=links[(cap[2]||cap[1]).replace(/\s+/g," ").toLowerCase()];if(!link){const text=cap[0].charAt(0);return{type:"text",raw:text,text:text}}return outputLink(cap,link,cap[0],this.lexer)}}emStrong(src,maskedSrc){let prevChar=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"",match=this.rules.inline.emStrongLDelim.exec(src);if(!match)return;if(match[3]&&prevChar.match(/[\p{L}\p{N}]/u))return;if(!(match[1]||match[2]||"")||!prevChar||this.rules.inline.punctuation.exec(prevChar)){const lLength=[...match[0]].length-1;let rDelim,rLength,delimTotal=lLength,midDelimTotal=0;const endReg="*"===match[0][0]?this.rules.inline.emStrongRDelimAst:this.rules.inline.emStrongRDelimUnd;for(endReg.lastIndex=0,maskedSrc=maskedSrc.slice(-1*src.length+lLength);null!=(match=endReg.exec(maskedSrc));){if(rDelim=match[1]||match[2]||match[3]||match[4]||match[5]||match[6],!rDelim)continue;if(rLength=[...rDelim].length,match[3]||match[4]){delimTotal+=rLength;continue}if((match[5]||match[6])&&lLength%3&&!((lLength+rLength)%3)){midDelimTotal+=rLength;continue}if(delimTotal-=rLength,delimTotal>0)continue;rLength=Math.min(rLength,rLength+delimTotal+midDelimTotal);const lastCharLength=[...match[0]][0].length,raw=src.slice(0,lLength+match.index+lastCharLength+rLength);if(Math.min(lLength,rLength)%2){const text=raw.slice(1,-1);return{type:"em",raw:raw,text:text,tokens:this.lexer.inlineTokens(text)}}const text=raw.slice(2,-2);return{type:"strong",raw:raw,text:text,tokens:this.lexer.inlineTokens(text)}}}}codespan(src){const cap=this.rules.inline.code.exec(src);if(cap){let text=cap[2].replace(/\n/g," ");const hasNonSpaceChars=/[^ ]/.test(text),hasSpaceCharsOnBothEnds=/^ /.test(text)&&/ $/.test(text);return hasNonSpaceChars&&hasSpaceCharsOnBothEnds&&(text=text.substring(1,text.length-1)),text=escape$1(text,!0),{type:"codespan",raw:cap[0],text:text}}}br(src){const cap=this.rules.inline.br.exec(src);if(cap)return{type:"br",raw:cap[0]}}del(src){const cap=this.rules.inline.del.exec(src);if(cap)return{type:"del",raw:cap[0],text:cap[2],tokens:this.lexer.inlineTokens(cap[2])}}autolink(src){const cap=this.rules.inline.autolink.exec(src);if(cap){let text,href;return"@"===cap[2]?(text=escape$1(cap[1]),href="mailto:"+text):(text=escape$1(cap[1]),href=text),{type:"link",raw:cap[0],text:text,href:href,tokens:[{type:"text",raw:text,text:text}]}}}url(src){let cap;if(cap=this.rules.inline.url.exec(src)){let text,href;if("@"===cap[2])text=escape$1(cap[0]),href="mailto:"+text;else{let prevCapZero;do{var _this$rules$inline$_b;prevCapZero=cap[0],cap[0]=(null===(_this$rules$inline$_b=this.rules.inline._backpedal.exec(cap[0]))||void 0===_this$rules$inline$_b?void 0:_this$rules$inline$_b[0])??""}while(prevCapZero!==cap[0]);text=escape$1(cap[0]),href="www."===cap[1]?"http://"+cap[0]:cap[0]}return{type:"link",raw:cap[0],text:text,href:href,tokens:[{type:"text",raw:text,text:text}]}}}inlineText(src){const cap=this.rules.inline.text.exec(src);if(cap){let text;return text=this.lexer.state.inRawBlock?cap[0]:escape$1(cap[0]),{type:"text",raw:cap[0],text:text}}}}_exports.Tokenizer=_Tokenizer;const hr=/^ {0,3}((?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/,bullet=/(?:[*+-]|\d{1,9}[.)])/,lheading=edit(/^(?!bull |blockCode|fences|blockquote|heading|html)((?:.|\n(?!\s*?\n|bull |blockCode|fences|blockquote|heading|html))+?)\n {0,3}(=+|-+) *(?:\n+|$)/).replace(/bull/g,bullet).replace(/blockCode/g,/ {4}/).replace(/fences/g,/ {0,3}(?:`{3,}|~{3,})/).replace(/blockquote/g,/ {0,3}>/).replace(/heading/g,/ {0,3}#{1,6}/).replace(/html/g,/ {0,3}<[^\n>]+>\n/).getRegex(),_paragraph=/^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html|table| +\n)[^\n]+)*)/,_blockLabel=/(?!\s*\])(?:\\.|[^\[\]\\])+/,def=edit(/^ {0,3}\[(label)\]: *(?:\n *)?([^<\s][^\s]*|<.*?>)(?:(?: +(?:\n *)?| *\n *)(title))? *(?:\n+|$)/).replace("label",_blockLabel).replace("title",/(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/).getRegex(),list=edit(/^( {0,3}bull)([ \t][^\n]+?)?(?:\n|$)/).replace(/bull/g,bullet).getRegex(),_tag="address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|search|section|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul",_comment=/|$))/,html=edit("^ {0,3}(?:<(script|pre|style|textarea)[\\s>][\\s\\S]*?(?:[^\\n]*\\n+|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?(?:\\?>\\n*|$)|\\n*|$)|\\n*|$)|)[\\s\\S]*?(?:(?:\\n *)+\\n|$)|<(?!script|pre|style|textarea)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n *)+\\n|$)|(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n *)+\\n|$))","i").replace("comment",_comment).replace("tag",_tag).replace("attribute",/ +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex(),paragraph=edit(_paragraph).replace("hr",hr).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("|lheading","").replace("|table","").replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|textarea|!--)").replace("tag",_tag).getRegex(),blockNormal={blockquote:edit(/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/).replace("paragraph",paragraph).getRegex(),code:/^( {4}[^\n]+(?:\n(?: *(?:\n|$))*)?)+/,def:def,fences:/^ {0,3}(`{3,}(?=[^`\n]*(?:\n|$))|~{3,})([^\n]*)(?:\n|$)(?:|([\s\S]*?)(?:\n|$))(?: {0,3}\1[~`]* *(?=\n|$)|$)/,heading:/^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/,hr:hr,html:html,lheading:lheading,list:list,newline:/^(?: *(?:\n|$))+/,paragraph:paragraph,table:noopTest,text:/^[^\n]+/},gfmTable=edit("^ *([^\\n ].*)\\n {0,3}((?:\\| *)?:?-+:? *(?:\\| *:?-+:? *)*(?:\\| *)?)(?:\\n((?:(?! *\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)").replace("hr",hr).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("blockquote"," {0,3}>").replace("code"," {4}[^\\n]").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|textarea|!--)").replace("tag",_tag).getRegex(),blockGfm={...blockNormal,table:gfmTable,paragraph:edit(_paragraph).replace("hr",hr).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("|lheading","").replace("table",gfmTable).replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|textarea|!--)").replace("tag",_tag).getRegex()},blockPedantic={...blockNormal,html:edit("^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+? *(?:\\n{2,}|\\s*$)|\\s]*)*?/?> *(?:\\n{2,}|\\s*$))").replace("comment",_comment).replace(/tag/g,"(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(),def:/^ *\[([^\]]+)\]: *]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,heading:/^(#{1,6})(.*)(?:\n+|$)/,fences:noopTest,lheading:/^(.+?)\n {0,3}(=+|-+) *(?:\n+|$)/,paragraph:edit(_paragraph).replace("hr",hr).replace("heading"," *#{1,6} *[^\n]").replace("lheading",lheading).replace("|table","").replace("blockquote"," {0,3}>").replace("|fences","").replace("|list","").replace("|html","").replace("|tag","").getRegex()},escape=/^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,br=/^( {2,}|\\)\n(?!\s*$)/,punctuation=edit(/^((?![*_])[\spunctuation])/,"u").replace(/punctuation/g,"\\p{P}\\p{S}").getRegex(),emStrongLDelim=edit(/^(?:\*+(?:((?!\*)[punct])|[^\s*]))|^_+(?:((?!_)[punct])|([^\s_]))/,"u").replace(/punct/g,"\\p{P}\\p{S}").getRegex(),emStrongRDelimAst=edit("^[^_*]*?__[^_*]*?\\*[^_*]*?(?=__)|[^*]+(?=[^*])|(?!\\*)[punct](\\*+)(?=[\\s]|$)|[^punct\\s](\\*+)(?!\\*)(?=[punct\\s]|$)|(?!\\*)[punct\\s](\\*+)(?=[^punct\\s])|[\\s](\\*+)(?!\\*)(?=[punct])|(?!\\*)[punct](\\*+)(?!\\*)(?=[punct])|[^punct\\s](\\*+)(?=[^punct\\s])","gu").replace(/punct/g,"\\p{P}\\p{S}").getRegex(),emStrongRDelimUnd=edit("^[^_*]*?\\*\\*[^_*]*?_[^_*]*?(?=\\*\\*)|[^_]+(?=[^_])|(?!_)[punct](_+)(?=[\\s]|$)|[^punct\\s](_+)(?!_)(?=[punct\\s]|$)|(?!_)[punct\\s](_+)(?=[^punct\\s])|[\\s](_+)(?!_)(?=[punct])|(?!_)[punct](_+)(?!_)(?=[punct])","gu").replace(/punct/g,"\\p{P}\\p{S}").getRegex(),anyPunctuation=edit(/\\([punct])/,"gu").replace(/punct/g,"\\p{P}\\p{S}").getRegex(),autolink=edit(/^<(scheme:[^\s\x00-\x1f<>]*|email)>/).replace("scheme",/[a-zA-Z][a-zA-Z0-9+.-]{1,31}/).replace("email",/[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/).getRegex(),_inlineComment=edit(_comment).replace("(?:--\x3e|$)","--\x3e").getRegex(),tag=edit("^comment|^|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^|^").replace("comment",_inlineComment).replace("attribute",/\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/).getRegex(),_inlineLabel=/(?:\[(?:\\.|[^\[\]\\])*\]|\\.|`[^`]*`|[^\[\]\\`])*?/,link=edit(/^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/).replace("label",_inlineLabel).replace("href",/<(?:\\.|[^\n<>\\])+>|[^\s\x00-\x1f]*/).replace("title",/"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/).getRegex(),reflink=edit(/^!?\[(label)\]\[(ref)\]/).replace("label",_inlineLabel).replace("ref",_blockLabel).getRegex(),nolink=edit(/^!?\[(ref)\](?:\[\])?/).replace("ref",_blockLabel).getRegex(),inlineNormal={_backpedal:noopTest,anyPunctuation:anyPunctuation,autolink:autolink,blockSkip:/\[[^[\]]*?\]\([^\(\)]*?\)|`[^`]*?`|<[^<>]*?>/g,br:br,code:/^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,del:noopTest,emStrongLDelim:emStrongLDelim,emStrongRDelimAst:emStrongRDelimAst,emStrongRDelimUnd:emStrongRDelimUnd,escape:escape,link:link,nolink:nolink,punctuation:punctuation,reflink:reflink,reflinkSearch:edit("reflink|nolink(?!\\()","g").replace("reflink",reflink).replace("nolink",nolink).getRegex(),tag:tag,text:/^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\1&&void 0!==arguments[1]?arguments[1]:[];for(src=this.options.pedantic?src.replace(/\t/g," ").replace(/^ +$/gm,""):src.replace(/^( *)(\t+)/gm,((_,leading,tabs)=>leading+" ".repeat(tabs.length)));src;)if(!(this.options.extensions&&this.options.extensions.block&&this.options.extensions.block.some((extTokenizer=>!!(token=extTokenizer.call({lexer:this},src,tokens))&&(src=src.substring(token.raw.length),tokens.push(token),!0)))))if(token=this.tokenizer.space(src))src=src.substring(token.raw.length),1===token.raw.length&&tokens.length>0?tokens[tokens.length-1].raw+="\n":tokens.push(token);else if(token=this.tokenizer.code(src))src=src.substring(token.raw.length),lastToken=tokens[tokens.length-1],!lastToken||"paragraph"!==lastToken.type&&"text"!==lastToken.type?tokens.push(token):(lastToken.raw+="\n"+token.raw,lastToken.text+="\n"+token.text,this.inlineQueue[this.inlineQueue.length-1].src=lastToken.text);else if(token=this.tokenizer.fences(src))src=src.substring(token.raw.length),tokens.push(token);else if(token=this.tokenizer.heading(src))src=src.substring(token.raw.length),tokens.push(token);else if(token=this.tokenizer.hr(src))src=src.substring(token.raw.length),tokens.push(token);else if(token=this.tokenizer.blockquote(src))src=src.substring(token.raw.length),tokens.push(token);else if(token=this.tokenizer.list(src))src=src.substring(token.raw.length),tokens.push(token);else if(token=this.tokenizer.html(src))src=src.substring(token.raw.length),tokens.push(token);else if(token=this.tokenizer.def(src))src=src.substring(token.raw.length),lastToken=tokens[tokens.length-1],!lastToken||"paragraph"!==lastToken.type&&"text"!==lastToken.type?this.tokens.links[token.tag]||(this.tokens.links[token.tag]={href:token.href,title:token.title}):(lastToken.raw+="\n"+token.raw,lastToken.text+="\n"+token.raw,this.inlineQueue[this.inlineQueue.length-1].src=lastToken.text);else if(token=this.tokenizer.table(src))src=src.substring(token.raw.length),tokens.push(token);else if(token=this.tokenizer.lheading(src))src=src.substring(token.raw.length),tokens.push(token);else{if(cutSrc=src,this.options.extensions&&this.options.extensions.startBlock){let startIndex=1/0;const tempSrc=src.slice(1);let tempStart;this.options.extensions.startBlock.forEach((getStartIndex=>{tempStart=getStartIndex.call({lexer:this},tempSrc),"number"==typeof tempStart&&tempStart>=0&&(startIndex=Math.min(startIndex,tempStart))})),startIndex<1/0&&startIndex>=0&&(cutSrc=src.substring(0,startIndex+1))}if(this.state.top&&(token=this.tokenizer.paragraph(cutSrc)))lastToken=tokens[tokens.length-1],lastParagraphClipped&&"paragraph"===lastToken.type?(lastToken.raw+="\n"+token.raw,lastToken.text+="\n"+token.text,this.inlineQueue.pop(),this.inlineQueue[this.inlineQueue.length-1].src=lastToken.text):tokens.push(token),lastParagraphClipped=cutSrc.length!==src.length,src=src.substring(token.raw.length);else if(token=this.tokenizer.text(src))src=src.substring(token.raw.length),lastToken=tokens[tokens.length-1],lastToken&&"text"===lastToken.type?(lastToken.raw+="\n"+token.raw,lastToken.text+="\n"+token.text,this.inlineQueue.pop(),this.inlineQueue[this.inlineQueue.length-1].src=lastToken.text):tokens.push(token);else if(src){const errMsg="Infinite loop on byte: "+src.charCodeAt(0);if(this.options.silent){console.error(errMsg);break}throw new Error(errMsg)}}return this.state.top=!0,tokens}inline(src){let tokens=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[];return this.inlineQueue.push({src:src,tokens:tokens}),tokens}inlineTokens(src){let token,lastToken,cutSrc,match,keepPrevChar,prevChar,tokens=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[],maskedSrc=src;if(this.tokens.links){const links=Object.keys(this.tokens.links);if(links.length>0)for(;null!=(match=this.tokenizer.rules.inline.reflinkSearch.exec(maskedSrc));)links.includes(match[0].slice(match[0].lastIndexOf("[")+1,-1))&&(maskedSrc=maskedSrc.slice(0,match.index)+"["+"a".repeat(match[0].length-2)+"]"+maskedSrc.slice(this.tokenizer.rules.inline.reflinkSearch.lastIndex))}for(;null!=(match=this.tokenizer.rules.inline.blockSkip.exec(maskedSrc));)maskedSrc=maskedSrc.slice(0,match.index)+"["+"a".repeat(match[0].length-2)+"]"+maskedSrc.slice(this.tokenizer.rules.inline.blockSkip.lastIndex);for(;null!=(match=this.tokenizer.rules.inline.anyPunctuation.exec(maskedSrc));)maskedSrc=maskedSrc.slice(0,match.index)+"++"+maskedSrc.slice(this.tokenizer.rules.inline.anyPunctuation.lastIndex);for(;src;)if(keepPrevChar||(prevChar=""),keepPrevChar=!1,!(this.options.extensions&&this.options.extensions.inline&&this.options.extensions.inline.some((extTokenizer=>!!(token=extTokenizer.call({lexer:this},src,tokens))&&(src=src.substring(token.raw.length),tokens.push(token),!0)))))if(token=this.tokenizer.escape(src))src=src.substring(token.raw.length),tokens.push(token);else if(token=this.tokenizer.tag(src))src=src.substring(token.raw.length),lastToken=tokens[tokens.length-1],lastToken&&"text"===token.type&&"text"===lastToken.type?(lastToken.raw+=token.raw,lastToken.text+=token.text):tokens.push(token);else if(token=this.tokenizer.link(src))src=src.substring(token.raw.length),tokens.push(token);else if(token=this.tokenizer.reflink(src,this.tokens.links))src=src.substring(token.raw.length),lastToken=tokens[tokens.length-1],lastToken&&"text"===token.type&&"text"===lastToken.type?(lastToken.raw+=token.raw,lastToken.text+=token.text):tokens.push(token);else if(token=this.tokenizer.emStrong(src,maskedSrc,prevChar))src=src.substring(token.raw.length),tokens.push(token);else if(token=this.tokenizer.codespan(src))src=src.substring(token.raw.length),tokens.push(token);else if(token=this.tokenizer.br(src))src=src.substring(token.raw.length),tokens.push(token);else if(token=this.tokenizer.del(src))src=src.substring(token.raw.length),tokens.push(token);else if(token=this.tokenizer.autolink(src))src=src.substring(token.raw.length),tokens.push(token);else if(this.state.inLink||!(token=this.tokenizer.url(src))){if(cutSrc=src,this.options.extensions&&this.options.extensions.startInline){let startIndex=1/0;const tempSrc=src.slice(1);let tempStart;this.options.extensions.startInline.forEach((getStartIndex=>{tempStart=getStartIndex.call({lexer:this},tempSrc),"number"==typeof tempStart&&tempStart>=0&&(startIndex=Math.min(startIndex,tempStart))})),startIndex<1/0&&startIndex>=0&&(cutSrc=src.substring(0,startIndex+1))}if(token=this.tokenizer.inlineText(cutSrc))src=src.substring(token.raw.length),"_"!==token.raw.slice(-1)&&(prevChar=token.raw.slice(-1)),keepPrevChar=!0,lastToken=tokens[tokens.length-1],lastToken&&"text"===lastToken.type?(lastToken.raw+=token.raw,lastToken.text+=token.text):tokens.push(token);else if(src){const errMsg="Infinite loop on byte: "+src.charCodeAt(0);if(this.options.silent){console.error(errMsg);break}throw new Error(errMsg)}}else src=src.substring(token.raw.length),tokens.push(token);return tokens}}_exports.Lexer=_Lexer;class _Renderer{options;constructor(options){this.options=options||_defaults}code(code,infostring,escaped){var _match;const lang=null===(_match=(infostring||"").match(/^\S*/))||void 0===_match?void 0:_match[0];return code=code.replace(/\n$/,"")+"\n",lang?'
'+(escaped?code:escape$1(code,!0))+"
\n":"
"+(escaped?code:escape$1(code,!0))+"
\n"}blockquote(quote){return`
\n${quote}
\n`}html(html,block){return html}heading(text,level,raw){return`${text}\n`}hr(){return"
\n"}list(body,ordered,start){const type=ordered?"ol":"ul";return"<"+type+(ordered&&1!==start?' start="'+start+'"':"")+">\n"+body+"\n"}listitem(text,task,checked){return`
  • ${text}
  • \n`}checkbox(checked){return"'}paragraph(text){return`

    ${text}

    \n`}table(header,body){return body&&(body=`${body}`),"\n\n"+header+"\n"+body+"
    \n"}tablerow(content){return`\n${content}\n`}tablecell(content,flags){const type=flags.header?"th":"td";return(flags.align?`<${type} align="${flags.align}">`:`<${type}>`)+content+`\n`}strong(text){return`${text}`}em(text){return`${text}`}codespan(text){return`${text}`}br(){return"
    "}del(text){return`${text}`}link(href,title,text){const cleanHref=cleanUrl(href);if(null===cleanHref)return text;let out='
    ",out}image(href,title,text){const cleanHref=cleanUrl(href);if(null===cleanHref)return text;let out=`${text}1&&void 0!==arguments[1])||arguments[1],out="";for(let i=0;i0&&"paragraph"===item.tokens[0].type?(item.tokens[0].text=checkbox+" "+item.tokens[0].text,item.tokens[0].tokens&&item.tokens[0].tokens.length>0&&"text"===item.tokens[0].tokens[0].type&&(item.tokens[0].tokens[0].text=checkbox+" "+item.tokens[0].tokens[0].text)):item.tokens.unshift({type:"text",text:checkbox+" "}):itemBody+=checkbox+" "}itemBody+=this.parse(item.tokens,loose),body+=this.renderer.listitem(itemBody,task,!!checked)}out+=this.renderer.list(body,ordered,start);continue}case"html":{const htmlToken=token;out+=this.renderer.html(htmlToken.text,htmlToken.block);continue}case"paragraph":{const paragraphToken=token;out+=this.renderer.paragraph(this.parseInline(paragraphToken.tokens));continue}case"text":{let textToken=token,body=textToken.tokens?this.parseInline(textToken.tokens):textToken.text;for(;i+1{const tokens=genericToken[childTokens].flat(1/0);values=values.concat(this.walkTokens(tokens,callback))})):genericToken.tokens&&(values=values.concat(this.walkTokens(genericToken.tokens,callback)))}}return values}use(){const extensions=this.defaults.extensions||{renderers:{},childTokens:{}};for(var _len=arguments.length,args=new Array(_len),_key=0;_key<_len;_key++)args[_key]=arguments[_key];return args.forEach((pack=>{const opts={...pack};if(opts.async=this.defaults.async||opts.async||!1,pack.extensions&&(pack.extensions.forEach((ext=>{if(!ext.name)throw new Error("extension name required");if("renderer"in ext){const prevRenderer=extensions.renderers[ext.name];extensions.renderers[ext.name]=prevRenderer?function(){for(var _len2=arguments.length,args=new Array(_len2),_key2=0;_key2<_len2;_key2++)args[_key2]=arguments[_key2];let ret=ext.renderer.apply(this,args);return!1===ret&&(ret=prevRenderer.apply(this,args)),ret}:ext.renderer}if("tokenizer"in ext){if(!ext.level||"block"!==ext.level&&"inline"!==ext.level)throw new Error("extension level must be 'block' or 'inline'");const extLevel=extensions[ext.level];extLevel?extLevel.unshift(ext.tokenizer):extensions[ext.level]=[ext.tokenizer],ext.start&&("block"===ext.level?extensions.startBlock?extensions.startBlock.push(ext.start):extensions.startBlock=[ext.start]:"inline"===ext.level&&(extensions.startInline?extensions.startInline.push(ext.start):extensions.startInline=[ext.start]))}"childTokens"in ext&&ext.childTokens&&(extensions.childTokens[ext.name]=ext.childTokens)})),opts.extensions=extensions),pack.renderer){const renderer=this.defaults.renderer||new _Renderer(this.defaults);for(const prop in pack.renderer){if(!(prop in renderer))throw new Error(`renderer '${prop}' does not exist`);if("options"===prop)continue;const rendererProp=prop,rendererFunc=pack.renderer[rendererProp],prevRenderer=renderer[rendererProp];renderer[rendererProp]=function(){for(var _len3=arguments.length,args=new Array(_len3),_key3=0;_key3<_len3;_key3++)args[_key3]=arguments[_key3];let ret=rendererFunc.apply(renderer,args);return!1===ret&&(ret=prevRenderer.apply(renderer,args)),ret||""}}opts.renderer=renderer}if(pack.tokenizer){const tokenizer=this.defaults.tokenizer||new _Tokenizer(this.defaults);for(const prop in pack.tokenizer){if(!(prop in tokenizer))throw new Error(`tokenizer '${prop}' does not exist`);if(["options","rules","lexer"].includes(prop))continue;const tokenizerProp=prop,tokenizerFunc=pack.tokenizer[tokenizerProp],prevTokenizer=tokenizer[tokenizerProp];tokenizer[tokenizerProp]=function(){for(var _len4=arguments.length,args=new Array(_len4),_key4=0;_key4<_len4;_key4++)args[_key4]=arguments[_key4];let ret=tokenizerFunc.apply(tokenizer,args);return!1===ret&&(ret=prevTokenizer.apply(tokenizer,args)),ret}}opts.tokenizer=tokenizer}if(pack.hooks){const hooks=this.defaults.hooks||new _Hooks;for(const prop in pack.hooks){if(!(prop in hooks))throw new Error(`hook '${prop}' does not exist`);if("options"===prop)continue;const hooksProp=prop,hooksFunc=pack.hooks[hooksProp],prevHook=hooks[hooksProp];_Hooks.passThroughHooks.has(prop)?hooks[hooksProp]=arg=>{if(this.defaults.async)return Promise.resolve(hooksFunc.call(hooks,arg)).then((ret=>prevHook.call(hooks,ret)));const ret=hooksFunc.call(hooks,arg);return prevHook.call(hooks,ret)}:hooks[hooksProp]=function(){for(var _len5=arguments.length,args=new Array(_len5),_key5=0;_key5<_len5;_key5++)args[_key5]=arguments[_key5];let ret=hooksFunc.apply(hooks,args);return!1===ret&&(ret=prevHook.apply(hooks,args)),ret}}opts.hooks=hooks}if(pack.walkTokens){const walkTokens=this.defaults.walkTokens,packWalktokens=pack.walkTokens;opts.walkTokens=function(token){let values=[];return values.push(packWalktokens.call(this,token)),walkTokens&&(values=values.concat(walkTokens.call(this,token))),values}}this.defaults={...this.defaults,...opts}})),this}setOptions(opt){return this.defaults={...this.defaults,...opt},this}lexer(src,options){return _Lexer.lex(src,options??this.defaults)}parser(tokens,options){return _Parser.parse(tokens,options??this.defaults)}#parseMarkdown(lexer,parser){return(src,options)=>{const origOpt={...options},opt={...this.defaults,...origOpt};!0===this.defaults.async&&!1===origOpt.async&&(opt.silent||console.warn("marked(): The async option was set to true by an extension. The async: false option sent to parse will be ignored."),opt.async=!0);const throwError=this.#onError(!!opt.silent,!!opt.async);if(null==src)return throwError(new Error("marked(): input parameter is undefined or null"));if("string"!=typeof src)return throwError(new Error("marked(): input parameter is of type "+Object.prototype.toString.call(src)+", string expected"));if(opt.hooks&&(opt.hooks.options=opt),opt.async)return Promise.resolve(opt.hooks?opt.hooks.preprocess(src):src).then((src=>lexer(src,opt))).then((tokens=>opt.hooks?opt.hooks.processAllTokens(tokens):tokens)).then((tokens=>opt.walkTokens?Promise.all(this.walkTokens(tokens,opt.walkTokens)).then((()=>tokens)):tokens)).then((tokens=>parser(tokens,opt))).then((html=>opt.hooks?opt.hooks.postprocess(html):html)).catch(throwError);try{opt.hooks&&(src=opt.hooks.preprocess(src));let tokens=lexer(src,opt);opt.hooks&&(tokens=opt.hooks.processAllTokens(tokens)),opt.walkTokens&&this.walkTokens(tokens,opt.walkTokens);let html=parser(tokens,opt);return opt.hooks&&(html=opt.hooks.postprocess(html)),html}catch(e){return throwError(e)}}}#onError(silent,async){return e=>{if(e.message+="\nPlease report this to https://github.com/markedjs/marked.",silent){const msg="

    An error occurred:

    "+escape$1(e.message+"",!0)+"
    ";return async?Promise.resolve(msg):msg}if(async)return Promise.reject(e);throw e}}}_exports.Marked=Marked;const markedInstance=new Marked;function marked(src,opt){return markedInstance.parse(src,opt)}marked.options=marked.setOptions=function(options){return markedInstance.setOptions(options),marked.defaults=markedInstance.defaults,changeDefaults(marked.defaults),marked},marked.getDefaults=_getDefaults,marked.defaults=_defaults,marked.use=function(){return markedInstance.use(...arguments),marked.defaults=markedInstance.defaults,changeDefaults(marked.defaults),marked},marked.walkTokens=function(tokens,callback){return markedInstance.walkTokens(tokens,callback)},marked.parseInline=markedInstance.parseInline,marked.Parser=_Parser,marked.parser=_Parser.parse,marked.Renderer=_Renderer,marked.TextRenderer=_TextRenderer,marked.Lexer=_Lexer,marked.lexer=_Lexer.lex,marked.Tokenizer=_Tokenizer,marked.Hooks=_Hooks,marked.parse=marked;const options=marked.options;_exports.options=options;const setOptions=marked.setOptions;_exports.setOptions=setOptions;const use=marked.use;_exports.use=use;const walkTokens=marked.walkTokens;_exports.walkTokens=walkTokens;const parseInline=marked.parseInline;_exports.parseInline=parseInline;const parse=marked;_exports.parse=parse;const parser=_Parser.parse;_exports.parser=parser;const lexer=_Lexer.lex;_exports.lexer=lexer})); - -//# sourceMappingURL=marked.esm.min.js.map \ No newline at end of file diff --git a/amd/build/marked.esm.min.js.map b/amd/build/marked.esm.min.js.map deleted file mode 100644 index a3891a8..0000000 --- a/amd/build/marked.esm.min.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"marked.esm.min.js","sources":["../src/marked.esm.js"],"sourcesContent":["/**\n * marked v12.0.2 - a markdown parser\n * Copyright (c) 2011-2024, Christopher Jeffrey. (MIT Licensed)\n * https://github.com/markedjs/marked\n */\n\n/**\n * DO NOT EDIT THIS FILE\n * The code in this file is generated from files in ./src/\n */\n\n/**\n * Gets the original marked default options.\n */\nfunction _getDefaults() {\n return {\n async: false,\n breaks: false,\n extensions: null,\n gfm: true,\n hooks: null,\n pedantic: false,\n renderer: null,\n silent: false,\n tokenizer: null,\n walkTokens: null\n };\n}\nlet _defaults = _getDefaults();\nfunction changeDefaults(newDefaults) {\n _defaults = newDefaults;\n}\n\n/**\n * Helpers\n */\nconst escapeTest = /[&<>\"']/;\nconst escapeReplace = new RegExp(escapeTest.source, 'g');\nconst escapeTestNoEncode = /[<>\"']|&(?!(#\\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\\w+);)/;\nconst escapeReplaceNoEncode = new RegExp(escapeTestNoEncode.source, 'g');\nconst escapeReplacements = {\n '&': '&',\n '<': '<',\n '>': '>',\n '\"': '"',\n \"'\": '''\n};\nconst getEscapeReplacement = (ch) => escapeReplacements[ch];\nfunction escape$1(html, encode) {\n if (encode) {\n if (escapeTest.test(html)) {\n return html.replace(escapeReplace, getEscapeReplacement);\n }\n }\n else {\n if (escapeTestNoEncode.test(html)) {\n return html.replace(escapeReplaceNoEncode, getEscapeReplacement);\n }\n }\n return html;\n}\nconst unescapeTest = /&(#(?:\\d+)|(?:#x[0-9A-Fa-f]+)|(?:\\w+));?/ig;\nfunction unescape(html) {\n // explicitly match decimal, hex, and named HTML entities\n return html.replace(unescapeTest, (_, n) => {\n n = n.toLowerCase();\n if (n === 'colon')\n return ':';\n if (n.charAt(0) === '#') {\n return n.charAt(1) === 'x'\n ? String.fromCharCode(parseInt(n.substring(2), 16))\n : String.fromCharCode(+n.substring(1));\n }\n return '';\n });\n}\nconst caret = /(^|[^\\[])\\^/g;\nfunction edit(regex, opt) {\n let source = typeof regex === 'string' ? regex : regex.source;\n opt = opt || '';\n const obj = {\n replace: (name, val) => {\n let valSource = typeof val === 'string' ? val : val.source;\n valSource = valSource.replace(caret, '$1');\n source = source.replace(name, valSource);\n return obj;\n },\n getRegex: () => {\n return new RegExp(source, opt);\n }\n };\n return obj;\n}\nfunction cleanUrl(href) {\n try {\n href = encodeURI(href).replace(/%25/g, '%');\n }\n catch (e) {\n return null;\n }\n return href;\n}\nconst noopTest = { exec: () => null };\nfunction splitCells(tableRow, count) {\n // ensure that every cell-delimiting pipe has a space\n // before it to distinguish it from an escaped pipe\n const row = tableRow.replace(/\\|/g, (match, offset, str) => {\n let escaped = false;\n let curr = offset;\n while (--curr >= 0 && str[curr] === '\\\\')\n escaped = !escaped;\n if (escaped) {\n // odd number of slashes means | is escaped\n // so we leave it alone\n return '|';\n }\n else {\n // add space before unescaped |\n return ' |';\n }\n }), cells = row.split(/ \\|/);\n let i = 0;\n // First/last cell in a row cannot be empty if it has no leading/trailing pipe\n if (!cells[0].trim()) {\n cells.shift();\n }\n if (cells.length > 0 && !cells[cells.length - 1].trim()) {\n cells.pop();\n }\n if (count) {\n if (cells.length > count) {\n cells.splice(count);\n }\n else {\n while (cells.length < count)\n cells.push('');\n }\n }\n for (; i < cells.length; i++) {\n // leading or trailing whitespace is ignored per the gfm spec\n cells[i] = cells[i].trim().replace(/\\\\\\|/g, '|');\n }\n return cells;\n}\n/**\n * Remove trailing 'c's. Equivalent to str.replace(/c*$/, '').\n * /c*$/ is vulnerable to REDOS.\n *\n * @param str\n * @param c\n * @param invert Remove suffix of non-c chars instead. Default falsey.\n */\nfunction rtrim(str, c, invert) {\n const l = str.length;\n if (l === 0) {\n return '';\n }\n // Length of suffix matching the invert condition.\n let suffLen = 0;\n // Step left until we fail to match the invert condition.\n while (suffLen < l) {\n const currChar = str.charAt(l - suffLen - 1);\n if (currChar === c && !invert) {\n suffLen++;\n }\n else if (currChar !== c && invert) {\n suffLen++;\n }\n else {\n break;\n }\n }\n return str.slice(0, l - suffLen);\n}\nfunction findClosingBracket(str, b) {\n if (str.indexOf(b[1]) === -1) {\n return -1;\n }\n let level = 0;\n for (let i = 0; i < str.length; i++) {\n if (str[i] === '\\\\') {\n i++;\n }\n else if (str[i] === b[0]) {\n level++;\n }\n else if (str[i] === b[1]) {\n level--;\n if (level < 0) {\n return i;\n }\n }\n }\n return -1;\n}\n\nfunction outputLink(cap, link, raw, lexer) {\n const href = link.href;\n const title = link.title ? escape$1(link.title) : null;\n const text = cap[1].replace(/\\\\([\\[\\]])/g, '$1');\n if (cap[0].charAt(0) !== '!') {\n lexer.state.inLink = true;\n const token = {\n type: 'link',\n raw,\n href,\n title,\n text,\n tokens: lexer.inlineTokens(text)\n };\n lexer.state.inLink = false;\n return token;\n }\n return {\n type: 'image',\n raw,\n href,\n title,\n text: escape$1(text)\n };\n}\nfunction indentCodeCompensation(raw, text) {\n const matchIndentToCode = raw.match(/^(\\s+)(?:```)/);\n if (matchIndentToCode === null) {\n return text;\n }\n const indentToCode = matchIndentToCode[1];\n return text\n .split('\\n')\n .map(node => {\n const matchIndentInNode = node.match(/^\\s+/);\n if (matchIndentInNode === null) {\n return node;\n }\n const [indentInNode] = matchIndentInNode;\n if (indentInNode.length >= indentToCode.length) {\n return node.slice(indentToCode.length);\n }\n return node;\n })\n .join('\\n');\n}\n/**\n * Tokenizer\n */\nclass _Tokenizer {\n options;\n rules; // set by the lexer\n lexer; // set by the lexer\n constructor(options) {\n this.options = options || _defaults;\n }\n space(src) {\n const cap = this.rules.block.newline.exec(src);\n if (cap && cap[0].length > 0) {\n return {\n type: 'space',\n raw: cap[0]\n };\n }\n }\n code(src) {\n const cap = this.rules.block.code.exec(src);\n if (cap) {\n const text = cap[0].replace(/^ {1,4}/gm, '');\n return {\n type: 'code',\n raw: cap[0],\n codeBlockStyle: 'indented',\n text: !this.options.pedantic\n ? rtrim(text, '\\n')\n : text\n };\n }\n }\n fences(src) {\n const cap = this.rules.block.fences.exec(src);\n if (cap) {\n const raw = cap[0];\n const text = indentCodeCompensation(raw, cap[3] || '');\n return {\n type: 'code',\n raw,\n lang: cap[2] ? cap[2].trim().replace(this.rules.inline.anyPunctuation, '$1') : cap[2],\n text\n };\n }\n }\n heading(src) {\n const cap = this.rules.block.heading.exec(src);\n if (cap) {\n let text = cap[2].trim();\n // remove trailing #s\n if (/#$/.test(text)) {\n const trimmed = rtrim(text, '#');\n if (this.options.pedantic) {\n text = trimmed.trim();\n }\n else if (!trimmed || / $/.test(trimmed)) {\n // CommonMark requires space before trailing #s\n text = trimmed.trim();\n }\n }\n return {\n type: 'heading',\n raw: cap[0],\n depth: cap[1].length,\n text,\n tokens: this.lexer.inline(text)\n };\n }\n }\n hr(src) {\n const cap = this.rules.block.hr.exec(src);\n if (cap) {\n return {\n type: 'hr',\n raw: cap[0]\n };\n }\n }\n blockquote(src) {\n const cap = this.rules.block.blockquote.exec(src);\n if (cap) {\n // precede setext continuation with 4 spaces so it isn't a setext\n let text = cap[0].replace(/\\n {0,3}((?:=+|-+) *)(?=\\n|$)/g, '\\n $1');\n text = rtrim(text.replace(/^ *>[ \\t]?/gm, ''), '\\n');\n const top = this.lexer.state.top;\n this.lexer.state.top = true;\n const tokens = this.lexer.blockTokens(text);\n this.lexer.state.top = top;\n return {\n type: 'blockquote',\n raw: cap[0],\n tokens,\n text\n };\n }\n }\n list(src) {\n let cap = this.rules.block.list.exec(src);\n if (cap) {\n let bull = cap[1].trim();\n const isordered = bull.length > 1;\n const list = {\n type: 'list',\n raw: '',\n ordered: isordered,\n start: isordered ? +bull.slice(0, -1) : '',\n loose: false,\n items: []\n };\n bull = isordered ? `\\\\d{1,9}\\\\${bull.slice(-1)}` : `\\\\${bull}`;\n if (this.options.pedantic) {\n bull = isordered ? bull : '[*+-]';\n }\n // Get next list item\n const itemRegex = new RegExp(`^( {0,3}${bull})((?:[\\t ][^\\\\n]*)?(?:\\\\n|$))`);\n let raw = '';\n let itemContents = '';\n let endsWithBlankLine = false;\n // Check if current bullet point can start a new List Item\n while (src) {\n let endEarly = false;\n if (!(cap = itemRegex.exec(src))) {\n break;\n }\n if (this.rules.block.hr.test(src)) { // End list if bullet was actually HR (possibly move into itemRegex?)\n break;\n }\n raw = cap[0];\n src = src.substring(raw.length);\n let line = cap[2].split('\\n', 1)[0].replace(/^\\t+/, (t) => ' '.repeat(3 * t.length));\n let nextLine = src.split('\\n', 1)[0];\n let indent = 0;\n if (this.options.pedantic) {\n indent = 2;\n itemContents = line.trimStart();\n }\n else {\n indent = cap[2].search(/[^ ]/); // Find first non-space char\n indent = indent > 4 ? 1 : indent; // Treat indented code blocks (> 4 spaces) as having only 1 indent\n itemContents = line.slice(indent);\n indent += cap[1].length;\n }\n let blankLine = false;\n if (!line && /^ *$/.test(nextLine)) { // Items begin with at most one blank line\n raw += nextLine + '\\n';\n src = src.substring(nextLine.length + 1);\n endEarly = true;\n }\n if (!endEarly) {\n const nextBulletRegex = new RegExp(`^ {0,${Math.min(3, indent - 1)}}(?:[*+-]|\\\\d{1,9}[.)])((?:[ \\t][^\\\\n]*)?(?:\\\\n|$))`);\n const hrRegex = new RegExp(`^ {0,${Math.min(3, indent - 1)}}((?:- *){3,}|(?:_ *){3,}|(?:\\\\* *){3,})(?:\\\\n+|$)`);\n const fencesBeginRegex = new RegExp(`^ {0,${Math.min(3, indent - 1)}}(?:\\`\\`\\`|~~~)`);\n const headingBeginRegex = new RegExp(`^ {0,${Math.min(3, indent - 1)}}#`);\n // Check if following lines should be included in List Item\n while (src) {\n const rawLine = src.split('\\n', 1)[0];\n nextLine = rawLine;\n // Re-align to follow commonmark nesting rules\n if (this.options.pedantic) {\n nextLine = nextLine.replace(/^ {1,4}(?=( {4})*[^ ])/g, ' ');\n }\n // End list item if found code fences\n if (fencesBeginRegex.test(nextLine)) {\n break;\n }\n // End list item if found start of new heading\n if (headingBeginRegex.test(nextLine)) {\n break;\n }\n // End list item if found start of new bullet\n if (nextBulletRegex.test(nextLine)) {\n break;\n }\n // Horizontal rule found\n if (hrRegex.test(src)) {\n break;\n }\n if (nextLine.search(/[^ ]/) >= indent || !nextLine.trim()) { // Dedent if possible\n itemContents += '\\n' + nextLine.slice(indent);\n }\n else {\n // not enough indentation\n if (blankLine) {\n break;\n }\n // paragraph continuation unless last line was a different block level element\n if (line.search(/[^ ]/) >= 4) { // indented code block\n break;\n }\n if (fencesBeginRegex.test(line)) {\n break;\n }\n if (headingBeginRegex.test(line)) {\n break;\n }\n if (hrRegex.test(line)) {\n break;\n }\n itemContents += '\\n' + nextLine;\n }\n if (!blankLine && !nextLine.trim()) { // Check if current line is blank\n blankLine = true;\n }\n raw += rawLine + '\\n';\n src = src.substring(rawLine.length + 1);\n line = nextLine.slice(indent);\n }\n }\n if (!list.loose) {\n // If the previous item ended with a blank line, the list is loose\n if (endsWithBlankLine) {\n list.loose = true;\n }\n else if (/\\n *\\n *$/.test(raw)) {\n endsWithBlankLine = true;\n }\n }\n let istask = null;\n let ischecked;\n // Check for task list items\n if (this.options.gfm) {\n istask = /^\\[[ xX]\\] /.exec(itemContents);\n if (istask) {\n ischecked = istask[0] !== '[ ] ';\n itemContents = itemContents.replace(/^\\[[ xX]\\] +/, '');\n }\n }\n list.items.push({\n type: 'list_item',\n raw,\n task: !!istask,\n checked: ischecked,\n loose: false,\n text: itemContents,\n tokens: []\n });\n list.raw += raw;\n }\n // Do not consume newlines at end of final item. Alternatively, make itemRegex *start* with any newlines to simplify/speed up endsWithBlankLine logic\n list.items[list.items.length - 1].raw = raw.trimEnd();\n (list.items[list.items.length - 1]).text = itemContents.trimEnd();\n list.raw = list.raw.trimEnd();\n // Item child tokens handled here at end because we needed to have the final item to trim it first\n for (let i = 0; i < list.items.length; i++) {\n this.lexer.state.top = false;\n list.items[i].tokens = this.lexer.blockTokens(list.items[i].text, []);\n if (!list.loose) {\n // Check if list should be loose\n const spacers = list.items[i].tokens.filter(t => t.type === 'space');\n const hasMultipleLineBreaks = spacers.length > 0 && spacers.some(t => /\\n.*\\n/.test(t.raw));\n list.loose = hasMultipleLineBreaks;\n }\n }\n // Set all items to loose if list is loose\n if (list.loose) {\n for (let i = 0; i < list.items.length; i++) {\n list.items[i].loose = true;\n }\n }\n return list;\n }\n }\n html(src) {\n const cap = this.rules.block.html.exec(src);\n if (cap) {\n const token = {\n type: 'html',\n block: true,\n raw: cap[0],\n pre: cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style',\n text: cap[0]\n };\n return token;\n }\n }\n def(src) {\n const cap = this.rules.block.def.exec(src);\n if (cap) {\n const tag = cap[1].toLowerCase().replace(/\\s+/g, ' ');\n const href = cap[2] ? cap[2].replace(/^<(.*)>$/, '$1').replace(this.rules.inline.anyPunctuation, '$1') : '';\n const title = cap[3] ? cap[3].substring(1, cap[3].length - 1).replace(this.rules.inline.anyPunctuation, '$1') : cap[3];\n return {\n type: 'def',\n tag,\n raw: cap[0],\n href,\n title\n };\n }\n }\n table(src) {\n const cap = this.rules.block.table.exec(src);\n if (!cap) {\n return;\n }\n if (!/[:|]/.test(cap[2])) {\n // delimiter row must have a pipe (|) or colon (:) otherwise it is a setext heading\n return;\n }\n const headers = splitCells(cap[1]);\n const aligns = cap[2].replace(/^\\||\\| *$/g, '').split('|');\n const rows = cap[3] && cap[3].trim() ? cap[3].replace(/\\n[ \\t]*$/, '').split('\\n') : [];\n const item = {\n type: 'table',\n raw: cap[0],\n header: [],\n align: [],\n rows: []\n };\n if (headers.length !== aligns.length) {\n // header and align columns must be equal, rows can be different.\n return;\n }\n for (const align of aligns) {\n if (/^ *-+: *$/.test(align)) {\n item.align.push('right');\n }\n else if (/^ *:-+: *$/.test(align)) {\n item.align.push('center');\n }\n else if (/^ *:-+ *$/.test(align)) {\n item.align.push('left');\n }\n else {\n item.align.push(null);\n }\n }\n for (const header of headers) {\n item.header.push({\n text: header,\n tokens: this.lexer.inline(header)\n });\n }\n for (const row of rows) {\n item.rows.push(splitCells(row, item.header.length).map(cell => {\n return {\n text: cell,\n tokens: this.lexer.inline(cell)\n };\n }));\n }\n return item;\n }\n lheading(src) {\n const cap = this.rules.block.lheading.exec(src);\n if (cap) {\n return {\n type: 'heading',\n raw: cap[0],\n depth: cap[2].charAt(0) === '=' ? 1 : 2,\n text: cap[1],\n tokens: this.lexer.inline(cap[1])\n };\n }\n }\n paragraph(src) {\n const cap = this.rules.block.paragraph.exec(src);\n if (cap) {\n const text = cap[1].charAt(cap[1].length - 1) === '\\n'\n ? cap[1].slice(0, -1)\n : cap[1];\n return {\n type: 'paragraph',\n raw: cap[0],\n text,\n tokens: this.lexer.inline(text)\n };\n }\n }\n text(src) {\n const cap = this.rules.block.text.exec(src);\n if (cap) {\n return {\n type: 'text',\n raw: cap[0],\n text: cap[0],\n tokens: this.lexer.inline(cap[0])\n };\n }\n }\n escape(src) {\n const cap = this.rules.inline.escape.exec(src);\n if (cap) {\n return {\n type: 'escape',\n raw: cap[0],\n text: escape$1(cap[1])\n };\n }\n }\n tag(src) {\n const cap = this.rules.inline.tag.exec(src);\n if (cap) {\n if (!this.lexer.state.inLink && /^
    /i.test(cap[0])) {\n this.lexer.state.inLink = false;\n }\n if (!this.lexer.state.inRawBlock && /^<(pre|code|kbd|script)(\\s|>)/i.test(cap[0])) {\n this.lexer.state.inRawBlock = true;\n }\n else if (this.lexer.state.inRawBlock && /^<\\/(pre|code|kbd|script)(\\s|>)/i.test(cap[0])) {\n this.lexer.state.inRawBlock = false;\n }\n return {\n type: 'html',\n raw: cap[0],\n inLink: this.lexer.state.inLink,\n inRawBlock: this.lexer.state.inRawBlock,\n block: false,\n text: cap[0]\n };\n }\n }\n link(src) {\n const cap = this.rules.inline.link.exec(src);\n if (cap) {\n const trimmedUrl = cap[2].trim();\n if (!this.options.pedantic && /^$/.test(trimmedUrl))) {\n return;\n }\n // ending angle bracket cannot be escaped\n const rtrimSlash = rtrim(trimmedUrl.slice(0, -1), '\\\\');\n if ((trimmedUrl.length - rtrimSlash.length) % 2 === 0) {\n return;\n }\n }\n else {\n // find closing parenthesis\n const lastParenIndex = findClosingBracket(cap[2], '()');\n if (lastParenIndex > -1) {\n const start = cap[0].indexOf('!') === 0 ? 5 : 4;\n const linkLen = start + cap[1].length + lastParenIndex;\n cap[2] = cap[2].substring(0, lastParenIndex);\n cap[0] = cap[0].substring(0, linkLen).trim();\n cap[3] = '';\n }\n }\n let href = cap[2];\n let title = '';\n if (this.options.pedantic) {\n // split pedantic href and title\n const link = /^([^'\"]*[^\\s])\\s+(['\"])(.*)\\2/.exec(href);\n if (link) {\n href = link[1];\n title = link[3];\n }\n }\n else {\n title = cap[3] ? cap[3].slice(1, -1) : '';\n }\n href = href.trim();\n if (/^$/.test(trimmedUrl))) {\n // pedantic allows starting angle bracket without ending angle bracket\n href = href.slice(1);\n }\n else {\n href = href.slice(1, -1);\n }\n }\n return outputLink(cap, {\n href: href ? href.replace(this.rules.inline.anyPunctuation, '$1') : href,\n title: title ? title.replace(this.rules.inline.anyPunctuation, '$1') : title\n }, cap[0], this.lexer);\n }\n }\n reflink(src, links) {\n let cap;\n if ((cap = this.rules.inline.reflink.exec(src))\n || (cap = this.rules.inline.nolink.exec(src))) {\n const linkString = (cap[2] || cap[1]).replace(/\\s+/g, ' ');\n const link = links[linkString.toLowerCase()];\n if (!link) {\n const text = cap[0].charAt(0);\n return {\n type: 'text',\n raw: text,\n text\n };\n }\n return outputLink(cap, link, cap[0], this.lexer);\n }\n }\n emStrong(src, maskedSrc, prevChar = '') {\n let match = this.rules.inline.emStrongLDelim.exec(src);\n if (!match)\n return;\n // _ can't be between two alphanumerics. \\p{L}\\p{N} includes non-english alphabet/numbers as well\n if (match[3] && prevChar.match(/[\\p{L}\\p{N}]/u))\n return;\n const nextChar = match[1] || match[2] || '';\n if (!nextChar || !prevChar || this.rules.inline.punctuation.exec(prevChar)) {\n // unicode Regex counts emoji as 1 char; spread into array for proper count (used multiple times below)\n const lLength = [...match[0]].length - 1;\n let rDelim, rLength, delimTotal = lLength, midDelimTotal = 0;\n const endReg = match[0][0] === '*' ? this.rules.inline.emStrongRDelimAst : this.rules.inline.emStrongRDelimUnd;\n endReg.lastIndex = 0;\n // Clip maskedSrc to same section of string as src (move to lexer?)\n maskedSrc = maskedSrc.slice(-1 * src.length + lLength);\n while ((match = endReg.exec(maskedSrc)) != null) {\n rDelim = match[1] || match[2] || match[3] || match[4] || match[5] || match[6];\n if (!rDelim)\n continue; // skip single * in __abc*abc__\n rLength = [...rDelim].length;\n if (match[3] || match[4]) { // found another Left Delim\n delimTotal += rLength;\n continue;\n }\n else if (match[5] || match[6]) { // either Left or Right Delim\n if (lLength % 3 && !((lLength + rLength) % 3)) {\n midDelimTotal += rLength;\n continue; // CommonMark Emphasis Rules 9-10\n }\n }\n delimTotal -= rLength;\n if (delimTotal > 0)\n continue; // Haven't found enough closing delimiters\n // Remove extra characters. *a*** -> *a*\n rLength = Math.min(rLength, rLength + delimTotal + midDelimTotal);\n // char length can be >1 for unicode characters;\n const lastCharLength = [...match[0]][0].length;\n const raw = src.slice(0, lLength + match.index + lastCharLength + rLength);\n // Create `em` if smallest delimiter has odd char count. *a***\n if (Math.min(lLength, rLength) % 2) {\n const text = raw.slice(1, -1);\n return {\n type: 'em',\n raw,\n text,\n tokens: this.lexer.inlineTokens(text)\n };\n }\n // Create 'strong' if smallest delimiter has even char count. **a***\n const text = raw.slice(2, -2);\n return {\n type: 'strong',\n raw,\n text,\n tokens: this.lexer.inlineTokens(text)\n };\n }\n }\n }\n codespan(src) {\n const cap = this.rules.inline.code.exec(src);\n if (cap) {\n let text = cap[2].replace(/\\n/g, ' ');\n const hasNonSpaceChars = /[^ ]/.test(text);\n const hasSpaceCharsOnBothEnds = /^ /.test(text) && / $/.test(text);\n if (hasNonSpaceChars && hasSpaceCharsOnBothEnds) {\n text = text.substring(1, text.length - 1);\n }\n text = escape$1(text, true);\n return {\n type: 'codespan',\n raw: cap[0],\n text\n };\n }\n }\n br(src) {\n const cap = this.rules.inline.br.exec(src);\n if (cap) {\n return {\n type: 'br',\n raw: cap[0]\n };\n }\n }\n del(src) {\n const cap = this.rules.inline.del.exec(src);\n if (cap) {\n return {\n type: 'del',\n raw: cap[0],\n text: cap[2],\n tokens: this.lexer.inlineTokens(cap[2])\n };\n }\n }\n autolink(src) {\n const cap = this.rules.inline.autolink.exec(src);\n if (cap) {\n let text, href;\n if (cap[2] === '@') {\n text = escape$1(cap[1]);\n href = 'mailto:' + text;\n }\n else {\n text = escape$1(cap[1]);\n href = text;\n }\n return {\n type: 'link',\n raw: cap[0],\n text,\n href,\n tokens: [\n {\n type: 'text',\n raw: text,\n text\n }\n ]\n };\n }\n }\n url(src) {\n let cap;\n if (cap = this.rules.inline.url.exec(src)) {\n let text, href;\n if (cap[2] === '@') {\n text = escape$1(cap[0]);\n href = 'mailto:' + text;\n }\n else {\n // do extended autolink path validation\n let prevCapZero;\n do {\n prevCapZero = cap[0];\n cap[0] = this.rules.inline._backpedal.exec(cap[0])?.[0] ?? '';\n } while (prevCapZero !== cap[0]);\n text = escape$1(cap[0]);\n if (cap[1] === 'www.') {\n href = 'http://' + cap[0];\n }\n else {\n href = cap[0];\n }\n }\n return {\n type: 'link',\n raw: cap[0],\n text,\n href,\n tokens: [\n {\n type: 'text',\n raw: text,\n text\n }\n ]\n };\n }\n }\n inlineText(src) {\n const cap = this.rules.inline.text.exec(src);\n if (cap) {\n let text;\n if (this.lexer.state.inRawBlock) {\n text = cap[0];\n }\n else {\n text = escape$1(cap[0]);\n }\n return {\n type: 'text',\n raw: cap[0],\n text\n };\n }\n }\n}\n\n/**\n * Block-Level Grammar\n */\nconst newline = /^(?: *(?:\\n|$))+/;\nconst blockCode = /^( {4}[^\\n]+(?:\\n(?: *(?:\\n|$))*)?)+/;\nconst fences = /^ {0,3}(`{3,}(?=[^`\\n]*(?:\\n|$))|~{3,})([^\\n]*)(?:\\n|$)(?:|([\\s\\S]*?)(?:\\n|$))(?: {0,3}\\1[~`]* *(?=\\n|$)|$)/;\nconst hr = /^ {0,3}((?:-[\\t ]*){3,}|(?:_[ \\t]*){3,}|(?:\\*[ \\t]*){3,})(?:\\n+|$)/;\nconst heading = /^ {0,3}(#{1,6})(?=\\s|$)(.*)(?:\\n+|$)/;\nconst bullet = /(?:[*+-]|\\d{1,9}[.)])/;\nconst lheading = edit(/^(?!bull |blockCode|fences|blockquote|heading|html)((?:.|\\n(?!\\s*?\\n|bull |blockCode|fences|blockquote|heading|html))+?)\\n {0,3}(=+|-+) *(?:\\n+|$)/)\n .replace(/bull/g, bullet) // lists can interrupt\n .replace(/blockCode/g, / {4}/) // indented code blocks can interrupt\n .replace(/fences/g, / {0,3}(?:`{3,}|~{3,})/) // fenced code blocks can interrupt\n .replace(/blockquote/g, / {0,3}>/) // blockquote can interrupt\n .replace(/heading/g, / {0,3}#{1,6}/) // ATX heading can interrupt\n .replace(/html/g, / {0,3}<[^\\n>]+>\\n/) // block html can interrupt\n .getRegex();\nconst _paragraph = /^([^\\n]+(?:\\n(?!hr|heading|lheading|blockquote|fences|list|html|table| +\\n)[^\\n]+)*)/;\nconst blockText = /^[^\\n]+/;\nconst _blockLabel = /(?!\\s*\\])(?:\\\\.|[^\\[\\]\\\\])+/;\nconst def = edit(/^ {0,3}\\[(label)\\]: *(?:\\n *)?([^<\\s][^\\s]*|<.*?>)(?:(?: +(?:\\n *)?| *\\n *)(title))? *(?:\\n+|$)/)\n .replace('label', _blockLabel)\n .replace('title', /(?:\"(?:\\\\\"?|[^\"\\\\])*\"|'[^'\\n]*(?:\\n[^'\\n]+)*\\n?'|\\([^()]*\\))/)\n .getRegex();\nconst list = edit(/^( {0,3}bull)([ \\t][^\\n]+?)?(?:\\n|$)/)\n .replace(/bull/g, bullet)\n .getRegex();\nconst _tag = 'address|article|aside|base|basefont|blockquote|body|caption'\n + '|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption'\n + '|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe'\n + '|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option'\n + '|p|param|search|section|summary|table|tbody|td|tfoot|th|thead|title'\n + '|tr|track|ul';\nconst _comment = /|$))/;\nconst html = edit('^ {0,3}(?:' // optional indentation\n + '<(script|pre|style|textarea)[\\\\s>][\\\\s\\\\S]*?(?:[^\\\\n]*\\\\n+|$)' // (1)\n + '|comment[^\\\\n]*(\\\\n+|$)' // (2)\n + '|<\\\\?[\\\\s\\\\S]*?(?:\\\\?>\\\\n*|$)' // (3)\n + '|\\\\n*|$)' // (4)\n + '|\\\\n*|$)' // (5)\n + '|)[\\\\s\\\\S]*?(?:(?:\\\\n *)+\\\\n|$)' // (6)\n + '|<(?!script|pre|style|textarea)([a-z][\\\\w-]*)(?:attribute)*? */?>(?=[ \\\\t]*(?:\\\\n|$))[\\\\s\\\\S]*?(?:(?:\\\\n *)+\\\\n|$)' // (7) open tag\n + '|(?=[ \\\\t]*(?:\\\\n|$))[\\\\s\\\\S]*?(?:(?:\\\\n *)+\\\\n|$)' // (7) closing tag\n + ')', 'i')\n .replace('comment', _comment)\n .replace('tag', _tag)\n .replace('attribute', / +[a-zA-Z:_][\\w.:-]*(?: *= *\"[^\"\\n]*\"| *= *'[^'\\n]*'| *= *[^\\s\"'=<>`]+)?/)\n .getRegex();\nconst paragraph = edit(_paragraph)\n .replace('hr', hr)\n .replace('heading', ' {0,3}#{1,6}(?:\\\\s|$)')\n .replace('|lheading', '') // setext headings don't interrupt commonmark paragraphs\n .replace('|table', '')\n .replace('blockquote', ' {0,3}>')\n .replace('fences', ' {0,3}(?:`{3,}(?=[^`\\\\n]*\\\\n)|~{3,})[^\\\\n]*\\\\n')\n .replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt\n .replace('html', ')|<(?:script|pre|style|textarea|!--)')\n .replace('tag', _tag) // pars can be interrupted by type (6) html blocks\n .getRegex();\nconst blockquote = edit(/^( {0,3}> ?(paragraph|[^\\n]*)(?:\\n|$))+/)\n .replace('paragraph', paragraph)\n .getRegex();\n/**\n * Normal Block Grammar\n */\nconst blockNormal = {\n blockquote,\n code: blockCode,\n def,\n fences,\n heading,\n hr,\n html,\n lheading,\n list,\n newline,\n paragraph,\n table: noopTest,\n text: blockText\n};\n/**\n * GFM Block Grammar\n */\nconst gfmTable = edit('^ *([^\\\\n ].*)\\\\n' // Header\n + ' {0,3}((?:\\\\| *)?:?-+:? *(?:\\\\| *:?-+:? *)*(?:\\\\| *)?)' // Align\n + '(?:\\\\n((?:(?! *\\\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\\\n|$))*)\\\\n*|$)') // Cells\n .replace('hr', hr)\n .replace('heading', ' {0,3}#{1,6}(?:\\\\s|$)')\n .replace('blockquote', ' {0,3}>')\n .replace('code', ' {4}[^\\\\n]')\n .replace('fences', ' {0,3}(?:`{3,}(?=[^`\\\\n]*\\\\n)|~{3,})[^\\\\n]*\\\\n')\n .replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt\n .replace('html', ')|<(?:script|pre|style|textarea|!--)')\n .replace('tag', _tag) // tables can be interrupted by type (6) html blocks\n .getRegex();\nconst blockGfm = {\n ...blockNormal,\n table: gfmTable,\n paragraph: edit(_paragraph)\n .replace('hr', hr)\n .replace('heading', ' {0,3}#{1,6}(?:\\\\s|$)')\n .replace('|lheading', '') // setext headings don't interrupt commonmark paragraphs\n .replace('table', gfmTable) // interrupt paragraphs with table\n .replace('blockquote', ' {0,3}>')\n .replace('fences', ' {0,3}(?:`{3,}(?=[^`\\\\n]*\\\\n)|~{3,})[^\\\\n]*\\\\n')\n .replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt\n .replace('html', ')|<(?:script|pre|style|textarea|!--)')\n .replace('tag', _tag) // pars can be interrupted by type (6) html blocks\n .getRegex()\n};\n/**\n * Pedantic grammar (original John Gruber's loose markdown specification)\n */\nconst blockPedantic = {\n ...blockNormal,\n html: edit('^ *(?:comment *(?:\\\\n|\\\\s*$)'\n + '|<(tag)[\\\\s\\\\S]+? *(?:\\\\n{2,}|\\\\s*$)' // closed tag\n + '|\\\\s]*)*?/?> *(?:\\\\n{2,}|\\\\s*$))')\n .replace('comment', _comment)\n .replace(/tag/g, '(?!(?:'\n + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub'\n + '|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)'\n + '\\\\b)\\\\w+(?!:|[^\\\\w\\\\s@]*@)\\\\b')\n .getRegex(),\n def: /^ *\\[([^\\]]+)\\]: *]+)>?(?: +([\"(][^\\n]+[\")]))? *(?:\\n+|$)/,\n heading: /^(#{1,6})(.*)(?:\\n+|$)/,\n fences: noopTest, // fences not supported\n lheading: /^(.+?)\\n {0,3}(=+|-+) *(?:\\n+|$)/,\n paragraph: edit(_paragraph)\n .replace('hr', hr)\n .replace('heading', ' *#{1,6} *[^\\n]')\n .replace('lheading', lheading)\n .replace('|table', '')\n .replace('blockquote', ' {0,3}>')\n .replace('|fences', '')\n .replace('|list', '')\n .replace('|html', '')\n .replace('|tag', '')\n .getRegex()\n};\n/**\n * Inline-Level Grammar\n */\nconst escape = /^\\\\([!\"#$%&'()*+,\\-./:;<=>?@\\[\\]\\\\^_`{|}~])/;\nconst inlineCode = /^(`+)([^`]|[^`][\\s\\S]*?[^`])\\1(?!`)/;\nconst br = /^( {2,}|\\\\)\\n(?!\\s*$)/;\nconst inlineText = /^(`+|[^`])(?:(?= {2,}\\n)|[\\s\\S]*?(?:(?=[\\\\\nconst blockSkip = /\\[[^[\\]]*?\\]\\([^\\(\\)]*?\\)|`[^`]*?`|<[^<>]*?>/g;\nconst emStrongLDelim = edit(/^(?:\\*+(?:((?!\\*)[punct])|[^\\s*]))|^_+(?:((?!_)[punct])|([^\\s_]))/, 'u')\n .replace(/punct/g, _punctuation)\n .getRegex();\nconst emStrongRDelimAst = edit('^[^_*]*?__[^_*]*?\\\\*[^_*]*?(?=__)' // Skip orphan inside strong\n + '|[^*]+(?=[^*])' // Consume to delim\n + '|(?!\\\\*)[punct](\\\\*+)(?=[\\\\s]|$)' // (1) #*** can only be a Right Delimiter\n + '|[^punct\\\\s](\\\\*+)(?!\\\\*)(?=[punct\\\\s]|$)' // (2) a***#, a*** can only be a Right Delimiter\n + '|(?!\\\\*)[punct\\\\s](\\\\*+)(?=[^punct\\\\s])' // (3) #***a, ***a can only be Left Delimiter\n + '|[\\\\s](\\\\*+)(?!\\\\*)(?=[punct])' // (4) ***# can only be Left Delimiter\n + '|(?!\\\\*)[punct](\\\\*+)(?!\\\\*)(?=[punct])' // (5) #***# can be either Left or Right Delimiter\n + '|[^punct\\\\s](\\\\*+)(?=[^punct\\\\s])', 'gu') // (6) a***a can be either Left or Right Delimiter\n .replace(/punct/g, _punctuation)\n .getRegex();\n// (6) Not allowed for _\nconst emStrongRDelimUnd = edit('^[^_*]*?\\\\*\\\\*[^_*]*?_[^_*]*?(?=\\\\*\\\\*)' // Skip orphan inside strong\n + '|[^_]+(?=[^_])' // Consume to delim\n + '|(?!_)[punct](_+)(?=[\\\\s]|$)' // (1) #___ can only be a Right Delimiter\n + '|[^punct\\\\s](_+)(?!_)(?=[punct\\\\s]|$)' // (2) a___#, a___ can only be a Right Delimiter\n + '|(?!_)[punct\\\\s](_+)(?=[^punct\\\\s])' // (3) #___a, ___a can only be Left Delimiter\n + '|[\\\\s](_+)(?!_)(?=[punct])' // (4) ___# can only be Left Delimiter\n + '|(?!_)[punct](_+)(?!_)(?=[punct])', 'gu') // (5) #___# can be either Left or Right Delimiter\n .replace(/punct/g, _punctuation)\n .getRegex();\nconst anyPunctuation = edit(/\\\\([punct])/, 'gu')\n .replace(/punct/g, _punctuation)\n .getRegex();\nconst autolink = edit(/^<(scheme:[^\\s\\x00-\\x1f<>]*|email)>/)\n .replace('scheme', /[a-zA-Z][a-zA-Z0-9+.-]{1,31}/)\n .replace('email', /[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/)\n .getRegex();\nconst _inlineComment = edit(_comment).replace('(?:-->|$)', '-->').getRegex();\nconst tag = edit('^comment'\n + '|^' // self-closing tag\n + '|^<[a-zA-Z][\\\\w-]*(?:attribute)*?\\\\s*/?>' // open tag\n + '|^<\\\\?[\\\\s\\\\S]*?\\\\?>' // processing instruction, e.g. \n + '|^' // declaration, e.g. \n + '|^') // CDATA section\n .replace('comment', _inlineComment)\n .replace('attribute', /\\s+[a-zA-Z:_][\\w.:-]*(?:\\s*=\\s*\"[^\"]*\"|\\s*=\\s*'[^']*'|\\s*=\\s*[^\\s\"'=<>`]+)?/)\n .getRegex();\nconst _inlineLabel = /(?:\\[(?:\\\\.|[^\\[\\]\\\\])*\\]|\\\\.|`[^`]*`|[^\\[\\]\\\\`])*?/;\nconst link = edit(/^!?\\[(label)\\]\\(\\s*(href)(?:\\s+(title))?\\s*\\)/)\n .replace('label', _inlineLabel)\n .replace('href', /<(?:\\\\.|[^\\n<>\\\\])+>|[^\\s\\x00-\\x1f]*/)\n .replace('title', /\"(?:\\\\\"?|[^\"\\\\])*\"|'(?:\\\\'?|[^'\\\\])*'|\\((?:\\\\\\)?|[^)\\\\])*\\)/)\n .getRegex();\nconst reflink = edit(/^!?\\[(label)\\]\\[(ref)\\]/)\n .replace('label', _inlineLabel)\n .replace('ref', _blockLabel)\n .getRegex();\nconst nolink = edit(/^!?\\[(ref)\\](?:\\[\\])?/)\n .replace('ref', _blockLabel)\n .getRegex();\nconst reflinkSearch = edit('reflink|nolink(?!\\\\()', 'g')\n .replace('reflink', reflink)\n .replace('nolink', nolink)\n .getRegex();\n/**\n * Normal Inline Grammar\n */\nconst inlineNormal = {\n _backpedal: noopTest, // only used for GFM url\n anyPunctuation,\n autolink,\n blockSkip,\n br,\n code: inlineCode,\n del: noopTest,\n emStrongLDelim,\n emStrongRDelimAst,\n emStrongRDelimUnd,\n escape,\n link,\n nolink,\n punctuation,\n reflink,\n reflinkSearch,\n tag,\n text: inlineText,\n url: noopTest\n};\n/**\n * Pedantic Inline Grammar\n */\nconst inlinePedantic = {\n ...inlineNormal,\n link: edit(/^!?\\[(label)\\]\\((.*?)\\)/)\n .replace('label', _inlineLabel)\n .getRegex(),\n reflink: edit(/^!?\\[(label)\\]\\s*\\[([^\\]]*)\\]/)\n .replace('label', _inlineLabel)\n .getRegex()\n};\n/**\n * GFM Inline Grammar\n */\nconst inlineGfm = {\n ...inlineNormal,\n escape: edit(escape).replace('])', '~|])').getRegex(),\n url: edit(/^((?:ftp|https?):\\/\\/|www\\.)(?:[a-zA-Z0-9\\-]+\\.?)+[^\\s<]*|^email/, 'i')\n .replace('email', /[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/)\n .getRegex(),\n _backpedal: /(?:[^?!.,:;*_'\"~()&]+|\\([^)]*\\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_'\"~)]+(?!$))+/,\n del: /^(~~?)(?=[^\\s~])([\\s\\S]*?[^\\s~])\\1(?=[^~]|$)/,\n text: /^([`~]+|[^`~])(?:(?= {2,}\\n)|(?=[a-zA-Z0-9.!#$%&'*+\\/=?_`{\\|}~-]+@)|[\\s\\S]*?(?:(?=[\\\\ {\n return leading + ' '.repeat(tabs.length);\n });\n }\n let token;\n let lastToken;\n let cutSrc;\n let lastParagraphClipped;\n while (src) {\n if (this.options.extensions\n && this.options.extensions.block\n && this.options.extensions.block.some((extTokenizer) => {\n if (token = extTokenizer.call({ lexer: this }, src, tokens)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n return true;\n }\n return false;\n })) {\n continue;\n }\n // newline\n if (token = this.tokenizer.space(src)) {\n src = src.substring(token.raw.length);\n if (token.raw.length === 1 && tokens.length > 0) {\n // if there's a single \\n as a spacer, it's terminating the last line,\n // so move it there so that we don't get unnecessary paragraph tags\n tokens[tokens.length - 1].raw += '\\n';\n }\n else {\n tokens.push(token);\n }\n continue;\n }\n // code\n if (token = this.tokenizer.code(src)) {\n src = src.substring(token.raw.length);\n lastToken = tokens[tokens.length - 1];\n // An indented code block cannot interrupt a paragraph.\n if (lastToken && (lastToken.type === 'paragraph' || lastToken.type === 'text')) {\n lastToken.raw += '\\n' + token.raw;\n lastToken.text += '\\n' + token.text;\n this.inlineQueue[this.inlineQueue.length - 1].src = lastToken.text;\n }\n else {\n tokens.push(token);\n }\n continue;\n }\n // fences\n if (token = this.tokenizer.fences(src)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n }\n // heading\n if (token = this.tokenizer.heading(src)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n }\n // hr\n if (token = this.tokenizer.hr(src)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n }\n // blockquote\n if (token = this.tokenizer.blockquote(src)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n }\n // list\n if (token = this.tokenizer.list(src)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n }\n // html\n if (token = this.tokenizer.html(src)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n }\n // def\n if (token = this.tokenizer.def(src)) {\n src = src.substring(token.raw.length);\n lastToken = tokens[tokens.length - 1];\n if (lastToken && (lastToken.type === 'paragraph' || lastToken.type === 'text')) {\n lastToken.raw += '\\n' + token.raw;\n lastToken.text += '\\n' + token.raw;\n this.inlineQueue[this.inlineQueue.length - 1].src = lastToken.text;\n }\n else if (!this.tokens.links[token.tag]) {\n this.tokens.links[token.tag] = {\n href: token.href,\n title: token.title\n };\n }\n continue;\n }\n // table (gfm)\n if (token = this.tokenizer.table(src)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n }\n // lheading\n if (token = this.tokenizer.lheading(src)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n }\n // top-level paragraph\n // prevent paragraph consuming extensions by clipping 'src' to extension start\n cutSrc = src;\n if (this.options.extensions && this.options.extensions.startBlock) {\n let startIndex = Infinity;\n const tempSrc = src.slice(1);\n let tempStart;\n this.options.extensions.startBlock.forEach((getStartIndex) => {\n tempStart = getStartIndex.call({ lexer: this }, tempSrc);\n if (typeof tempStart === 'number' && tempStart >= 0) {\n startIndex = Math.min(startIndex, tempStart);\n }\n });\n if (startIndex < Infinity && startIndex >= 0) {\n cutSrc = src.substring(0, startIndex + 1);\n }\n }\n if (this.state.top && (token = this.tokenizer.paragraph(cutSrc))) {\n lastToken = tokens[tokens.length - 1];\n if (lastParagraphClipped && lastToken.type === 'paragraph') {\n lastToken.raw += '\\n' + token.raw;\n lastToken.text += '\\n' + token.text;\n this.inlineQueue.pop();\n this.inlineQueue[this.inlineQueue.length - 1].src = lastToken.text;\n }\n else {\n tokens.push(token);\n }\n lastParagraphClipped = (cutSrc.length !== src.length);\n src = src.substring(token.raw.length);\n continue;\n }\n // text\n if (token = this.tokenizer.text(src)) {\n src = src.substring(token.raw.length);\n lastToken = tokens[tokens.length - 1];\n if (lastToken && lastToken.type === 'text') {\n lastToken.raw += '\\n' + token.raw;\n lastToken.text += '\\n' + token.text;\n this.inlineQueue.pop();\n this.inlineQueue[this.inlineQueue.length - 1].src = lastToken.text;\n }\n else {\n tokens.push(token);\n }\n continue;\n }\n if (src) {\n const errMsg = 'Infinite loop on byte: ' + src.charCodeAt(0);\n if (this.options.silent) {\n console.error(errMsg);\n break;\n }\n else {\n throw new Error(errMsg);\n }\n }\n }\n this.state.top = true;\n return tokens;\n }\n inline(src, tokens = []) {\n this.inlineQueue.push({ src, tokens });\n return tokens;\n }\n /**\n * Lexing/Compiling\n */\n inlineTokens(src, tokens = []) {\n let token, lastToken, cutSrc;\n // String with links masked to avoid interference with em and strong\n let maskedSrc = src;\n let match;\n let keepPrevChar, prevChar;\n // Mask out reflinks\n if (this.tokens.links) {\n const links = Object.keys(this.tokens.links);\n if (links.length > 0) {\n while ((match = this.tokenizer.rules.inline.reflinkSearch.exec(maskedSrc)) != null) {\n if (links.includes(match[0].slice(match[0].lastIndexOf('[') + 1, -1))) {\n maskedSrc = maskedSrc.slice(0, match.index) + '[' + 'a'.repeat(match[0].length - 2) + ']' + maskedSrc.slice(this.tokenizer.rules.inline.reflinkSearch.lastIndex);\n }\n }\n }\n }\n // Mask out other blocks\n while ((match = this.tokenizer.rules.inline.blockSkip.exec(maskedSrc)) != null) {\n maskedSrc = maskedSrc.slice(0, match.index) + '[' + 'a'.repeat(match[0].length - 2) + ']' + maskedSrc.slice(this.tokenizer.rules.inline.blockSkip.lastIndex);\n }\n // Mask out escaped characters\n while ((match = this.tokenizer.rules.inline.anyPunctuation.exec(maskedSrc)) != null) {\n maskedSrc = maskedSrc.slice(0, match.index) + '++' + maskedSrc.slice(this.tokenizer.rules.inline.anyPunctuation.lastIndex);\n }\n while (src) {\n if (!keepPrevChar) {\n prevChar = '';\n }\n keepPrevChar = false;\n // extensions\n if (this.options.extensions\n && this.options.extensions.inline\n && this.options.extensions.inline.some((extTokenizer) => {\n if (token = extTokenizer.call({ lexer: this }, src, tokens)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n return true;\n }\n return false;\n })) {\n continue;\n }\n // escape\n if (token = this.tokenizer.escape(src)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n }\n // tag\n if (token = this.tokenizer.tag(src)) {\n src = src.substring(token.raw.length);\n lastToken = tokens[tokens.length - 1];\n if (lastToken && token.type === 'text' && lastToken.type === 'text') {\n lastToken.raw += token.raw;\n lastToken.text += token.text;\n }\n else {\n tokens.push(token);\n }\n continue;\n }\n // link\n if (token = this.tokenizer.link(src)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n }\n // reflink, nolink\n if (token = this.tokenizer.reflink(src, this.tokens.links)) {\n src = src.substring(token.raw.length);\n lastToken = tokens[tokens.length - 1];\n if (lastToken && token.type === 'text' && lastToken.type === 'text') {\n lastToken.raw += token.raw;\n lastToken.text += token.text;\n }\n else {\n tokens.push(token);\n }\n continue;\n }\n // em & strong\n if (token = this.tokenizer.emStrong(src, maskedSrc, prevChar)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n }\n // code\n if (token = this.tokenizer.codespan(src)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n }\n // br\n if (token = this.tokenizer.br(src)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n }\n // del (gfm)\n if (token = this.tokenizer.del(src)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n }\n // autolink\n if (token = this.tokenizer.autolink(src)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n }\n // url (gfm)\n if (!this.state.inLink && (token = this.tokenizer.url(src))) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n }\n // text\n // prevent inlineText consuming extensions by clipping 'src' to extension start\n cutSrc = src;\n if (this.options.extensions && this.options.extensions.startInline) {\n let startIndex = Infinity;\n const tempSrc = src.slice(1);\n let tempStart;\n this.options.extensions.startInline.forEach((getStartIndex) => {\n tempStart = getStartIndex.call({ lexer: this }, tempSrc);\n if (typeof tempStart === 'number' && tempStart >= 0) {\n startIndex = Math.min(startIndex, tempStart);\n }\n });\n if (startIndex < Infinity && startIndex >= 0) {\n cutSrc = src.substring(0, startIndex + 1);\n }\n }\n if (token = this.tokenizer.inlineText(cutSrc)) {\n src = src.substring(token.raw.length);\n if (token.raw.slice(-1) !== '_') { // Track prevChar before string of ____ started\n prevChar = token.raw.slice(-1);\n }\n keepPrevChar = true;\n lastToken = tokens[tokens.length - 1];\n if (lastToken && lastToken.type === 'text') {\n lastToken.raw += token.raw;\n lastToken.text += token.text;\n }\n else {\n tokens.push(token);\n }\n continue;\n }\n if (src) {\n const errMsg = 'Infinite loop on byte: ' + src.charCodeAt(0);\n if (this.options.silent) {\n console.error(errMsg);\n break;\n }\n else {\n throw new Error(errMsg);\n }\n }\n }\n return tokens;\n }\n}\n\n/**\n * Renderer\n */\nclass _Renderer {\n options;\n constructor(options) {\n this.options = options || _defaults;\n }\n code(code, infostring, escaped) {\n const lang = (infostring || '').match(/^\\S*/)?.[0];\n code = code.replace(/\\n$/, '') + '\\n';\n if (!lang) {\n return '
    '\n                + (escaped ? code : escape$1(code, true))\n                + '
    \\n';\n }\n return '
    '\n            + (escaped ? code : escape$1(code, true))\n            + '
    \\n';\n }\n blockquote(quote) {\n return `
    \\n${quote}
    \\n`;\n }\n html(html, block) {\n return html;\n }\n heading(text, level, raw) {\n // ignore IDs\n return `${text}\\n`;\n }\n hr() {\n return '
    \\n';\n }\n list(body, ordered, start) {\n const type = ordered ? 'ol' : 'ul';\n const startatt = (ordered && start !== 1) ? (' start=\"' + start + '\"') : '';\n return '<' + type + startatt + '>\\n' + body + '\\n';\n }\n listitem(text, task, checked) {\n return `
  • ${text}
  • \\n`;\n }\n checkbox(checked) {\n return '';\n }\n paragraph(text) {\n return `

    ${text}

    \\n`;\n }\n table(header, body) {\n if (body)\n body = `${body}`;\n return '\\n'\n + '\\n'\n + header\n + '\\n'\n + body\n + '
    \\n';\n }\n tablerow(content) {\n return `\\n${content}\\n`;\n }\n tablecell(content, flags) {\n const type = flags.header ? 'th' : 'td';\n const tag = flags.align\n ? `<${type} align=\"${flags.align}\">`\n : `<${type}>`;\n return tag + content + `\\n`;\n }\n /**\n * span level renderer\n */\n strong(text) {\n return `${text}`;\n }\n em(text) {\n return `${text}`;\n }\n codespan(text) {\n return `${text}`;\n }\n br() {\n return '
    ';\n }\n del(text) {\n return `${text}`;\n }\n link(href, title, text) {\n const cleanHref = cleanUrl(href);\n if (cleanHref === null) {\n return text;\n }\n href = cleanHref;\n let out = '
    ';\n return out;\n }\n image(href, title, text) {\n const cleanHref = cleanUrl(href);\n if (cleanHref === null) {\n return text;\n }\n href = cleanHref;\n let out = `\"${text}\"`;\n 0 && item.tokens[0].type === 'paragraph') {\n item.tokens[0].text = checkbox + ' ' + item.tokens[0].text;\n if (item.tokens[0].tokens && item.tokens[0].tokens.length > 0 && item.tokens[0].tokens[0].type === 'text') {\n item.tokens[0].tokens[0].text = checkbox + ' ' + item.tokens[0].tokens[0].text;\n }\n }\n else {\n item.tokens.unshift({\n type: 'text',\n text: checkbox + ' '\n });\n }\n }\n else {\n itemBody += checkbox + ' ';\n }\n }\n itemBody += this.parse(item.tokens, loose);\n body += this.renderer.listitem(itemBody, task, !!checked);\n }\n out += this.renderer.list(body, ordered, start);\n continue;\n }\n case 'html': {\n const htmlToken = token;\n out += this.renderer.html(htmlToken.text, htmlToken.block);\n continue;\n }\n case 'paragraph': {\n const paragraphToken = token;\n out += this.renderer.paragraph(this.parseInline(paragraphToken.tokens));\n continue;\n }\n case 'text': {\n let textToken = token;\n let body = textToken.tokens ? this.parseInline(textToken.tokens) : textToken.text;\n while (i + 1 < tokens.length && tokens[i + 1].type === 'text') {\n textToken = tokens[++i];\n body += '\\n' + (textToken.tokens ? this.parseInline(textToken.tokens) : textToken.text);\n }\n out += top ? this.renderer.paragraph(body) : body;\n continue;\n }\n default: {\n const errMsg = 'Token with \"' + token.type + '\" type was not found.';\n if (this.options.silent) {\n console.error(errMsg);\n return '';\n }\n else {\n throw new Error(errMsg);\n }\n }\n }\n }\n return out;\n }\n /**\n * Parse Inline Tokens\n */\n parseInline(tokens, renderer) {\n renderer = renderer || this.renderer;\n let out = '';\n for (let i = 0; i < tokens.length; i++) {\n const token = tokens[i];\n // Run any renderer extensions\n if (this.options.extensions && this.options.extensions.renderers && this.options.extensions.renderers[token.type]) {\n const ret = this.options.extensions.renderers[token.type].call({ parser: this }, token);\n if (ret !== false || !['escape', 'html', 'link', 'image', 'strong', 'em', 'codespan', 'br', 'del', 'text'].includes(token.type)) {\n out += ret || '';\n continue;\n }\n }\n switch (token.type) {\n case 'escape': {\n const escapeToken = token;\n out += renderer.text(escapeToken.text);\n break;\n }\n case 'html': {\n const tagToken = token;\n out += renderer.html(tagToken.text);\n break;\n }\n case 'link': {\n const linkToken = token;\n out += renderer.link(linkToken.href, linkToken.title, this.parseInline(linkToken.tokens, renderer));\n break;\n }\n case 'image': {\n const imageToken = token;\n out += renderer.image(imageToken.href, imageToken.title, imageToken.text);\n break;\n }\n case 'strong': {\n const strongToken = token;\n out += renderer.strong(this.parseInline(strongToken.tokens, renderer));\n break;\n }\n case 'em': {\n const emToken = token;\n out += renderer.em(this.parseInline(emToken.tokens, renderer));\n break;\n }\n case 'codespan': {\n const codespanToken = token;\n out += renderer.codespan(codespanToken.text);\n break;\n }\n case 'br': {\n out += renderer.br();\n break;\n }\n case 'del': {\n const delToken = token;\n out += renderer.del(this.parseInline(delToken.tokens, renderer));\n break;\n }\n case 'text': {\n const textToken = token;\n out += renderer.text(textToken.text);\n break;\n }\n default: {\n const errMsg = 'Token with \"' + token.type + '\" type was not found.';\n if (this.options.silent) {\n console.error(errMsg);\n return '';\n }\n else {\n throw new Error(errMsg);\n }\n }\n }\n }\n return out;\n }\n}\n\nclass _Hooks {\n options;\n constructor(options) {\n this.options = options || _defaults;\n }\n static passThroughHooks = new Set([\n 'preprocess',\n 'postprocess',\n 'processAllTokens'\n ]);\n /**\n * Process markdown before marked\n */\n preprocess(markdown) {\n return markdown;\n }\n /**\n * Process HTML after marked is finished\n */\n postprocess(html) {\n return html;\n }\n /**\n * Process all tokens before walk tokens\n */\n processAllTokens(tokens) {\n return tokens;\n }\n}\n\nclass Marked {\n defaults = _getDefaults();\n options = this.setOptions;\n parse = this.#parseMarkdown(_Lexer.lex, _Parser.parse);\n parseInline = this.#parseMarkdown(_Lexer.lexInline, _Parser.parseInline);\n Parser = _Parser;\n Renderer = _Renderer;\n TextRenderer = _TextRenderer;\n Lexer = _Lexer;\n Tokenizer = _Tokenizer;\n Hooks = _Hooks;\n constructor(...args) {\n this.use(...args);\n }\n /**\n * Run callback for every token\n */\n walkTokens(tokens, callback) {\n let values = [];\n for (const token of tokens) {\n values = values.concat(callback.call(this, token));\n switch (token.type) {\n case 'table': {\n const tableToken = token;\n for (const cell of tableToken.header) {\n values = values.concat(this.walkTokens(cell.tokens, callback));\n }\n for (const row of tableToken.rows) {\n for (const cell of row) {\n values = values.concat(this.walkTokens(cell.tokens, callback));\n }\n }\n break;\n }\n case 'list': {\n const listToken = token;\n values = values.concat(this.walkTokens(listToken.items, callback));\n break;\n }\n default: {\n const genericToken = token;\n if (this.defaults.extensions?.childTokens?.[genericToken.type]) {\n this.defaults.extensions.childTokens[genericToken.type].forEach((childTokens) => {\n const tokens = genericToken[childTokens].flat(Infinity);\n values = values.concat(this.walkTokens(tokens, callback));\n });\n }\n else if (genericToken.tokens) {\n values = values.concat(this.walkTokens(genericToken.tokens, callback));\n }\n }\n }\n }\n return values;\n }\n use(...args) {\n const extensions = this.defaults.extensions || { renderers: {}, childTokens: {} };\n args.forEach((pack) => {\n // copy options to new object\n const opts = { ...pack };\n // set async to true if it was set to true before\n opts.async = this.defaults.async || opts.async || false;\n // ==-- Parse \"addon\" extensions --== //\n if (pack.extensions) {\n pack.extensions.forEach((ext) => {\n if (!ext.name) {\n throw new Error('extension name required');\n }\n if ('renderer' in ext) { // Renderer extensions\n const prevRenderer = extensions.renderers[ext.name];\n if (prevRenderer) {\n // Replace extension with func to run new extension but fall back if false\n extensions.renderers[ext.name] = function (...args) {\n let ret = ext.renderer.apply(this, args);\n if (ret === false) {\n ret = prevRenderer.apply(this, args);\n }\n return ret;\n };\n }\n else {\n extensions.renderers[ext.name] = ext.renderer;\n }\n }\n if ('tokenizer' in ext) { // Tokenizer Extensions\n if (!ext.level || (ext.level !== 'block' && ext.level !== 'inline')) {\n throw new Error(\"extension level must be 'block' or 'inline'\");\n }\n const extLevel = extensions[ext.level];\n if (extLevel) {\n extLevel.unshift(ext.tokenizer);\n }\n else {\n extensions[ext.level] = [ext.tokenizer];\n }\n if (ext.start) { // Function to check for start of token\n if (ext.level === 'block') {\n if (extensions.startBlock) {\n extensions.startBlock.push(ext.start);\n }\n else {\n extensions.startBlock = [ext.start];\n }\n }\n else if (ext.level === 'inline') {\n if (extensions.startInline) {\n extensions.startInline.push(ext.start);\n }\n else {\n extensions.startInline = [ext.start];\n }\n }\n }\n }\n if ('childTokens' in ext && ext.childTokens) { // Child tokens to be visited by walkTokens\n extensions.childTokens[ext.name] = ext.childTokens;\n }\n });\n opts.extensions = extensions;\n }\n // ==-- Parse \"overwrite\" extensions --== //\n if (pack.renderer) {\n const renderer = this.defaults.renderer || new _Renderer(this.defaults);\n for (const prop in pack.renderer) {\n if (!(prop in renderer)) {\n throw new Error(`renderer '${prop}' does not exist`);\n }\n if (prop === 'options') {\n // ignore options property\n continue;\n }\n const rendererProp = prop;\n const rendererFunc = pack.renderer[rendererProp];\n const prevRenderer = renderer[rendererProp];\n // Replace renderer with func to run extension, but fall back if false\n renderer[rendererProp] = (...args) => {\n let ret = rendererFunc.apply(renderer, args);\n if (ret === false) {\n ret = prevRenderer.apply(renderer, args);\n }\n return ret || '';\n };\n }\n opts.renderer = renderer;\n }\n if (pack.tokenizer) {\n const tokenizer = this.defaults.tokenizer || new _Tokenizer(this.defaults);\n for (const prop in pack.tokenizer) {\n if (!(prop in tokenizer)) {\n throw new Error(`tokenizer '${prop}' does not exist`);\n }\n if (['options', 'rules', 'lexer'].includes(prop)) {\n // ignore options, rules, and lexer properties\n continue;\n }\n const tokenizerProp = prop;\n const tokenizerFunc = pack.tokenizer[tokenizerProp];\n const prevTokenizer = tokenizer[tokenizerProp];\n // Replace tokenizer with func to run extension, but fall back if false\n // @ts-expect-error cannot type tokenizer function dynamically\n tokenizer[tokenizerProp] = (...args) => {\n let ret = tokenizerFunc.apply(tokenizer, args);\n if (ret === false) {\n ret = prevTokenizer.apply(tokenizer, args);\n }\n return ret;\n };\n }\n opts.tokenizer = tokenizer;\n }\n // ==-- Parse Hooks extensions --== //\n if (pack.hooks) {\n const hooks = this.defaults.hooks || new _Hooks();\n for (const prop in pack.hooks) {\n if (!(prop in hooks)) {\n throw new Error(`hook '${prop}' does not exist`);\n }\n if (prop === 'options') {\n // ignore options property\n continue;\n }\n const hooksProp = prop;\n const hooksFunc = pack.hooks[hooksProp];\n const prevHook = hooks[hooksProp];\n if (_Hooks.passThroughHooks.has(prop)) {\n // @ts-expect-error cannot type hook function dynamically\n hooks[hooksProp] = (arg) => {\n if (this.defaults.async) {\n return Promise.resolve(hooksFunc.call(hooks, arg)).then(ret => {\n return prevHook.call(hooks, ret);\n });\n }\n const ret = hooksFunc.call(hooks, arg);\n return prevHook.call(hooks, ret);\n };\n }\n else {\n // @ts-expect-error cannot type hook function dynamically\n hooks[hooksProp] = (...args) => {\n let ret = hooksFunc.apply(hooks, args);\n if (ret === false) {\n ret = prevHook.apply(hooks, args);\n }\n return ret;\n };\n }\n }\n opts.hooks = hooks;\n }\n // ==-- Parse WalkTokens extensions --== //\n if (pack.walkTokens) {\n const walkTokens = this.defaults.walkTokens;\n const packWalktokens = pack.walkTokens;\n opts.walkTokens = function (token) {\n let values = [];\n values.push(packWalktokens.call(this, token));\n if (walkTokens) {\n values = values.concat(walkTokens.call(this, token));\n }\n return values;\n };\n }\n this.defaults = { ...this.defaults, ...opts };\n });\n return this;\n }\n setOptions(opt) {\n this.defaults = { ...this.defaults, ...opt };\n return this;\n }\n lexer(src, options) {\n return _Lexer.lex(src, options ?? this.defaults);\n }\n parser(tokens, options) {\n return _Parser.parse(tokens, options ?? this.defaults);\n }\n #parseMarkdown(lexer, parser) {\n return (src, options) => {\n const origOpt = { ...options };\n const opt = { ...this.defaults, ...origOpt };\n // Show warning if an extension set async to true but the parse was called with async: false\n if (this.defaults.async === true && origOpt.async === false) {\n if (!opt.silent) {\n console.warn('marked(): The async option was set to true by an extension. The async: false option sent to parse will be ignored.');\n }\n opt.async = true;\n }\n const throwError = this.#onError(!!opt.silent, !!opt.async);\n // throw error in case of non string input\n if (typeof src === 'undefined' || src === null) {\n return throwError(new Error('marked(): input parameter is undefined or null'));\n }\n if (typeof src !== 'string') {\n return throwError(new Error('marked(): input parameter is of type '\n + Object.prototype.toString.call(src) + ', string expected'));\n }\n if (opt.hooks) {\n opt.hooks.options = opt;\n }\n if (opt.async) {\n return Promise.resolve(opt.hooks ? opt.hooks.preprocess(src) : src)\n .then(src => lexer(src, opt))\n .then(tokens => opt.hooks ? opt.hooks.processAllTokens(tokens) : tokens)\n .then(tokens => opt.walkTokens ? Promise.all(this.walkTokens(tokens, opt.walkTokens)).then(() => tokens) : tokens)\n .then(tokens => parser(tokens, opt))\n .then(html => opt.hooks ? opt.hooks.postprocess(html) : html)\n .catch(throwError);\n }\n try {\n if (opt.hooks) {\n src = opt.hooks.preprocess(src);\n }\n let tokens = lexer(src, opt);\n if (opt.hooks) {\n tokens = opt.hooks.processAllTokens(tokens);\n }\n if (opt.walkTokens) {\n this.walkTokens(tokens, opt.walkTokens);\n }\n let html = parser(tokens, opt);\n if (opt.hooks) {\n html = opt.hooks.postprocess(html);\n }\n return html;\n }\n catch (e) {\n return throwError(e);\n }\n };\n }\n #onError(silent, async) {\n return (e) => {\n e.message += '\\nPlease report this to https://github.com/markedjs/marked.';\n if (silent) {\n const msg = '

    An error occurred:

    '\n                    + escape$1(e.message + '', true)\n                    + '
    ';\n if (async) {\n return Promise.resolve(msg);\n }\n return msg;\n }\n if (async) {\n return Promise.reject(e);\n }\n throw e;\n };\n }\n}\n\nconst markedInstance = new Marked();\nfunction marked(src, opt) {\n return markedInstance.parse(src, opt);\n}\n/**\n * Sets the default options.\n *\n * @param options Hash of options\n */\nmarked.options =\n marked.setOptions = function (options) {\n markedInstance.setOptions(options);\n marked.defaults = markedInstance.defaults;\n changeDefaults(marked.defaults);\n return marked;\n };\n/**\n * Gets the original marked default options.\n */\nmarked.getDefaults = _getDefaults;\nmarked.defaults = _defaults;\n/**\n * Use Extension\n */\nmarked.use = function (...args) {\n markedInstance.use(...args);\n marked.defaults = markedInstance.defaults;\n changeDefaults(marked.defaults);\n return marked;\n};\n/**\n * Run callback for every token\n */\nmarked.walkTokens = function (tokens, callback) {\n return markedInstance.walkTokens(tokens, callback);\n};\n/**\n * Compiles markdown to HTML without enclosing `p` tag.\n *\n * @param src String of markdown source to be compiled\n * @param options Hash of options\n * @return String of compiled HTML\n */\nmarked.parseInline = markedInstance.parseInline;\n/**\n * Expose\n */\nmarked.Parser = _Parser;\nmarked.parser = _Parser.parse;\nmarked.Renderer = _Renderer;\nmarked.TextRenderer = _TextRenderer;\nmarked.Lexer = _Lexer;\nmarked.lexer = _Lexer.lex;\nmarked.Tokenizer = _Tokenizer;\nmarked.Hooks = _Hooks;\nmarked.parse = marked;\nconst options = marked.options;\nconst setOptions = marked.setOptions;\nconst use = marked.use;\nconst walkTokens = marked.walkTokens;\nconst parseInline = marked.parseInline;\nconst parse = marked;\nconst parser = _Parser.parse;\nconst lexer = _Lexer.lex;\n\nexport { _Hooks as Hooks, _Lexer as Lexer, Marked, _Parser as Parser, _Renderer as Renderer, _TextRenderer as TextRenderer, _Tokenizer as Tokenizer, _defaults as defaults, _getDefaults as getDefaults, lexer, marked, options, parse, parseInline, parser, setOptions, use, walkTokens };\n//# sourceMappingURL=marked.esm.js.map\n"],"names":["_getDefaults","async","breaks","extensions","gfm","hooks","pedantic","renderer","silent","tokenizer","walkTokens","_defaults","changeDefaults","newDefaults","_exports","defaults","escapeTest","escapeReplace","RegExp","source","escapeTestNoEncode","escapeReplaceNoEncode","escapeReplacements","getEscapeReplacement","ch","escape$1","html","encode","test","replace","unescapeTest","unescape","_","n","toLowerCase","charAt","String","fromCharCode","parseInt","substring","caret","edit","regex","opt","obj","name","val","valSource","getRegex","cleanUrl","href","encodeURI","e","noopTest","exec","splitCells","tableRow","count","cells","match","offset","str","escaped","curr","split","i","trim","shift","length","pop","splice","push","rtrim","c","invert","l","suffLen","currChar","slice","outputLink","cap","link","raw","lexer","title","text","state","inLink","token","type","tokens","inlineTokens","_Tokenizer","options","rules","constructor","this","space","src","block","newline","code","codeBlockStyle","fences","matchIndentToCode","indentToCode","map","node","matchIndentInNode","indentInNode","join","indentCodeCompensation","lang","inline","anyPunctuation","heading","trimmed","depth","hr","blockquote","top","blockTokens","list","bull","isordered","ordered","start","loose","items","itemRegex","itemContents","endsWithBlankLine","endEarly","line","t","repeat","nextLine","indent","trimStart","search","blankLine","nextBulletRegex","Math","min","hrRegex","fencesBeginRegex","headingBeginRegex","rawLine","ischecked","istask","task","checked","trimEnd","spacers","filter","hasMultipleLineBreaks","some","pre","def","tag","table","headers","aligns","rows","item","header","align","row","cell","lheading","paragraph","escape","inRawBlock","trimmedUrl","rtrimSlash","lastParenIndex","b","indexOf","level","findClosingBracket","linkLen","reflink","links","nolink","emStrong","maskedSrc","prevChar","arguments","undefined","emStrongLDelim","punctuation","lLength","rDelim","rLength","delimTotal","midDelimTotal","endReg","emStrongRDelimAst","emStrongRDelimUnd","lastIndex","lastCharLength","index","codespan","hasNonSpaceChars","hasSpaceCharsOnBothEnds","br","del","autolink","url","prevCapZero","_this$rules$inline$_b","_backpedal","inlineText","Tokenizer","bullet","_paragraph","_blockLabel","_tag","_comment","blockNormal","gfmTable","blockGfm","blockPedantic","_inlineComment","_inlineLabel","inlineNormal","blockSkip","reflinkSearch","inlinePedantic","inlineGfm","inlineBreaks","normal","_Lexer","inlineQueue","Object","create","lex","lexInline","next","lastToken","cutSrc","lastParagraphClipped","leading","tabs","extTokenizer","call","startBlock","startIndex","Infinity","tempSrc","tempStart","forEach","getStartIndex","errMsg","charCodeAt","console","error","Error","keepPrevChar","keys","includes","lastIndexOf","startInline","Lexer","_Renderer","infostring","_match","quote","body","listitem","checkbox","tablerow","content","tablecell","flags","strong","em","cleanHref","out","image","Renderer","_TextRenderer","TextRenderer","_Parser","textRenderer","parse","parseInline","renderers","genericToken","ret","parser","headingToken","codeToken","tableToken","j","k","blockquoteToken","listToken","itemBody","unshift","htmlToken","paragraphToken","textToken","escapeToken","tagToken","linkToken","imageToken","strongToken","emToken","codespanToken","delToken","Parser","_Hooks","static","Set","preprocess","markdown","postprocess","processAllTokens","Hooks","Marked","setOptions","parseMarkdown","use","callback","values","concat","_this$defaults$extens","_this$defaults$extens2","childTokens","flat","_len","args","Array","_key","pack","opts","ext","prevRenderer","_len2","_key2","apply","extLevel","prop","rendererProp","rendererFunc","_len3","_key3","tokenizerProp","tokenizerFunc","prevTokenizer","_len4","_key4","hooksProp","hooksFunc","prevHook","passThroughHooks","has","arg","Promise","resolve","then","_len5","_key5","packWalktokens","origOpt","warn","throwError","onError","prototype","toString","all","catch","message","msg","reject","markedInstance","marked","getDefaults"],"mappings":"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"} \ No newline at end of file diff --git a/amd/src/ai_manager.js b/amd/src/ai_manager.js index d224eba..27ea7c2 100644 --- a/amd/src/ai_manager.js +++ b/amd/src/ai_manager.js @@ -1,5 +1,4 @@ import {makeRequest} from 'local_ai_manager/make_request'; -import {exception as displayException} from 'core/notification'; /** * Get the async answer from the local_ai_manager. @@ -14,7 +13,6 @@ export const askLocalAiManager = async(purpose, prompt, options = []) => { try { result = await makeRequest(purpose, prompt, options); } catch (error) { - console.log(error); result.code = 'aiconnector'; result.result = error.error + " " + error.message; // For devs. diff --git a/amd/src/dialog.js b/amd/src/dialog.js index 1660064..f9fe907 100644 --- a/amd/src/dialog.js +++ b/amd/src/dialog.js @@ -64,7 +64,6 @@ class DialogModal extends Modal { modalConfig.removeOnClose = false; modalConfig.isVerticallyCentered = false; - // returnFocus: target, super.configure(modalConfig); @@ -107,7 +106,6 @@ export const init = async(params) => { templateContext: { title: strNewDialog, badge: badge, - // history: history, // history dynamically added. }, }); @@ -232,12 +230,9 @@ async function showModal() { * Webservice Get all conversations. */ const getConversations = async() => { - console.log("allConversations called"); try { allConversations = await externalServices.getAllConversations(userid, contextid); - console.log(allConversations); } catch (error) { - console.log(allConversations); displayException(error); } }; @@ -247,7 +242,6 @@ const getConversations = async() => { * @param {*} id */ const showConversation = (id = 0) => { - console.log("showConversation called"); // Dissallow changing conversations when question running. if (aiAtWork) { return; @@ -284,7 +278,6 @@ const enterQuestion = async(question) => { } const message = await userAllowed(); if (message !== '') { - console.log("User not allowed"); const notice = await getString('noticenewquestion', 'block_ai_chat'); await displayAlert(notice, message); aiAtWork = false; @@ -363,7 +356,7 @@ const enterQuestion = async(question) => { * Render reply. * @param {string} text */ -const showReply = async (text) => { +const showReply = async(text) => { // Get textblock. let fields = document.querySelectorAll('.ai_chat_modal .awaitanswer .text'); const field = fields[fields.length - 1]; @@ -378,7 +371,6 @@ const showReply = async (text) => { }; const showMessages = () => { - console.log("showMessages called"); conversation.messages.forEach((val) => { showMessage(val.message, val.sender); }); @@ -427,7 +419,6 @@ const showMessage = async(text, sender = '', answer = true) => { * @param {bool} deleted */ const newDialog = async(deleted = false) => { - console.log("newDialog called"); if (aiAtWork) { return; } @@ -449,7 +440,6 @@ const newDialog = async(deleted = false) => { * Delete /hide current dialog. */ const deleteCurrentDialog = () => { - console.log("deleteCurrentDialog called"); deleteCancelPromise( getString('delete', 'block_ai_chat'), getString('deletewarning', 'block_ai_chat'), @@ -475,7 +465,6 @@ const deleteCurrentDialog = () => { * Show conversation history. */ const showHistory = async() => { - console.log("showHistory called"); // Add current convo local representation, if not already there. if (allConversations.find(x => x.id === conversation.id) === undefined) { allConversations.push(conversation); @@ -598,7 +587,6 @@ const saveConversationLocally = (question, reply) => { * @param {*} hideinput */ const clearMessages = (hideinput = false) => { - console.log("clearMessages called"); const output = document.querySelector('.block_ai_chat-output'); output.innerHTML = ''; // For showing history. @@ -727,7 +715,6 @@ const errorHandling = async(requestresult, question, options) => { // And write generic error message in chatbot. requestresult.result = await getString('error', 'block_ai_chat'); - console.log(requestresult); return requestresult; }; @@ -738,11 +725,9 @@ const errorHandling = async(requestresult, question, options) => { */ const checkMessageHistoryLengthLimit = async(messages) => { const length = messages.length; - console.log("checkHistoryLengthLimit called"); if (length > maxHistory) { // Cut history. let shortenedMessages = [messages[0], ...messages.slice(-maxHistory)]; - console.log(shortenedMessages); // Show warning once per session. if (!maxHistoryWarnings.has(conversation.id)) { @@ -800,6 +785,7 @@ const setView = async(mode = '') => { * @returns {message} */ const userAllowed = async() => { + let message; if (tenantConfig.tenantenabled === false) { message = await getString('error_http403disabled', 'local_ai_manager'); return message; diff --git a/amd/src/helper.js b/amd/src/helper.js index ea9cc88..d82e1eb 100644 --- a/amd/src/helper.js +++ b/amd/src/helper.js @@ -47,7 +47,6 @@ export const focustextarea = () => { * Scroll to bottom of modal body. */ export const scrollToBottom = () => { - console.log("scroll to bottom called"); const modalContent = document.querySelector('.ai_chat_modal .modal-body .block_ai_chat-output-wrapper'); modalContent.scrollTop = modalContent.scrollHeight; }; @@ -71,7 +70,7 @@ export const escapeHTML = (str) => { '/': '/', }; - return String(str).replace(/[&<>"'`\/]/g, function(match) { + return String(str).replace(/[&<>"'`/]/g, function(match) { return escapeMap[match]; }); }; diff --git a/classes/external/delete_conversation.php b/classes/external/delete_conversation.php index 594dd8d..3ee147f 100644 --- a/classes/external/delete_conversation.php +++ b/classes/external/delete_conversation.php @@ -47,6 +47,8 @@ public static function execute_parameters(): external_function_parameters { * Execute the service. * * @param int $contextid + * @param int $userid + * @param int $conversationid * @return array * @throws invalid_parameter_exception * @throws dml_exception diff --git a/classes/local/hook_callbacks.php b/classes/local/hook_callbacks.php index fd1e0dd..25c0130 100644 --- a/classes/local/hook_callbacks.php +++ b/classes/local/hook_callbacks.php @@ -85,7 +85,9 @@ public static function handle_after_form_submission(\core_course\hook\after_form /** * Check if block instance is present and set addaichat form setting. * - * @param after_form_submission $hook + * @param after_form_definition_after_data $hook + * @return void + * @throws \dml_exception */ public static function handle_after_form_definition_after_data(\core_course\hook\after_form_definition_after_data $hook): void { // Get form data. diff --git a/classes/output/renderer.php b/classes/output/renderer.php index 3e8e768..33eda6d 100644 --- a/classes/output/renderer.php +++ b/classes/output/renderer.php @@ -33,6 +33,7 @@ class renderer extends plugin_renderer_base { /** * Defer to template. * + * @param block_ai_chat $block * @return string html for the page */ public function render_ai_chat_content(\block_ai_chat $block): string { diff --git a/styles.css b/styles.css index dd90c58..0504a0b 100644 --- a/styles.css +++ b/styles.css @@ -1,3 +1,4 @@ +/* stylelint-disable */ #ai_chat_button { visibility: visible; position: fixed; @@ -256,6 +257,11 @@ display: none; } +@media (min-width: 497px) { + .ai_chat_modal.onhistorypage .modal-body { + min-width: 497px; + } +} .ai_fake_block { visibility: hidden; height: 0; @@ -277,7 +283,8 @@ body.block_ai_chat_chatwindow, body.block_ai_chat_dockright { overflow: initial; } -body.block_ai_chat_chatwindow .modal-backdrop.show, body.block_ai_chat_chatwindow .ai_chat_modal, +body.block_ai_chat_chatwindow .modal-backdrop.show, +body.block_ai_chat_chatwindow .ai_chat_modal, body.block_ai_chat_dockright .modal-backdrop.show, body.block_ai_chat_dockright .ai_chat_modal { width: 0; @@ -330,11 +337,6 @@ body.block_ai_chat_openfull .block_floatingbutton-floatingicons { display: none; } } -@media (min-width: 497px) { - .ai_chat_modal.onhistorypage .modal-body { - min-width: 497px; - } -} body.block_ai_chat_replacehelp #page-footer [data-region=footer-container-popover] .btn-footer-popover[data-action=footer-popover] { display: none; } diff --git a/styles.scss b/styles.scss index affaf93..fcb4dc0 100644 --- a/styles.scss +++ b/styles.scss @@ -1,3 +1,4 @@ +/* stylelint-disable */ #ai_chat_button { visibility: visible; position: fixed; @@ -269,7 +270,13 @@ } } } - +@media (min-width: 497px) { + .ai_chat_modal.onhistorypage { + .modal-body { + min-width: 497px; + } + } +} .ai_fake_block { visibility: hidden; @@ -292,7 +299,8 @@ body.block_ai_chat_chatwindow { body.block_ai_chat_chatwindow, body.block_ai_chat_dockright { overflow: initial; - .modal-backdrop.show, .ai_chat_modal { + .modal-backdrop.show, + .ai_chat_modal { width: 0; height: 0; } @@ -349,13 +357,7 @@ body.block_ai_chat_openfull { display: none; } } -@media (min-width: 497px) { - .ai_chat_modal.onhistorypage { - .modal-body { - min-width: 497px; - } - } -} + body.block_ai_chat_replacehelp { // Replace question mark popover on the bottom right corner with ai_chat. diff --git a/templates/dialog_modal.mustache b/templates/dialog_modal.mustache index 4cc00a6..cc7b5b9 100644 --- a/templates/dialog_modal.mustache +++ b/templates/dialog_modal.mustache @@ -15,7 +15,7 @@ You should have received a copy of the GNU General Public License along with Moodle. If not, see . }} {{! - @template block_ai_chat/iconpicker + @template block_ai_chat/dialog_modal Template for iconpicker. @@ -32,7 +32,7 @@ along with Moodle. If not, see . { "history": { "message":"content", - "sender":"user", + "sender":"user" } } }} diff --git a/templates/floatingbutton.mustache b/templates/floatingbutton.mustache index bda2723..50c04a2 100644 --- a/templates/floatingbutton.mustache +++ b/templates/floatingbutton.mustache @@ -22,10 +22,10 @@ Example context (json): { "title":"AI Companion", - "arialabel":"Open AI Companion", + "arialabel":"Open AI Companion" } }} \ No newline at end of file diff --git a/templates/history.mustache b/templates/history.mustache index c1c68cc..2064da7 100644 --- a/templates/history.mustache +++ b/templates/history.mustache @@ -24,8 +24,8 @@ "key": "Heute", "objects": [{ "title": "Erste Frage", - "conversationid": 9, - },] + "conversationid": 9 + }] } }} diff --git a/templates/message.mustache b/templates/message.mustache index e0427d2..5a2245b 100644 --- a/templates/message.mustache +++ b/templates/message.mustache @@ -15,14 +15,14 @@ along with Moodle. If not, see . }} {{! - @template block_ai_chat/floatingbutton + @template block_ai_chat/message Button to call ai_chat modal Example context (json): { "message":"content", - "sender":"", + "sender":"" } }} {{! Show message from user or ai }} @@ -40,7 +40,7 @@ {{{content}}} - + {{! Insert placeholder in case of pending question }} {{^answer}}
    @@ -52,5 +52,6 @@
    {{#str}} awaitanswer, block_ai_chat {{/str}}
    - + + {{/answer}} \ No newline at end of file