diff --git a/Scripts/appversion.js b/Scripts/appversion.js
index 01538c8..36f5211 100644
--- a/Scripts/appversion.js
+++ b/Scripts/appversion.js
@@ -1 +1 @@
-const appversion = "1.5.1";
+const appversion = "1.5.2";
diff --git a/Scripts/preferences.js b/Scripts/preferences.js
index 0674ee4..8cae316 100644
--- a/Scripts/preferences.js
+++ b/Scripts/preferences.js
@@ -29,13 +29,10 @@ let up_overalltheme_light = localStorage.getObject("overalltheme_light") || over
let up_editortheme_dark = localStorage.getObject("editortheme_dark") || editorThemes_dark[0];
let up_editortheme_light = localStorage.getObject("editortheme_light") || editorThemes_light[0];
let up_wordcount_tracking = localStorage.getObject("wordcount_tracking") || true; // whether wordcount tracking is enabled
-let up_wordcount_interval = localStorage.getObject("wordcount_interval") || 15; // interval to check on the wordcount in minutes
let up_wordcount_dailytarget = localStorage.getObject("wordcount_dailytarget") || 200; // net number of words that must be produced daily
let up_wordcount_notificationhour = localStorage.getObject("wordcount_notificationhour") || 18; // hour of the day at which the user is notified whether they have achieved their goal
// user preferences boundaries
-let up_wordcount_interval_min = 1;
-let up_wordcount_interval_max = 360;
let up_wordcount_dailytarget_min = 1;
let up_wordcount_dailytarget_max = 2147483647;
let up_wordcount_notificationhour_min = -1;
@@ -129,20 +126,17 @@ function setupPreferencesPane() {
Tracking
-
-
+
+
-
-
+
+
-
-
+
Show wordcount graph
-
Show wordcount graph
-
-
Reset wordcount
+
Reset wordcount
`;
if (document.querySelector("#left-menu")) {
@@ -163,7 +157,6 @@ function setupPreferencesPane() {
settings_form.querySelector("#editortheme_dark").value = up_editortheme_dark;
settings_form.querySelector("#editortheme_light").value = up_editortheme_light;
settings_form.querySelector("#wordcount_tracking").checked = up_wordcount_tracking;
- settings_form.querySelector("#wordcount_interval").value = up_wordcount_interval;
settings_form.querySelector("#wordcount_dailytarget").value = up_wordcount_dailytarget;
settings_form.querySelector("#wordcount_notificationhour").value = up_wordcount_notificationhour;
@@ -172,7 +165,6 @@ function setupPreferencesPane() {
settings_form.querySelector("#overalltheme_light").disabled = !up_colormode_switching;
settings_form.querySelector("#editortheme_dark").disabled = !up_colormode_switching;
settings_form.querySelector("#editortheme_light").disabled = !up_colormode_switching;
- settings_form.querySelector("#wordcount_interval").disabled = !up_wordcount_tracking;
settings_form.querySelector("#wordcount_dailytarget").disabled = !up_wordcount_tracking;
settings_form.querySelector("#wordcount_notificationhour").disabled = !up_wordcount_tracking;
@@ -215,7 +207,6 @@ const settings_handler = {
editortheme_dark: set_editortheme_dark,
editortheme_light: set_editortheme_light,
wordcount_tracking: set_wordcount_tracking,
- wordcount_interval: set_wordcount_interval,
wordcount_dailytarget: set_wordcount_dailytarget,
wordcount_notificationhour: set_wordcount_notificationhour,
};
@@ -224,7 +215,6 @@ function set_wordcount_tracking(key, value) {
if (value.checked != up_wordcount_tracking) {
up_wordcount_tracking = value.checked;
localStorage.setObject(key, value.checked);
- settings_form.querySelector("#wordcount_interval").disabled = !up_wordcount_tracking;
settings_form.querySelector("#wordcount_dailytarget").disabled = !up_wordcount_tracking;
settings_form.querySelector("#wordcount_notificationhour").disabled = !up_wordcount_tracking;
if (up_wordcount_tracking == true) {
@@ -237,21 +227,6 @@ function set_wordcount_tracking(key, value) {
}
}
-function set_wordcount_interval(key, value) {
- if (value.value < up_wordcount_interval_min || value.value > up_wordcount_interval_max) {
- alert(
- `You set ${value.value}, but wordcount interval must be between ${up_wordcount_interval_min} and ${up_wordcount_interval_max}`
- );
- settings_form.querySelector(`#${key}`).value = up_wordcount_interval;
- } else if (value.value != up_wordcount_interval) {
- up_wordcount_interval = value.value;
- localStorage.setObject(key, value.value);
- // register the wordcount tracking again so the new interval is used
- destructWordCount();
- setupWordCount();
- }
-}
-
function set_wordcount_dailytarget(key, value) {
if (value.value < up_wordcount_dailytarget_min || value.value > up_wordcount_dailytarget_max) {
alert(
diff --git a/bundled_script.js b/bundled_script.js
index 2e70c57..6094707 100644
--- a/bundled_script.js
+++ b/bundled_script.js
@@ -1 +1 @@
-let comments_watcher_unbind,chat_observer,colorscheme,lib_chartjs_loaded=!1;const appversion="1.5.1";try{angular}catch(e){if("ReferenceError"==e.name)throw new Error("Angular is not present on this page, Native Overleaf will not be active here")}let notificationCounter=0,lastNotificationResetTimestamp=Date.now();const originalDocumentTitle=document.title;let current_colorscheme_preference;function getLocalDate(){return(new Date).toLocaleDateString("en-CA")}function recursiveCheckAndWait(checkFunction,waitTime,numberOfTimesToCheck,multiplyWaitTime=!1,numberOfTimesChecked=0){const checkFunctionResult=checkFunction();return numberOfTimesChecked+=1,0!=checkFunctionResult?checkFunctionResult:!(numberOfTimesToCheck-numberOfTimesChecked<=0)&&new Promise((resolve=>{1==multiplyWaitTime&&(waitTime*=numberOfTimesChecked),setTimeout((()=>{resolve(recursiveCheckAndWait(checkFunction,waitTime,numberOfTimesToCheck,multiplyWaitTime,numberOfTimesChecked))}),waitTime)}))}window.matchMedia&&(colorscheme=window.matchMedia("(prefers-color-scheme: dark)"),current_colorscheme_preference=colorscheme.matches?"dark":"light"),Storage.prototype.setObject=function(key,value){this.setItem(key,JSON.stringify(value))},Storage.prototype.getObject=function(key){const value=this.getItem(key);return value&&JSON.parse(value)};const deepDiffMapper={VALUE_CREATED:"created",VALUE_UPDATED:"updated",VALUE_DELETED:"deleted",VALUE_UNCHANGED:"---",map:function(obj1,obj2){if(this.isFunction(obj1)||this.isFunction(obj2))throw"Invalid argument. Function given, object expected.";if(this.isValue(obj1)||this.isValue(obj2)){let returnObj={type:this.compareValues(obj1,obj2),original:obj1,updated:obj2};return returnObj.type!=this.VALUE_UNCHANGED?returnObj:void 0}let diff={},foundKeys={};for(let key in obj1){if(this.isFunction(obj1[key]))continue;let value2;void 0!==obj2[key]&&(value2=obj2[key]);let mapValue=this.map(obj1[key],value2);foundKeys[key]=!0,mapValue&&(diff[key]=mapValue)}for(let key in obj2){if(this.isFunction(obj2[key])||void 0!==foundKeys[key])continue;let mapValue=this.map(void 0,obj2[key]);mapValue&&(diff[key]=mapValue)}if(Object.keys(diff).length>0)return diff},compareValues:function(value1,value2){return value1===value2||this.isDate(value1)&&this.isDate(value2)&&value1.getTime()===value2.getTime()?this.VALUE_UNCHANGED:void 0===value1?this.VALUE_CREATED:void 0===value2?this.VALUE_DELETED:this.VALUE_UPDATED},isFunction:function(x){return"[object Function]"===Object.prototype.toString.call(x)},isArray:function(x){return"[object Array]"===Object.prototype.toString.call(x)},isDate:function(x){return"[object Date]"===Object.prototype.toString.call(x)},isObject:function(x){return"[object Object]"===Object.prototype.toString.call(x)},isValue:function(x){return!this.isObject(x)&&!this.isArray(x)}},overallThemes_dark={dark:"Default"},overallThemes_light={light:"Light"},editorThemes_dark={dracula:"Dracula",monokai:"Monokai",cobalt:"Cobalt"},editorThemes_light={textmate:"TextMate",overleaf:"Overleaf",eclipse:"Eclipse"};let up_notifications=localStorage.getObject("notifications")||!0,up_notifications_comments=localStorage.getObject("notifications_comment")||!0,up_notifications_comment_threads=localStorage.getObject("up_notifications_comment_response")||!0,up_notifications_chats=localStorage.getObject("notifications_chat")||!0,up_colormode_switching=localStorage.getObject("colormode_switching")||!0,up_overalltheme_dark=localStorage.getObject("overalltheme_dark")||overallThemes_dark[0],up_overalltheme_light=localStorage.getObject("overalltheme_light")||overallThemes_light[0],up_editortheme_dark=localStorage.getObject("editortheme_dark")||editorThemes_dark[0],up_editortheme_light=localStorage.getObject("editortheme_light")||editorThemes_light[0],up_wordcount_tracking=localStorage.getObject("wordcount_tracking")||!0,up_wordcount_interval=localStorage.getObject("wordcount_interval")||15,up_wordcount_dailytarget=localStorage.getObject("wordcount_dailytarget")||200,up_wordcount_notificationhour=localStorage.getObject("wordcount_notificationhour")||18,up_wordcount_interval_min=1,up_wordcount_interval_max=360,up_wordcount_dailytarget_min=1,up_wordcount_dailytarget_max=2147483647,up_wordcount_notificationhour_min=-1,up_wordcount_notificationhour_max=23,settings_form;function getFormSelectHTML(category_dicts,category_names){let str="";for(category_index in category_dicts){let endstr="";category_names.length-1>=category_index&&(str+=`"),category_dict=category_dicts[category_index];for(let key in category_dict)str+=`\n`;str+=endstr}return str}function setupPreferencesPane(){const settings_html=`\n
Native Overleaf
\n
\n
Version ${appversion}
\n \n \n
\n `;document.querySelector("#left-menu")&&(document.querySelector("#left-menu").getElementsByTagName("form")[0].insertAdjacentHTML("afterend",settings_html),settings_form=document.querySelector("#native-overleaf-settings"),settings_form.querySelector("#notifications_chat").checked=up_notifications_chats,settings_form.querySelector("#notifications_comment").checked=up_notifications_comments,settings_form.querySelector("#notifications_comment_response").checked=up_notifications_comment_threads,settings_form.querySelector("#colormode_switching").checked=up_colormode_switching,settings_form.querySelector("#overalltheme_dark").value=up_overalltheme_dark,settings_form.querySelector("#overalltheme_light").value=up_overalltheme_light,settings_form.querySelector("#editortheme_dark").value=up_editortheme_dark,settings_form.querySelector("#editortheme_light").value=up_editortheme_light,settings_form.querySelector("#wordcount_tracking").checked=up_wordcount_tracking,settings_form.querySelector("#wordcount_interval").value=up_wordcount_interval,settings_form.querySelector("#wordcount_dailytarget").value=up_wordcount_dailytarget,settings_form.querySelector("#wordcount_notificationhour").value=up_wordcount_notificationhour,settings_form.querySelector("#overalltheme_dark").disabled=!up_colormode_switching,settings_form.querySelector("#overalltheme_light").disabled=!up_colormode_switching,settings_form.querySelector("#editortheme_dark").disabled=!up_colormode_switching,settings_form.querySelector("#editortheme_light").disabled=!up_colormode_switching,settings_form.querySelector("#wordcount_interval").disabled=!up_wordcount_tracking,settings_form.querySelector("#wordcount_dailytarget").disabled=!up_wordcount_tracking,settings_form.querySelector("#wordcount_notificationhour").disabled=!up_wordcount_tracking,settings_form.addEventListener("change",(function(){for(let id_key in settings_handler)settings_handler[id_key](id_key,settings_form.querySelector(`#${id_key}`))})),document.getElementById("button_show_wordcount_graph").addEventListener("click",(()=>{showWordCountChart()})),document.getElementById("button_reset_wordcount").addEventListener("click",(()=>{let text_number_of_days="";void 0!==wordcounts&&void 0!==wordcounts[this.project_id]&&(text_number_of_days=`You currently have ${Object.keys(wordcounts[this.project_id]).length} tracked days.`);confirm(`Are you sure you want to remove all tracked wordcount history?\n ${text_number_of_days}`)&&(resetWordCounts(),setupWordCount())})))}const settings_handler={notifications_chat:set_notifications_chat,notifications_comment:set_notifications_comment,notifications_comment_response:set_notifications_comment_response,colormode_switching:set_colormode_switching,overalltheme_dark:set_overalltheme_dark,overalltheme_light:set_overalltheme_light,editortheme_dark:set_editortheme_dark,editortheme_light:set_editortheme_light,wordcount_tracking:set_wordcount_tracking,wordcount_interval:set_wordcount_interval,wordcount_dailytarget:set_wordcount_dailytarget,wordcount_notificationhour:set_wordcount_notificationhour};function set_wordcount_tracking(key,value){value.checked!=up_wordcount_tracking&&(up_wordcount_tracking=value.checked,localStorage.setObject(key,value.checked),settings_form.querySelector("#wordcount_interval").disabled=!up_wordcount_tracking,settings_form.querySelector("#wordcount_dailytarget").disabled=!up_wordcount_tracking,settings_form.querySelector("#wordcount_notificationhour").disabled=!up_wordcount_tracking,1==up_wordcount_tracking?setupWordCount():destructWordCount())}function set_wordcount_interval(key,value){value.valueup_wordcount_interval_max?(alert(`You set ${value.value}, but wordcount interval must be between ${up_wordcount_interval_min} and ${up_wordcount_interval_max}`),settings_form.querySelector(`#${key}`).value=up_wordcount_interval):value.value!=up_wordcount_interval&&(up_wordcount_interval=value.value,localStorage.setObject(key,value.value),destructWordCount(),setupWordCount())}function set_wordcount_dailytarget(key,value){value.valueup_wordcount_dailytarget_max?(alert(`You set ${value.value}, but wordcount daily target must be between ${up_wordcount_dailytarget_min} and ${up_wordcount_dailytarget_max}`),settings_form.querySelector(`#${key}`).value=up_wordcount_dailytarget):value.value!=up_wordcount_dailytarget&&(up_wordcount_dailytarget=value.value,localStorage.setObject(key,value.value),setHasBeenNotified(!1))}function set_wordcount_notificationhour(key,value){(value.valueup_wordcount_notificationhour_max)&&(alert(`You set ${value.value}, but wordcount notification hour must be between ${up_wordcount_notificationhour_min} and ${up_wordcount_notificationhour_max}`),settings_form.querySelector(`#${key}`).value=up_wordcount_notificationhour),value.value!=up_wordcount_notificationhour&&(up_wordcount_notificationhour=value.value,localStorage.setObject(key,value.value),setHasBeenNotified(!1))}function set_notifications_chat(key,value){value!=up_notifications_chats&&(up_notifications_chats=value.checked,localStorage.setObject(key,value.checked),destructNotifications(),setupNotifications())}function set_notifications_comment(key,value){value.checked!=up_notifications_comments&&(up_notifications_comments=value.checked,localStorage.setObject(key,value.checked),destructNotifications(),setupNotifications())}function set_notifications_comment_response(key,value){value.checked!=up_notifications_comment_threads&&(up_notifications_comment_threads=value.checked,localStorage.setObject(key,value.checked),destructNotifications(),setupNotifications())}function set_colormode_switching(key,value){value.checked!=up_colormode_switching&&(up_colormode_switching=value.checked,localStorage.setObject(key,value.checked),settings_form.querySelector("#overalltheme_dark").disabled=!up_colormode_switching,settings_form.querySelector("#overalltheme_light").disabled=!up_colormode_switching,settings_form.querySelector("#editortheme_dark").disabled=!up_colormode_switching,settings_form.querySelector("#editortheme_light").disabled=!up_colormode_switching,1==up_colormode_switching?setupColormode():destructColormode())}function themesetter(user_preference_variable_name,key,value){const user_preference_variable=eval(user_preference_variable_name);localStorage.setObject(key,value.value),value.value!=user_preference_variable&&(eval(`${user_preference_variable_name} = "${value.value}"`),switchColorMode())}function set_overalltheme_dark(key,value){themesetter("up_overalltheme_dark",key,value)}function set_overalltheme_light(key,value){themesetter("up_overalltheme_light",key,value)}function set_editortheme_dark(key,value){themesetter("up_editortheme_dark",key,value)}function set_editortheme_light(key,value){themesetter("up_editortheme_light",key,value)}const overallThemeToOverleaf={dark:"",light:"light-"};function switchColorMode(){let scope=angular.element("[ng-controller=SettingsController]").scope();scope&&("dark"==current_colorscheme_preference?(scope.settings.overallTheme=overallThemeToOverleaf[up_overalltheme_dark],scope.settings.editorTheme=up_editortheme_dark):"light"==current_colorscheme_preference?(scope.settings.overallTheme=overallThemeToOverleaf[up_overalltheme_light],scope.settings.editorTheme=up_editortheme_light):console.err(`current colorscheme preference ${current_colorscheme_preference} is not a valid value`),scope.$apply())}function autoChangeColorMode(event){current_colorscheme_preference=event.matches?"dark":"light",switchColorMode()}function setupColormode(){void 0!==colorscheme&&1==up_colormode_switching&&(switchColorMode(),colorscheme.addEventListener("change",autoChangeColorMode,!0))}function destructColormode(){void 0!==colorscheme&&0==up_colormode_switching&&colorscheme.removeEventListener("change",autoChangeColorMode,!0)}function sendNotification(text){new Notification(`${text}`),updateCounter(1)}function setupNotifications(){if(1==up_notifications&&1==(1==up_notifications_chats||1==up_notifications_comments||1==up_notifications_comment_threads)){if("Notification"in window?"granted"===Notification.permission||"denied"!==Notification.permission&&Notification.requestPermission((function(permission){"granted"===permission&&sendNotification("Notifications are now enabled")})):alert("This browser does not support notifications"),addEventListener("focus",resetCounter),1==up_notifications_comments){let comments_scope=angular.element("[ng-controller=ReviewPanelController]").scope();if(comments_scope){if(void 0!==comments_watcher_unbind)throw"comments_watcher_unbind should be undefined at this point";comments_watcher_unbind=comments_scope.$watch("reviewPanel.commentThreads",(function(newVal,oldVal){const diffs=deepDiffMapper.map(oldVal,newVal);for(const diff_key in diffs){let payload=diffs[diff_key];if(payload.resolved&&payload.resolved_at&&payload.resolved_by_user){const user=payload.resolved_by_user.updated;new Date(payload.resolved_at.updated)>lastNotificationResetTimestamp&&!user.isSelf&&sendNotification(`${user.name} resolved a comment`)}let actionText="responded to a comment";payload.updated&&(payload=payload.updated,actionText="commented");const messages=payload.messages;for(const message_index in messages){let message=messages[message_index];message.updated&&(message=message.updated,!up_notifications_comment_threads)||message.timestamp>lastNotificationResetTimestamp&&message.user&&message.content&&!message.user.isSelf&&sendNotification(`${message.user.name} ${actionText}: ${message.content}`)}}}),!0)}}if(1==up_notifications_chats){let chat_scope=angular.element('[class="infinite-scroll messages"]').children().children();chat_scope&&chat_scope.length&&chat_scope[1]&&(void 0===chat_observer&&(chat_observer=new MutationObserver((function(mutations){if(mutations.length&&(mutations=mutations[mutations.length-1]),Date.now()>lastNotificationResetTimestamp+2e3)for(const message_index in mutations.addedNodes)message=mutations.addedNodes[message_index],message.getElementsByClassName&&(wrapper=message.getElementsByClassName("message-wrapper")[0],wrapper.getElementsByClassName("name").length&&(sendername=wrapper.getElementsByClassName("name")[0].getElementsByTagName("span")[0].innerHTML,contents=wrapper.getElementsByClassName("message")[0].getElementsByClassName("message-content"),last_texts=contents[contents.length-1].getElementsByTagName("p"),last_text=last_texts[last_texts.length-1].innerHTML,sendNotification(`${sendername} in chat: ${last_text}`)))}))),chat_observer.observe(chat_scope[1],{childList:!0,subtree:!0}))}}}function destructNotifications(){void 0!==comments_watcher_unbind&&(comments_watcher_unbind(),comments_watcher_unbind=void 0),void 0!==chat_observer&&chat_observer.disconnect(),removeEventListener("focus",resetCounter)}function updateCounter(countToAdd){if(notificationCounter+=countToAdd,notificationCounter<=0)return resetCounter();const replaceOldCounter=/^(\(\d*\))\W/;replaceOldCounter.test(document.title)?document.title=document.title.replace(replaceOldCounter,`(${notificationCounter}) `):document.title=`(${notificationCounter}) ${originalDocumentTitle}`}function resetCounter(event){notificationCounter=0,document.title=originalDocumentTitle,lastNotificationResetTimestamp=Date.now()}function addCSS(){let styleSheet=document.createElement("style");styleSheet.innerText='\n .native-overleaf-settings {\n display: inline-block;\n width: 260px;\n }\n\n .settings-toggle {\n cursor: pointer;\n display: inline-block;\n }\n .settings-toggle-switch {\n display: inline-block;\n background: #2e3644;\n border-radius: 16px;\n width: 58px;\n height: 32px;\n position: relative;\n vertical-align: middle;\n transition: background 0.25s;\n }\n .settings-toggle-switch:before, .settings-toggle-switch:after {\n content: "";\n }\n .settings-toggle-switch:before {\n display: block;\n background: linear-gradient(to bottom, #fff 0%, #eee 100%);\n border-radius: 50%;\n box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.25);\n width: 24px;\n height: 24px;\n position: absolute;\n top: 4px;\n left: 4px;\n transition: left 0.25s;\n }\n .settings-toggle:hover .settings-toggle-switch:before {\n background: linear-gradient(to bottom, #fff 0%, #fff 100%);\n box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.5);\n }\n .settings-toggle-checkbox:checked + .settings-toggle-switch {\n background: #408827;\n }\n .settings-toggle-checkbox:checked + .settings-toggle-switch:before {\n left: 30px;\n }\n .settings-toggle-checkbox {\n position: absolute;\n visibility: hidden;\n }\n .settings-toggle-label {\n margin-left: 5px;\n position: relative;\n top: 2px;\n }\n dialog {\n width: 80vw;\n background: #EEEFEE;\n color: black;\n border-color: #E9E9E9;\n margin: auto;\n position: fixed;\n box-shadow: 5px;\n }\n dialog::backdrop {\n background: black;\n opacity: 0.7;\n backdrop-filter: blur(25px);\n }\n \n @media (prefers-color-scheme: dark) {\n dialog {\n background: #282A35;\n color: white;\n border-color: #485263;\n }\n #wordcountchart {\n filter: invert(1) hue-rotate(180deg);\n }\n }\n ',document.head.appendChild(styleSheet)}async function fetchAsync(url){let response=await fetch(url);return await response.json()}function semanticVersionCompare(a,b){return a.startsWith(b+"-")?-1:b.startsWith(a+"-")?1:a.localeCompare(b,void 0,{numeric:!0,sensitivity:"case",caseFirst:"upper"})}async function checkForUpdate(reportAll=!1){const tags=await fetchAsync("https://api.github.com/repos/fjwillemsen/NativeOverleaf/tags");if(!tags.length||void 0===tags.length)return void console.error("Can not retrieve latest version for update checking");const latest_version=tags[0].name.replace("v",""),comparison=semanticVersionCompare(latest_version,appversion);if(0==comparison&&""!==comparison)console.log("Update check completed, no update available."),1==reportAll&&alert("You're up to date with the latest version!");else if(1==comparison){confirm(`Update available! \n Current: ${appversion}, latest: ${latest_version}.\n Go to downloads page?`)&&window.open("https://github.com/fjwillemsen/NativeOverleaf/releases/latest/")}else if(-1==comparison){const result_text=`No update needed, current version (${appversion}) is newer than latest publicly available version (${latest_version}).`;console.log(result_text),1==reportAll&&alert(result_text)}else{const result_text=`Invalid semantic version comparison outcome: ${comparison}`;console.log(result_text),1==reportAll&&alert(result_text)}}function setAutoUpdateChecking(){checkForUpdate(),setInterval(checkForUpdate,216e5),document.querySelector("#versionlabel")&&(document.querySelector("#versionlabel").onclick=function(){checkForUpdate(!0)})}let wordcount_timer_id,compilation_observer,wordcounts;async function waitUntilPDFCompiled(){return await recursiveCheckAndWait(isPDFLinkAvailable,500,5,!0)}function extractWordCount(){const modal=document.getElementById("clone-project-modal");if(modal&&void 0!==modal){const modaltext=modal.outerText,wordcount=modaltext.substring(modaltext.lastIndexOf("\nTotal Words:\n")+14,modaltext.lastIndexOf("\nHeaders:")),parsedWordCount=parseInt(wordcount);if(0==isNaN(parsedWordCount))return parsedWordCount}return!1}async function getWordCount(){let wordcount_el=angular.element("[ng-controller=WordCountModalController]");if(wordcount_el&&void 0!==wordcount_el&&void 0!==wordcount_el.scope){let wordcount_scope=wordcount_el.scope();if(void 0!==wordcount_scope&&1==await waitUntilPDFCompiled()){wordcount_scope.openWordCountModal();const wordcount=await recursiveCheckAndWait(extractWordCount,50,100);return wordcount_scope.handleHide(),0==wordcount?void console.warn("Unable to get wordcount within 5 seconds, skipping"):wordcount}}}function getWordCounts(){let wordcounts=localStorage.getObject("wordcounts")||{};this.project_id in wordcounts||(wordcounts[this.project_id]={});const currentdate=getLocalDate();return currentdate in wordcounts[this.project_id]||(wordcounts[this.project_id][currentdate]={earliest:void 0,latest:void 0,hasbeennotified:!1}),wordcounts}function resetWordCounts(){return wordcounts=void 0,localStorage.removeItem("wordcounts")}async function updateWordCount(){wordcounts=getWordCounts();const currentdate=getLocalDate(),wordcount=await getWordCount(),hasbeennotified=wordcounts[this.project_id][currentdate].hasbeennotified;if(void 0===wordcount)return;void 0===wordcounts[this.project_id][currentdate].earliest&&(wordcounts[this.project_id][currentdate].earliest=wordcounts[this.project_id][currentdate].latest||wordcount),wordcounts[this.project_id][currentdate].latest=wordcount;const achieved_wordcount=wordcount-wordcounts[this.project_id][currentdate].earliest;if(0==hasbeennotified&&up_wordcount_dailytarget>0&&achieved_wordcount>=up_wordcount_dailytarget&&(new Notification("Awesome, already met today's target!",{body:`You wrote ${achieved_wordcount} words, ${achieved_wordcount-up_wordcount_dailytarget} above target!`}),wordcounts[this.project_id][currentdate].hasbeennotified=!0),0==hasbeennotified&&up_wordcount_notificationhour>-1){(new Date).getHours()==up_wordcount_notificationhour&&(up_wordcount_dailytarget<=0?new Notification(`You wrote ${achieved_wordcount} out of ${up_wordcount_dailytarget} words today.`):achieved_wordcount0)return backup_source_html.getElementsByTagName("a")[0]}return!1}function getBackupLink(backup_type_index){const backup_element=getBackupElement(backup_type_index);return""!=backup_element?backup_element.href:""}function isPDFLinkAvailable(){return getBackupElement(1)}function doBackup(){getBackupLink(up_backup_type)}let wordcountchart_show_net_wordcount=!0;async function getChartJS(){return $.ajaxSetup({cache:!0}),$.when($.getScript("https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.9.1/chart.min.js")).done((()=>{lib_chartjs_loaded=!0})).fail((()=>{alert("Unable to dynamically load ChartJS, do you have an active internet connection?")}))}function injectWordCountChartElement(){document.querySelector("#chat-wrapper").insertAdjacentHTML("afterend",'');const dialog=document.querySelector("#wordcountchartdialog");return dialog.addEventListener("click",(function(event){const rect=dialog.getBoundingClientRect();(event.clientYrect.bottom||event.clientXrect.right)&&dialog.close()})),document.getElementById("show_net_wordcount").checked=wordcountchart_show_net_wordcount,document.getElementById("show_net_wordcount").addEventListener("change",(()=>{wordcountchart_show_net_wordcount=document.getElementById("show_net_wordcount").checked,updateWordCountChartData()})),dialog}function getWordCountChartConfig(){let labels=[],counts=[];const label=1==wordcountchart_show_net_wordcount?"Net number of words written":"Total number of words",wordcounts_project=wordcounts[this.project_id];(null==wordcounts||Object.keys(wordcounts).length<=0)&&alert("Wordcounts have not been tracked, enable wordcount tracking and reload the project");for(const[date,wordcount]of Object.entries(wordcounts_project)){labels.push(date);const count=1==wordcountchart_show_net_wordcount?wordcount.latest-wordcount.earliest:wordcount.latest;counts.push(count)}let config={type:"bar",data:{labels:labels,datasets:[]},options:{}};return 1==wordcountchart_show_net_wordcount&&up_wordcount_dailytarget>0&&config.data.datasets.push({label:"Daily target",data:Array(labels.length).fill(up_wordcount_dailytarget),type:"line",backgroundColor:"red",borderColor:"red"}),config.data.datasets.push({label:label,data:counts,backgroundColor:"#408827"}),config}function updateWordCountChartData(){const config=getWordCountChartConfig();wordcountchart.data.labels=config.data.labels,wordcountchart.data.datasets=config.data.datasets,wordcountchart.update()}async function showWordCountChart(){await getChartJS(),null==wordcountchartdialog&&(wordcountchartdialog=injectWordCountChartElement(),wordcountchart=new Chart(document.getElementById("wordcountchart"),getWordCountChartConfig())),wordcountchartdialog.showModal()}function hideWordCountChart(){wordcountchartdialog.close()}const startTime=performance.now();setupColormode(),setupNotifications(),setupPreferencesPane(),addCSS(),setAutoUpdateChecking(),setupWordCount();const endTime=performance.now();console.log(`Native Overleaf injected setup took ${endTime-startTime} milliseconds`);
\ No newline at end of file
+let comments_watcher_unbind,chat_observer,colorscheme,lib_chartjs_loaded=!1;const appversion="1.5.2";try{angular}catch(e){if("ReferenceError"==e.name)throw new Error("Angular is not present on this page, Native Overleaf will not be active here")}let notificationCounter=0,lastNotificationResetTimestamp=Date.now();const originalDocumentTitle=document.title;let current_colorscheme_preference;function getLocalDate(){return(new Date).toLocaleDateString("en-CA")}function recursiveCheckAndWait(checkFunction,waitTime,numberOfTimesToCheck,multiplyWaitTime=!1,numberOfTimesChecked=0){const checkFunctionResult=checkFunction();return numberOfTimesChecked+=1,0!=checkFunctionResult?checkFunctionResult:!(numberOfTimesToCheck-numberOfTimesChecked<=0)&&new Promise((resolve=>{1==multiplyWaitTime&&(waitTime*=numberOfTimesChecked),setTimeout((()=>{resolve(recursiveCheckAndWait(checkFunction,waitTime,numberOfTimesToCheck,multiplyWaitTime,numberOfTimesChecked))}),waitTime)}))}window.matchMedia&&(colorscheme=window.matchMedia("(prefers-color-scheme: dark)"),current_colorscheme_preference=colorscheme.matches?"dark":"light"),Storage.prototype.setObject=function(key,value){this.setItem(key,JSON.stringify(value))},Storage.prototype.getObject=function(key){const value=this.getItem(key);return value&&JSON.parse(value)};const deepDiffMapper={VALUE_CREATED:"created",VALUE_UPDATED:"updated",VALUE_DELETED:"deleted",VALUE_UNCHANGED:"---",map:function(obj1,obj2){if(this.isFunction(obj1)||this.isFunction(obj2))throw"Invalid argument. Function given, object expected.";if(this.isValue(obj1)||this.isValue(obj2)){let returnObj={type:this.compareValues(obj1,obj2),original:obj1,updated:obj2};return returnObj.type!=this.VALUE_UNCHANGED?returnObj:void 0}let diff={},foundKeys={};for(let key in obj1){if(this.isFunction(obj1[key]))continue;let value2;void 0!==obj2[key]&&(value2=obj2[key]);let mapValue=this.map(obj1[key],value2);foundKeys[key]=!0,mapValue&&(diff[key]=mapValue)}for(let key in obj2){if(this.isFunction(obj2[key])||void 0!==foundKeys[key])continue;let mapValue=this.map(void 0,obj2[key]);mapValue&&(diff[key]=mapValue)}if(Object.keys(diff).length>0)return diff},compareValues:function(value1,value2){return value1===value2||this.isDate(value1)&&this.isDate(value2)&&value1.getTime()===value2.getTime()?this.VALUE_UNCHANGED:void 0===value1?this.VALUE_CREATED:void 0===value2?this.VALUE_DELETED:this.VALUE_UPDATED},isFunction:function(x){return"[object Function]"===Object.prototype.toString.call(x)},isArray:function(x){return"[object Array]"===Object.prototype.toString.call(x)},isDate:function(x){return"[object Date]"===Object.prototype.toString.call(x)},isObject:function(x){return"[object Object]"===Object.prototype.toString.call(x)},isValue:function(x){return!this.isObject(x)&&!this.isArray(x)}},overallThemes_dark={dark:"Default"},overallThemes_light={light:"Light"},editorThemes_dark={dracula:"Dracula",monokai:"Monokai",cobalt:"Cobalt"},editorThemes_light={textmate:"TextMate",overleaf:"Overleaf",eclipse:"Eclipse"};let up_notifications=localStorage.getObject("notifications")||!0,up_notifications_comments=localStorage.getObject("notifications_comment")||!0,up_notifications_comment_threads=localStorage.getObject("up_notifications_comment_response")||!0,up_notifications_chats=localStorage.getObject("notifications_chat")||!0,up_colormode_switching=localStorage.getObject("colormode_switching")||!0,up_overalltheme_dark=localStorage.getObject("overalltheme_dark")||overallThemes_dark[0],up_overalltheme_light=localStorage.getObject("overalltheme_light")||overallThemes_light[0],up_editortheme_dark=localStorage.getObject("editortheme_dark")||editorThemes_dark[0],up_editortheme_light=localStorage.getObject("editortheme_light")||editorThemes_light[0],up_wordcount_tracking=localStorage.getObject("wordcount_tracking")||!0,up_wordcount_dailytarget=localStorage.getObject("wordcount_dailytarget")||200,up_wordcount_notificationhour=localStorage.getObject("wordcount_notificationhour")||18,up_wordcount_dailytarget_min=1,up_wordcount_dailytarget_max=2147483647,up_wordcount_notificationhour_min=-1,up_wordcount_notificationhour_max=23,settings_form;function getFormSelectHTML(category_dicts,category_names){let str="";for(category_index in category_dicts){let endstr="";category_names.length-1>=category_index&&(str+=`"),category_dict=category_dicts[category_index];for(let key in category_dict)str+=`\n`;str+=endstr}return str}function setupPreferencesPane(){const settings_html=`\n
Native Overleaf
\n
\n
Version ${appversion}
\n \n \n
\n `;document.querySelector("#left-menu")&&(document.querySelector("#left-menu").getElementsByTagName("form")[0].insertAdjacentHTML("afterend",settings_html),settings_form=document.querySelector("#native-overleaf-settings"),settings_form.querySelector("#notifications_chat").checked=up_notifications_chats,settings_form.querySelector("#notifications_comment").checked=up_notifications_comments,settings_form.querySelector("#notifications_comment_response").checked=up_notifications_comment_threads,settings_form.querySelector("#colormode_switching").checked=up_colormode_switching,settings_form.querySelector("#overalltheme_dark").value=up_overalltheme_dark,settings_form.querySelector("#overalltheme_light").value=up_overalltheme_light,settings_form.querySelector("#editortheme_dark").value=up_editortheme_dark,settings_form.querySelector("#editortheme_light").value=up_editortheme_light,settings_form.querySelector("#wordcount_tracking").checked=up_wordcount_tracking,settings_form.querySelector("#wordcount_dailytarget").value=up_wordcount_dailytarget,settings_form.querySelector("#wordcount_notificationhour").value=up_wordcount_notificationhour,settings_form.querySelector("#overalltheme_dark").disabled=!up_colormode_switching,settings_form.querySelector("#overalltheme_light").disabled=!up_colormode_switching,settings_form.querySelector("#editortheme_dark").disabled=!up_colormode_switching,settings_form.querySelector("#editortheme_light").disabled=!up_colormode_switching,settings_form.querySelector("#wordcount_dailytarget").disabled=!up_wordcount_tracking,settings_form.querySelector("#wordcount_notificationhour").disabled=!up_wordcount_tracking,settings_form.addEventListener("change",(function(){for(let id_key in settings_handler)settings_handler[id_key](id_key,settings_form.querySelector(`#${id_key}`))})),document.getElementById("button_show_wordcount_graph").addEventListener("click",(()=>{showWordCountChart()})),document.getElementById("button_reset_wordcount").addEventListener("click",(()=>{let text_number_of_days="";void 0!==wordcounts&&void 0!==wordcounts[this.project_id]&&(text_number_of_days=`You currently have ${Object.keys(wordcounts[this.project_id]).length} tracked days.`);confirm(`Are you sure you want to remove all tracked wordcount history?\n ${text_number_of_days}`)&&(resetWordCounts(),setupWordCount())})))}const settings_handler={notifications_chat:set_notifications_chat,notifications_comment:set_notifications_comment,notifications_comment_response:set_notifications_comment_response,colormode_switching:set_colormode_switching,overalltheme_dark:set_overalltheme_dark,overalltheme_light:set_overalltheme_light,editortheme_dark:set_editortheme_dark,editortheme_light:set_editortheme_light,wordcount_tracking:set_wordcount_tracking,wordcount_dailytarget:set_wordcount_dailytarget,wordcount_notificationhour:set_wordcount_notificationhour};function set_wordcount_tracking(key,value){value.checked!=up_wordcount_tracking&&(up_wordcount_tracking=value.checked,localStorage.setObject(key,value.checked),settings_form.querySelector("#wordcount_dailytarget").disabled=!up_wordcount_tracking,settings_form.querySelector("#wordcount_notificationhour").disabled=!up_wordcount_tracking,1==up_wordcount_tracking?setupWordCount():destructWordCount())}function set_wordcount_dailytarget(key,value){value.valueup_wordcount_dailytarget_max?(alert(`You set ${value.value}, but wordcount daily target must be between ${up_wordcount_dailytarget_min} and ${up_wordcount_dailytarget_max}`),settings_form.querySelector(`#${key}`).value=up_wordcount_dailytarget):value.value!=up_wordcount_dailytarget&&(up_wordcount_dailytarget=value.value,localStorage.setObject(key,value.value),setHasBeenNotified(!1))}function set_wordcount_notificationhour(key,value){(value.valueup_wordcount_notificationhour_max)&&(alert(`You set ${value.value}, but wordcount notification hour must be between ${up_wordcount_notificationhour_min} and ${up_wordcount_notificationhour_max}`),settings_form.querySelector(`#${key}`).value=up_wordcount_notificationhour),value.value!=up_wordcount_notificationhour&&(up_wordcount_notificationhour=value.value,localStorage.setObject(key,value.value),setHasBeenNotified(!1))}function set_notifications_chat(key,value){value!=up_notifications_chats&&(up_notifications_chats=value.checked,localStorage.setObject(key,value.checked),destructNotifications(),setupNotifications())}function set_notifications_comment(key,value){value.checked!=up_notifications_comments&&(up_notifications_comments=value.checked,localStorage.setObject(key,value.checked),destructNotifications(),setupNotifications())}function set_notifications_comment_response(key,value){value.checked!=up_notifications_comment_threads&&(up_notifications_comment_threads=value.checked,localStorage.setObject(key,value.checked),destructNotifications(),setupNotifications())}function set_colormode_switching(key,value){value.checked!=up_colormode_switching&&(up_colormode_switching=value.checked,localStorage.setObject(key,value.checked),settings_form.querySelector("#overalltheme_dark").disabled=!up_colormode_switching,settings_form.querySelector("#overalltheme_light").disabled=!up_colormode_switching,settings_form.querySelector("#editortheme_dark").disabled=!up_colormode_switching,settings_form.querySelector("#editortheme_light").disabled=!up_colormode_switching,1==up_colormode_switching?setupColormode():destructColormode())}function themesetter(user_preference_variable_name,key,value){const user_preference_variable=eval(user_preference_variable_name);localStorage.setObject(key,value.value),value.value!=user_preference_variable&&(eval(`${user_preference_variable_name} = "${value.value}"`),switchColorMode())}function set_overalltheme_dark(key,value){themesetter("up_overalltheme_dark",key,value)}function set_overalltheme_light(key,value){themesetter("up_overalltheme_light",key,value)}function set_editortheme_dark(key,value){themesetter("up_editortheme_dark",key,value)}function set_editortheme_light(key,value){themesetter("up_editortheme_light",key,value)}const overallThemeToOverleaf={dark:"",light:"light-"};function switchColorMode(){let scope=angular.element("[ng-controller=SettingsController]").scope();scope&&("dark"==current_colorscheme_preference?(scope.settings.overallTheme=overallThemeToOverleaf[up_overalltheme_dark],scope.settings.editorTheme=up_editortheme_dark):"light"==current_colorscheme_preference?(scope.settings.overallTheme=overallThemeToOverleaf[up_overalltheme_light],scope.settings.editorTheme=up_editortheme_light):console.err(`current colorscheme preference ${current_colorscheme_preference} is not a valid value`),scope.$apply())}function autoChangeColorMode(event){current_colorscheme_preference=event.matches?"dark":"light",switchColorMode()}function setupColormode(){void 0!==colorscheme&&1==up_colormode_switching&&(switchColorMode(),colorscheme.addEventListener("change",autoChangeColorMode,!0))}function destructColormode(){void 0!==colorscheme&&0==up_colormode_switching&&colorscheme.removeEventListener("change",autoChangeColorMode,!0)}function sendNotification(text){new Notification(`${text}`),updateCounter(1)}function setupNotifications(){if(1==up_notifications&&1==(1==up_notifications_chats||1==up_notifications_comments||1==up_notifications_comment_threads)){if("Notification"in window?"granted"===Notification.permission||"denied"!==Notification.permission&&Notification.requestPermission((function(permission){"granted"===permission&&sendNotification("Notifications are now enabled")})):alert("This browser does not support notifications"),addEventListener("focus",resetCounter),1==up_notifications_comments){let comments_scope=angular.element("[ng-controller=ReviewPanelController]").scope();if(comments_scope){if(void 0!==comments_watcher_unbind)throw"comments_watcher_unbind should be undefined at this point";comments_watcher_unbind=comments_scope.$watch("reviewPanel.commentThreads",(function(newVal,oldVal){const diffs=deepDiffMapper.map(oldVal,newVal);for(const diff_key in diffs){let payload=diffs[diff_key];if(payload.resolved&&payload.resolved_at&&payload.resolved_by_user){const user=payload.resolved_by_user.updated;new Date(payload.resolved_at.updated)>lastNotificationResetTimestamp&&!user.isSelf&&sendNotification(`${user.name} resolved a comment`)}let actionText="responded to a comment";payload.updated&&(payload=payload.updated,actionText="commented");const messages=payload.messages;for(const message_index in messages){let message=messages[message_index];message.updated&&(message=message.updated,!up_notifications_comment_threads)||message.timestamp>lastNotificationResetTimestamp&&message.user&&message.content&&!message.user.isSelf&&sendNotification(`${message.user.name} ${actionText}: ${message.content}`)}}}),!0)}}if(1==up_notifications_chats){let chat_scope=angular.element('[class="infinite-scroll messages"]').children().children();chat_scope&&chat_scope.length&&chat_scope[1]&&(void 0===chat_observer&&(chat_observer=new MutationObserver((function(mutations){if(mutations.length&&(mutations=mutations[mutations.length-1]),Date.now()>lastNotificationResetTimestamp+2e3)for(const message_index in mutations.addedNodes)message=mutations.addedNodes[message_index],message.getElementsByClassName&&(wrapper=message.getElementsByClassName("message-wrapper")[0],wrapper.getElementsByClassName("name").length&&(sendername=wrapper.getElementsByClassName("name")[0].getElementsByTagName("span")[0].innerHTML,contents=wrapper.getElementsByClassName("message")[0].getElementsByClassName("message-content"),last_texts=contents[contents.length-1].getElementsByTagName("p"),last_text=last_texts[last_texts.length-1].innerHTML,sendNotification(`${sendername} in chat: ${last_text}`)))}))),chat_observer.observe(chat_scope[1],{childList:!0,subtree:!0}))}}}function destructNotifications(){void 0!==comments_watcher_unbind&&(comments_watcher_unbind(),comments_watcher_unbind=void 0),void 0!==chat_observer&&chat_observer.disconnect(),removeEventListener("focus",resetCounter)}function updateCounter(countToAdd){if(notificationCounter+=countToAdd,notificationCounter<=0)return resetCounter();const replaceOldCounter=/^(\(\d*\))\W/;replaceOldCounter.test(document.title)?document.title=document.title.replace(replaceOldCounter,`(${notificationCounter}) `):document.title=`(${notificationCounter}) ${originalDocumentTitle}`}function resetCounter(event){notificationCounter=0,document.title=originalDocumentTitle,lastNotificationResetTimestamp=Date.now()}function addCSS(){let styleSheet=document.createElement("style");styleSheet.innerText='\n .native-overleaf-settings {\n display: inline-block;\n width: 260px;\n }\n\n .settings-toggle {\n cursor: pointer;\n display: inline-block;\n }\n .settings-toggle-switch {\n display: inline-block;\n background: #2e3644;\n border-radius: 16px;\n width: 58px;\n height: 32px;\n position: relative;\n vertical-align: middle;\n transition: background 0.25s;\n }\n .settings-toggle-switch:before, .settings-toggle-switch:after {\n content: "";\n }\n .settings-toggle-switch:before {\n display: block;\n background: linear-gradient(to bottom, #fff 0%, #eee 100%);\n border-radius: 50%;\n box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.25);\n width: 24px;\n height: 24px;\n position: absolute;\n top: 4px;\n left: 4px;\n transition: left 0.25s;\n }\n .settings-toggle:hover .settings-toggle-switch:before {\n background: linear-gradient(to bottom, #fff 0%, #fff 100%);\n box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.5);\n }\n .settings-toggle-checkbox:checked + .settings-toggle-switch {\n background: #408827;\n }\n .settings-toggle-checkbox:checked + .settings-toggle-switch:before {\n left: 30px;\n }\n .settings-toggle-checkbox {\n position: absolute;\n visibility: hidden;\n }\n .settings-toggle-label {\n margin-left: 5px;\n position: relative;\n top: 2px;\n }\n dialog {\n width: 80vw;\n background: #EEEFEE;\n color: black;\n border-color: #E9E9E9;\n margin: auto;\n position: fixed;\n box-shadow: 5px;\n }\n dialog::backdrop {\n background: black;\n opacity: 0.7;\n backdrop-filter: blur(25px);\n }\n \n @media (prefers-color-scheme: dark) {\n dialog {\n background: #282A35;\n color: white;\n border-color: #485263;\n }\n #wordcountchart {\n filter: invert(1) hue-rotate(180deg);\n }\n }\n ',document.head.appendChild(styleSheet)}async function fetchAsync(url){let response=await fetch(url);return await response.json()}function semanticVersionCompare(a,b){return a.startsWith(b+"-")?-1:b.startsWith(a+"-")?1:a.localeCompare(b,void 0,{numeric:!0,sensitivity:"case",caseFirst:"upper"})}async function checkForUpdate(reportAll=!1){const tags=await fetchAsync("https://api.github.com/repos/fjwillemsen/NativeOverleaf/tags");if(!tags.length||void 0===tags.length)return void console.error("Can not retrieve latest version for update checking");const latest_version=tags[0].name.replace("v",""),comparison=semanticVersionCompare(latest_version,appversion);if(0==comparison&&""!==comparison)console.log("Update check completed, no update available."),1==reportAll&&alert("You're up to date with the latest version!");else if(1==comparison){confirm(`Update available! \n Current: ${appversion}, latest: ${latest_version}.\n Go to downloads page?`)&&window.open("https://github.com/fjwillemsen/NativeOverleaf/releases/latest/")}else if(-1==comparison){const result_text=`No update needed, current version (${appversion}) is newer than latest publicly available version (${latest_version}).`;console.log(result_text),1==reportAll&&alert(result_text)}else{const result_text=`Invalid semantic version comparison outcome: ${comparison}`;console.log(result_text),1==reportAll&&alert(result_text)}}function setAutoUpdateChecking(){checkForUpdate(),setInterval(checkForUpdate,216e5),document.querySelector("#versionlabel")&&(document.querySelector("#versionlabel").onclick=function(){checkForUpdate(!0)})}let wordcount_timer_id,compilation_observer,wordcounts;async function waitUntilPDFCompiled(){return await recursiveCheckAndWait(isPDFLinkAvailable,500,5,!0)}function extractWordCount(){const modal=document.getElementById("clone-project-modal");if(modal&&void 0!==modal){const modaltext=modal.outerText,wordcount=modaltext.substring(modaltext.lastIndexOf("\nTotal Words:\n")+14,modaltext.lastIndexOf("\nHeaders:")),parsedWordCount=parseInt(wordcount);if(0==isNaN(parsedWordCount))return parsedWordCount}return!1}async function getWordCount(){let wordcount_el=angular.element("[ng-controller=WordCountModalController]");if(wordcount_el&&void 0!==wordcount_el&&void 0!==wordcount_el.scope){let wordcount_scope=wordcount_el.scope();if(void 0!==wordcount_scope&&1==await waitUntilPDFCompiled()){wordcount_scope.openWordCountModal();const wordcount=await recursiveCheckAndWait(extractWordCount,50,100);return wordcount_scope.handleHide(),0==wordcount?void console.warn("Unable to get wordcount within 5 seconds, skipping"):wordcount}}}function getWordCounts(){let wordcounts=localStorage.getObject("wordcounts")||{};this.project_id in wordcounts||(wordcounts[this.project_id]={});const currentdate=getLocalDate();return currentdate in wordcounts[this.project_id]||(wordcounts[this.project_id][currentdate]={earliest:void 0,latest:void 0,hasbeennotified:!1}),wordcounts}function resetWordCounts(){return wordcounts=void 0,localStorage.removeItem("wordcounts")}async function updateWordCount(){wordcounts=getWordCounts();const currentdate=getLocalDate(),wordcount=await getWordCount(),hasbeennotified=wordcounts[this.project_id][currentdate].hasbeennotified;if(void 0===wordcount)return;void 0===wordcounts[this.project_id][currentdate].earliest&&(wordcounts[this.project_id][currentdate].earliest=wordcounts[this.project_id][currentdate].latest||wordcount),wordcounts[this.project_id][currentdate].latest=wordcount;const achieved_wordcount=wordcount-wordcounts[this.project_id][currentdate].earliest;if(0==hasbeennotified&&up_wordcount_dailytarget>0&&achieved_wordcount>=up_wordcount_dailytarget&&(new Notification("Awesome, already met today's target!",{body:`You wrote ${achieved_wordcount} words, ${achieved_wordcount-up_wordcount_dailytarget} above target!`}),wordcounts[this.project_id][currentdate].hasbeennotified=!0),0==hasbeennotified&&up_wordcount_notificationhour>-1){(new Date).getHours()==up_wordcount_notificationhour&&(up_wordcount_dailytarget<=0?new Notification(`You wrote ${achieved_wordcount} out of ${up_wordcount_dailytarget} words today.`):achieved_wordcount0)return backup_source_html.getElementsByTagName("a")[0]}return!1}function getBackupLink(backup_type_index){const backup_element=getBackupElement(backup_type_index);return""!=backup_element?backup_element.href:""}function isPDFLinkAvailable(){return getBackupElement(1)}function doBackup(){getBackupLink(up_backup_type)}let wordcountchart_show_net_wordcount=!0;async function getChartJS(){return $.ajaxSetup({cache:!0}),$.when($.getScript("https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.9.1/chart.min.js")).done((()=>{lib_chartjs_loaded=!0})).fail((()=>{alert("Unable to dynamically load ChartJS, do you have an active internet connection?")}))}function injectWordCountChartElement(){document.querySelector("#chat-wrapper").insertAdjacentHTML("afterend",'');const dialog=document.querySelector("#wordcountchartdialog");return dialog.addEventListener("click",(function(event){const rect=dialog.getBoundingClientRect();(event.clientYrect.bottom||event.clientXrect.right)&&dialog.close()})),document.getElementById("show_net_wordcount").checked=wordcountchart_show_net_wordcount,document.getElementById("show_net_wordcount").addEventListener("change",(()=>{wordcountchart_show_net_wordcount=document.getElementById("show_net_wordcount").checked,updateWordCountChartData()})),dialog}function getWordCountChartConfig(){let labels=[],counts=[];const label=1==wordcountchart_show_net_wordcount?"Net number of words written":"Total number of words",wordcounts_project=wordcounts[this.project_id];(null==wordcounts||Object.keys(wordcounts).length<=0)&&alert("Wordcounts have not been tracked, enable wordcount tracking and reload the project");for(const[date,wordcount]of Object.entries(wordcounts_project)){labels.push(date);const count=1==wordcountchart_show_net_wordcount?wordcount.latest-wordcount.earliest:wordcount.latest;counts.push(count)}let config={type:"bar",data:{labels:labels,datasets:[]},options:{}};return 1==wordcountchart_show_net_wordcount&&up_wordcount_dailytarget>0&&config.data.datasets.push({label:"Daily target",data:Array(labels.length).fill(up_wordcount_dailytarget),type:"line",backgroundColor:"red",borderColor:"red"}),config.data.datasets.push({label:label,data:counts,backgroundColor:"#408827"}),config}function updateWordCountChartData(){const config=getWordCountChartConfig();wordcountchart.data.labels=config.data.labels,wordcountchart.data.datasets=config.data.datasets,wordcountchart.update()}async function showWordCountChart(){await getChartJS(),null==wordcountchartdialog&&(wordcountchartdialog=injectWordCountChartElement(),wordcountchart=new Chart(document.getElementById("wordcountchart"),getWordCountChartConfig())),wordcountchartdialog.showModal()}function hideWordCountChart(){wordcountchartdialog.close()}const startTime=performance.now();setupColormode(),setupNotifications(),setupPreferencesPane(),addCSS(),setAutoUpdateChecking(),setupWordCount();const endTime=performance.now();console.log(`Native Overleaf injected setup took ${endTime-startTime} milliseconds`);
\ No newline at end of file