index.js000644 0000074177 14714563747007413 0ustar00000000 000000 (()=>{var e={181:e=>{var t=/^\s+|\s+$/g,i=/^[-+]0x[0-9a-f]+$/i,n=/^0b[01]+$/i,s=/^0o[0-7]+$/i,o=parseInt,a="object"==typeof global&&global&&global.Object===Object&&global,r="object"==typeof self&&self&&self.Object===Object&&self,l=a||r||Function("return this")(),d=Object.prototype.toString,u=Math.max,c=Math.min,p=function(){return l.Date.now()};function m(e){var t=typeof e;return!!e&&("object"==t||"function"==t)}function g(e){if("number"==typeof e)return e;if(function(e){return"symbol"==typeof e||function(e){return!!e&&"object"==typeof e}(e)&&"[object Symbol]"==d.call(e)}(e))return NaN;if(m(e)){var a="function"==typeof e.valueOf?e.valueOf():e;e=m(a)?a+"":a}if("string"!=typeof e)return 0===e?e:+e;e=e.replace(t,"");var r=n.test(e);return r||s.test(e)?o(e.slice(2),r?2:8):i.test(e)?NaN:+e}e.exports=function(e,t,i){var n,s,o,a,r,l,d=0,f=!1,h=!1,y=!0;if("function"!=typeof e)throw new TypeError("Expected a function");function v(t){var i=n,o=s;return n=s=void 0,d=t,a=e.apply(o,i)}function T(e){var i=e-l;return void 0===l||i>=t||i<0||h&&e-d>=o}function S(){var e=p();if(T(e))return k(e);r=setTimeout(S,function(e){var i=t-(e-l);return h?c(i,o-(e-d)):i}(e))}function k(e){return r=void 0,y&&n?v(e):(n=s=void 0,a)}function N(){var e=p(),i=T(e);if(n=arguments,s=this,l=e,i){if(void 0===r)return function(e){return d=e,r=setTimeout(S,t),f?v(e):a}(l);if(h)return r=setTimeout(S,t),v(l)}return void 0===r&&(r=setTimeout(S,t)),a}return t=g(t)||0,m(i)&&(f=!!i.leading,o=(h="maxWait"in i)?u(g(i.maxWait)||0,t):o,y="trailing"in i?!!i.trailing:y),N.cancel=function(){void 0!==r&&clearTimeout(r),d=0,n=l=s=r=void 0},N.flush=function(){return void 0===r?a:k(p())},N}},998:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=joplin},143:(e,t)=>{"use strict";var i,n,s,o,a,r,l,d,u,c;Object.defineProperty(t,"__esModule",{value:!0}),t.ContentScriptType=t.SettingStorage=t.AppType=t.SettingItemSubType=t.SettingItemType=t.ToolbarButtonLocation=t.isContextMenuItemLocation=t.MenuItemLocation=t.ModelType=t.ImportModuleOutputFormat=t.FileSystemItem=void 0,(c=t.FileSystemItem||(t.FileSystemItem={})).File="file",c.Directory="directory",(u=t.ImportModuleOutputFormat||(t.ImportModuleOutputFormat={})).Markdown="md",u.Html="html",(d=t.ModelType||(t.ModelType={}))[d.Note=1]="Note",d[d.Folder=2]="Folder",d[d.Setting=3]="Setting",d[d.Resource=4]="Resource",d[d.Tag=5]="Tag",d[d.NoteTag=6]="NoteTag",d[d.Search=7]="Search",d[d.Alarm=8]="Alarm",d[d.MasterKey=9]="MasterKey",d[d.ItemChange=10]="ItemChange",d[d.NoteResource=11]="NoteResource",d[d.ResourceLocalState=12]="ResourceLocalState",d[d.Revision=13]="Revision",d[d.Migration=14]="Migration",d[d.SmartFilter=15]="SmartFilter",d[d.Command=16]="Command",function(e){e.File="file",e.Edit="edit",e.View="view",e.Note="note",e.Tools="tools",e.Help="help",e.Context="context",e.NoteListContextMenu="noteListContextMenu",e.EditorContextMenu="editorContextMenu",e.FolderContextMenu="folderContextMenu",e.TagContextMenu="tagContextMenu"}(i=t.MenuItemLocation||(t.MenuItemLocation={})),t.isContextMenuItemLocation=function(e){return[i.Context,i.NoteListContextMenu,i.EditorContextMenu,i.FolderContextMenu,i.TagContextMenu].includes(e)},(l=t.ToolbarButtonLocation||(t.ToolbarButtonLocation={})).NoteToolbar="noteToolbar",l.EditorToolbar="editorToolbar",(r=t.SettingItemType||(t.SettingItemType={}))[r.Int=1]="Int",r[r.String=2]="String",r[r.Bool=3]="Bool",r[r.Array=4]="Array",r[r.Object=5]="Object",r[r.Button=6]="Button",(a=t.SettingItemSubType||(t.SettingItemSubType={})).FilePathAndArgs="file_path_and_args",a.FilePath="file_path",a.DirectoryPath="directory_path",(o=t.AppType||(t.AppType={})).Desktop="desktop",o.Mobile="mobile",o.Cli="cli",(s=t.SettingStorage||(t.SettingStorage={}))[s.Database=1]="Database",s[s.File=2]="File",(n=t.ContentScriptType||(t.ContentScriptType={})).MarkdownItPlugin="markdownItPlugin",n.CodeMirrorPlugin="codeMirrorPlugin"},156:function(e,t,i){"use strict";var n=this&&this.__awaiter||function(e,t,i,n){return new(i||(i=Promise))((function(s,o){function a(e){try{l(n.next(e))}catch(e){o(e)}}function r(e){try{l(n.throw(e))}catch(e){o(e)}}function l(e){var t;e.done?s(e.value):(t=e.value,t instanceof i?t:new i((function(e){e(t)}))).then(a,r)}l((n=n.apply(e,t||[])).next())}))};Object.defineProperty(t,"__esModule",{value:!0});const s=i(998),o=i(143),a=i(180),r=i(751),l=i(451);s.default.plugins.register({onStart:function(){return n(this,void 0,void 0,(function*(){yield(0,l.registerSettings)();const e=yield(0,l.getLogNoteTag)(),t=yield(0,l.getDefaultNoteId)(),i=yield s.default.views.panels.create("timeSlipPanel");yield s.default.views.panels.setHtml(i,'\n
\n
\n \n \n \n
\n
\n \n \n
\n
\n
\n
\n
\n Completed Tasks\n
\n
\n
\n
\n \n \n
\n \n
\n
\n \n
\n '),yield s.default.views.panels.addScript(i,"timeTracker.css"),yield s.default.views.panels.addScript(i,"timeTracker.js");let d=t;const u=new r.NoteManager(s.default,d,i),c=new a.TaskManager(s.default,i,d,u);u.setTaskManager(c),yield c.setLogNoteTag(e),d&&(yield u.setNoteId(d),yield c.setNoteId(d)),yield s.default.workspace.onSyncComplete((()=>n(this,void 0,void 0,(function*(){return yield c.scanNoteAndUpdateTasks()})))),yield s.default.workspace.onNoteChange(u.handleNoteChange),yield s.default.workspace.onNoteSelectionChange(u.handleNoteSelectionChange),yield s.default.commands.register({name:"timeslip.togglePanel",label:"Toggle Time Slip panel",iconName:"fas fa-stopwatch",execute:()=>n(this,void 0,void 0,(function*(){(yield s.default.views.panels.visible(i))?yield s.default.views.panels.hide(i):yield s.default.views.panels.show(i)}))}),yield s.default.views.menuItems.create("timeslip.togglePanel","timeslip.togglePanel",o.MenuItemLocation.View),yield s.default.commands.register({name:"timeslip.sortTimeLog",label:"Sort Time Slip log",iconName:"fas fa-sort",execute:()=>n(this,void 0,void 0,(function*(){d?(yield c.updateEnforceSorting(!0),yield c.scanNoteAndUpdateTasks(),yield c.updateEnforceSorting()):yield s.default.views.dialogs.showMessageBox("Please select a time log note first.")}))}),yield s.default.views.menuItems.create("timeslip.sortTimeLog","timeslip.sortTimeLog",o.MenuItemLocation.Tools),yield s.default.commands.register({name:"timeslip.insertLogMarkdown",label:"Insert Time Slip markdown log",iconName:"fas fa-table",execute:()=>n(this,void 0,void 0,(function*(){if(d){const e=yield u.exportNote();e?(yield s.default.commands.execute("editor.focus"),yield s.default.commands.execute("editor.execCommand",{name:"replaceSelection",args:[e]})):yield s.default.views.dialogs.showMessageBox("Failed to render time slip.")}else yield s.default.views.dialogs.showMessageBox("Please select a time log note first.")}))}),yield s.default.views.menuItems.create("timeslip.insertLogMarkdown","timeslip.insertLogMarkdown",o.MenuItemLocation.Note),yield s.default.commands.register({name:"timeslip.insertSummaryMarkdown",label:"Insert Time Slip markdown summary",iconName:"fas fa-markdown",execute:()=>n(this,void 0,void 0,(function*(){d?yield s.default.views.panels.postMessage(i,{name:"requestSummaryMarkdown"}):yield s.default.views.dialogs.showMessageBox("Please select a time log note first.")}))}),yield s.default.views.menuItems.create("timeslip.insertSummaryMarkdown","timeslip.insertSummaryMarkdown",o.MenuItemLocation.Note),yield s.default.commands.register({name:"timeslip.copySummaryCSV",label:"Copy Time Slip CSV summary",iconName:"fas fa-clipboard",execute:()=>n(this,void 0,void 0,(function*(){d?yield s.default.views.panels.postMessage(i,{name:"requestSummaryCSV"}):yield s.default.views.dialogs.showMessageBox("Please select a time log note first.")}))}),yield s.default.views.menuItems.create("timeslip.copySummaryCSV","timeslip.copySummaryCSV",o.MenuItemLocation.Tools),yield s.default.commands.register({name:"timeslip.convertSelectionToCSV",label:"Convert selected table to CSV",iconName:"fas fa-table",execute:()=>n(this,void 0,void 0,(function*(){const e=yield s.default.commands.execute("selectedText");if(!e)return void(yield s.default.views.dialogs.showMessageBox("Please select a markdown table first."));const t=(0,r.convertMarkdownTableToCSV)(e);t?(yield s.default.commands.execute("editor.focus"),yield s.default.commands.execute("editor.execCommand",{name:"replaceSelection",args:[t]})):yield s.default.views.dialogs.showMessageBox("Failed to convert the selected text to CSV. Make sure it's a valid markdown table.")}))}),yield s.default.views.menuItems.create("timeslip.convertSelectionToCSV","timeslip.convertSelectionToCSV",o.MenuItemLocation.Tools),yield s.default.settings.onChange((e=>n(this,void 0,void 0,(function*(){if(e.keys.includes("timeslip.logNoteTag")){const e=yield s.default.settings.value("timeslip.logNoteTag");yield c.setLogNoteTag(e),d=""}if(e.keys.includes("timeslip.summarySortOrder")){const e=yield(0,l.getSummarySortOrder)();yield c.updateSummarySortOrder(e)}e.keys.includes("timeslip.logSortOrder")&&(yield c.updateLogSortOrder(),yield c.scanNoteAndUpdateTasks()),e.keys.includes("timeslip.enforceLogSort")&&(yield c.updateEnforceSorting(),yield c.scanNoteAndUpdateTasks())})))),yield s.default.views.panels.onMessage(i,(e=>n(this,void 0,void 0,(function*(){if("changeNote"===e.name)d=e.noteId,yield u.setNoteId(d),yield c.setNoteId(d),d?(yield c.setDateRange(e.startDate,e.endDate),(0,l.setCurrentDateRange)(e.startDate,e.endDate),yield c.scanNoteAndUpdateTasks(),yield(0,l.setDefaultNoteId)(d)):(yield c.clearTasks(),yield(0,l.setDefaultNoteId)(""));else if("start"===e.name)d?yield c.startTask(e.taskName,e.projectName):yield s.default.views.panels.postMessage(i,{name:"error",message:"Please select a note first."});else if("stop"===e.name)d?yield c.stopTask(e.taskName,e.projectName):console.error("No note selected. Cannot stop task.");else if("requestInitialData"===e.name){const e=yield c.getInitialData(),t=yield(0,l.getCurrentDateRange)(),n=yield(0,l.getAggregationLevel)();yield s.default.views.panels.postMessage(i,Object.assign(Object.assign({name:"initialData"},e),{currentDateRange:t,aggregationLevel:n}))}else if("applyDateFilter"===e.name)d?(yield c.setDateRange(e.startDate,e.endDate),(0,l.setCurrentDateRange)(e.startDate,e.endDate),yield c.scanNoteAndUpdateTasks()):yield s.default.views.panels.postMessage(i,{name:"error",message:"Please select a note first."});else if("getDefaultDateRange"===e.name){const e=yield(0,l.getCurrentDateRange)();yield s.default.views.panels.postMessage(i,Object.assign({name:"defaultDateRange"},e))}else"setAggregationLevel"===e.name?yield(0,l.setAggregationLevel)(e.level):"openNote"===e.name?e.noteId&&(yield s.default.commands.execute("openNote",e.noteId)):"changeSortOrder"===e.name?d?(yield c.updateSummarySortOrder(e.sortBy),yield s.default.settings.setValue("timeslip.summarySortOrder",e.sortBy),yield c.scanNoteAndUpdateTasks()):yield s.default.views.panels.postMessage(i,{name:"error",message:"Please select a note first."}):"summaryCSV"===e.name?(yield s.default.clipboard.writeText(e.content),yield s.default.views.dialogs.showMessageBox("Summary table has been copied to clipboard.")):"summaryMarkdown"===e.name&&(yield s.default.commands.execute("editor.focus"),yield s.default.commands.execute("editor.execCommand",{name:"replaceSelection",args:[e.content]}))}))))}))}})},751:function(e,t,i){"use strict";var n=this&&this.__awaiter||function(e,t,i,n){return new(i||(i=Promise))((function(s,o){function a(e){try{l(n.next(e))}catch(e){o(e)}}function r(e){try{l(n.throw(e))}catch(e){o(e)}}function l(e){var t;e.done?s(e.value):(t=e.value,t instanceof i?t:new i((function(e){e(t)}))).then(a,r)}l((n=n.apply(e,t||[])).next())}))};Object.defineProperty(t,"__esModule",{value:!0}),t.convertMarkdownTableToCSV=t.NoteManager=void 0;const s=i(185);t.NoteManager=class{constructor(e,t,i){this.handleNoteChange=e=>n(this,void 0,void 0,(function*(){let e=yield this.joplin.workspace.selectedNote();e&&e.id===this.noteId&&this.taskManager.debouncedScanAndUpdate(),e=(0,s.clearNoteReferences)(e)})),this.handleNoteSelectionChange=()=>n(this,void 0,void 0,(function*(){yield this.taskManager.getLogNotes()})),this.joplin=e,this.noteId=t,this.panel=i}setTaskManager(e){this.taskManager=e}setNoteId(e){this.noteId=e}updateNote(e){return n(this,void 0,void 0,(function*(){let t;try{yield this.joplin.data.put(["notes",this.noteId],null,{body:e}),t=yield this.joplin.workspace.selectedNote(),t&&t.id===this.noteId&&(yield this.joplin.commands.execute("editor.setText",e))}catch(e){console.error("Failed to update note:",e),this.joplin.views.panels.postMessage(this.panel,{name:"error",message:"Failed to update note."})}finally{t=(0,s.clearNoteReferences)(t)}}))}exportNote(){return n(this,void 0,void 0,(function*(){try{const e=(yield this.joplin.data.get(["notes",this.noteId],{fields:["body"]})).body.split("\n");if(e.length<2)return"The note is empty or contains only a header.";const t=e[0].split(",");let i=`| ${t.join(" | ")} |\n| ${t.map((()=>"---")).join(" | ")} |\n`;for(let n=1;ne.trim()));for(;s.lengthe.replace(/^\||\|$/g,"").split("|").map((e=>{const t=e.trim();return t.includes(",")?`"${t}"`:t})).join(","))).join("\n"))}},451:function(e,t,i){"use strict";var n=this&&this.__awaiter||function(e,t,i,n){return new(i||(i=Promise))((function(s,o){function a(e){try{l(n.next(e))}catch(e){o(e)}}function r(e){try{l(n.throw(e))}catch(e){o(e)}}function l(e){var t;e.done?s(e.value):(t=e.value,t instanceof i?t:new i((function(e){e(t)}))).then(a,r)}l((n=n.apply(e,t||[])).next())}))};Object.defineProperty(t,"__esModule",{value:!0}),t.setCurrentDateRange=t.getCurrentDateRange=t.setEnforceSorting=t.getEnforceSorting=t.setLogSortOrder=t.getLogSortOrder=t.setSummarySortOrder=t.getSummarySortOrder=t.setAggregationLevel=t.getAggregationLevel=t.getDefaultDateRange=t.setDefaultNoteId=t.getDefaultNoteId=t.getLogNoteTag=t.registerSettings=void 0;const s=i(998),o=i(143);function a(){return n(this,void 0,void 0,(function*(){return yield s.default.settings.value("timeslip.defaultDateRange")}))}t.registerSettings=function(){return n(this,void 0,void 0,(function*(){yield s.default.settings.registerSection("timeslip",{label:"Time Slip",iconName:"fas fa-stopwatch"}),yield s.default.settings.registerSettings({"timeslip.logNoteTag":{value:"time-slip",type:o.SettingItemType.String,section:"timeslip",public:!0,label:"Time log tag",description:"Tag for notes that contain time tracking logs. Default: time-slip"},"timeslip.defaultNoteId":{value:"",type:o.SettingItemType.String,section:"timeslip",public:!0,label:"Default time log note ID"},"timeslip.defaultDateRange":{value:7,minimum:1,maximum:365,step:1,type:o.SettingItemType.Int,section:"timeslip",public:!0,label:"Default date range (days)",description:"The default last number of days of completed tasks to display. Default: 7"},"timeslip.aggregationLevel":{value:1,type:o.SettingItemType.Int,section:"timeslip",public:!0,isEnum:!0,label:"Aggregation level",description:"For summarising completed tasks",options:{1:"Task",2:"Project",3:"Note"}},"timeslip.summarySortOrder":{value:"duration",type:o.SettingItemType.String,section:"timeslip",public:!0,isEnum:!0,label:"Sort completed tasks by",options:{duration:"Duration",endTime:"End Time",name:"Name"}},"timeslip.logSortOrder":{value:"ascending",type:o.SettingItemType.String,section:"timeslip",public:!0,isEnum:!0,label:"Order of time logs",description:"Sort order for tasks in the time log based on start time",options:{ascending:"Ascending",descending:"Descending"}},"timeslip.enforceLogSort":{value:!1,type:o.SettingItemType.Bool,section:"timeslip",public:!0,label:"Auto-sort time logs",description:"Automatically sort tasks in time log notes based on start time"}})}))},t.getLogNoteTag=function(){return n(this,void 0,void 0,(function*(){return yield s.default.settings.value("timeslip.logNoteTag")}))},t.getDefaultNoteId=function(){return n(this,void 0,void 0,(function*(){return yield s.default.settings.value("timeslip.defaultNoteId")}))},t.setDefaultNoteId=function(e){return n(this,void 0,void 0,(function*(){yield s.default.settings.setValue("timeslip.defaultNoteId",e)}))},t.getDefaultDateRange=a,t.getAggregationLevel=function(){return n(this,void 0,void 0,(function*(){return yield s.default.settings.value("timeslip.aggregationLevel")}))},t.setAggregationLevel=function(e){return n(this,void 0,void 0,(function*(){yield s.default.settings.setValue("timeslip.aggregationLevel",e)}))},t.getSummarySortOrder=function(){return n(this,void 0,void 0,(function*(){return yield s.default.settings.value("timeslip.summarySortOrder")}))},t.setSummarySortOrder=function(e){return n(this,void 0,void 0,(function*(){yield s.default.settings.setValue("timeslip.summarySortOrder",e)}))},t.getLogSortOrder=function(){return n(this,void 0,void 0,(function*(){return yield s.default.settings.value("timeslip.logSortOrder")}))},t.setLogSortOrder=function(e){return n(this,void 0,void 0,(function*(){yield s.default.settings.setValue("timeslip.logSortOrder",e)}))},t.getEnforceSorting=function(){return n(this,void 0,void 0,(function*(){return yield s.default.settings.value("timeslip.enforceLogSort")}))},t.setEnforceSorting=function(e){return n(this,void 0,void 0,(function*(){yield s.default.settings.setValue("timeslip.enforceLogSort",e)}))};let r=null,l=null;t.getCurrentDateRange=function(){return n(this,void 0,void 0,(function*(){if(r&&l)return{startDate:r,endDate:l};{const e=yield a(),t=new Date,i=new Date;return i.setDate(i.getDate()-e+1),{startDate:i.toLocaleDateString("en-CA"),endDate:t.toLocaleDateString("en-CA")}}}))},t.setCurrentDateRange=function(e,t){r=e,l=t}},180:function(e,t,i){"use strict";var n=this&&this.__awaiter||function(e,t,i,n){return new(i||(i=Promise))((function(s,o){function a(e){try{l(n.next(e))}catch(e){o(e)}}function r(e){try{l(n.throw(e))}catch(e){o(e)}}function l(e){var t;e.done?s(e.value):(t=e.value,t instanceof i?t:new i((function(e){e(t)}))).then(a,r)}l((n=n.apply(e,t||[])).next())}))};Object.defineProperty(t,"__esModule",{value:!0}),t.TaskManager=void 0;const s=i(185),o=i(451),a=i(181);t.TaskManager=class{constructor(e,t,i,n){this.tasks={},this.uniqueTasks=[],this.uniqueProjects=[],this.completedTasks=[],this.logNotes=[],this.currentStartDate=null,this.currentEndDate=null,this.logNoteTag="time-slip",this.fieldIndices=null,this.defaultHeader="Project,Task,Start date,Start time,End date,End time,Duration",this.sortBy="duration",this.logSortOrder="ascending",this.enforceSorting=!0,this.joplin=e,this.panel=t,this.noteId=i,this.noteManager=n,this.initializeSortOrder(),this.debouncedScanAndUpdate=a(this.scanNoteAndUpdateTasks.bind(this),4e3),this.updateLogSortOrder(),this.updateEnforceSorting()}getTaskKey(e,t){return`${e}|${t}`}initialize(){return n(this,void 0,void 0,(function*(){yield this.scanNoteAndUpdateTasks()}))}updateRunningTasks(){this.joplin.views.panels.postMessage(this.panel,{name:"updateRunningTasks",tasks:this.tasks})}inferFieldIndices(e){const t=e.toLowerCase().split(",").map((e=>e.trim())),i={};return i.project=t.indexOf("project"),i.taskName=t.indexOf("task"),i.startDate=t.indexOf("start date"),i.startTime=t.indexOf("start time"),i.endDate=t.indexOf("end date"),i.endTime=t.indexOf("end time"),i.duration=t.indexOf("duration"),Object.values(i).some((e=>-1===e))?(console.error("Missing required fields in the header"),null):i}ensureNoteHasHeader(e){if(null!=e)return""===e.trim()&&(e=this.defaultHeader+"\n"),e}scanNoteAndUpdateTasks(){return n(this,void 0,void 0,(function*(){if(this.noteId)try{const e=yield this.scanNote();e&&(yield this.updateTasksAndNote(e))}catch(e){console.error("scanNoteAndUpdateTasks:",e),this.joplin.views.panels.postMessage(this.panel,{name:"error",message:"An error occurred while scanning or updating the note. Note ID: "+this.noteId})}else this.updateCompletedTasks([])}))}scanNote(){return n(this,void 0,void 0,(function*(){let e=yield this.joplin.data.get(["notes",this.noteId],{fields:["body"]});if(!e||void 0===e.body||null===e.body)return this.handleNoteError(e),null;const t=this.ensureNoteHasHeader(e.body).split("\n");return e=(0,s.clearNoteReferences)(e),this.fieldIndices=this.inferFieldIndices(t[0]),this.fieldIndices?this.processNoteLines(t):(this.joplin.views.panels.postMessage(this.panel,{name:"error",message:"Invalid header format"}),null)}))}processNoteLines(e){const t={},i={},n=new Set,o=new Set,a=[],r=[];let l=!1,d=!0,u="ascending"===this.logSortOrder?0:Number.MAX_SAFE_INTEGER;const c=this.currentStartDate?new Date(this.currentStartDate):null,p=this.currentEndDate?new Date(this.currentEndDate):null;c&&c.setHours(0,0,0,0),p&&p.setHours(23,59,59,999);for(let m=1;me.trim())),f=g[this.fieldIndices.project],h=g[this.fieldIndices.taskName],y=g[this.fieldIndices.startDate],v=g[this.fieldIndices.startTime],T=g[this.fieldIndices.endDate],S=g[this.fieldIndices.endTime],k=g[this.fieldIndices.duration];if(h&&n.add(h),f&&o.add(f),v){const n=new Date(`${y} ${v}`),o=n.getTime();if(this.enforceSorting&&("ascending"===this.logSortOrder&&ou)&&(d=!1),u=o,S){const t=new Date(`${T} ${S}`),o=t.getTime()-n.getTime(),a=(0,s.formatDuration)(o);if(a!==k&&(g[this.fieldIndices.duration]=a,e[m]=g.join(","),l=!0),this.isTaskInDateRange(n,c,p)){const e=this.getTaskKey(h,f);e in i?(i[e].duration+=o,i[e].startTime=Math.min(i[e].startTime,n.getTime()),i[e].endTime=Math.max(i[e].endTime,t.getTime())):i[e]={taskName:h,project:f,duration:o,startTime:n.getTime(),endTime:t.getTime()}}}else t[this.getTaskKey(h,f)]={startTime:n.getTime(),project:f};a.push({index:m,startTime:o,line:e[m]})}else r.push({index:m,line:e[m]})}return{openTasks:t,completedTasks:i,tasksSet:n,projectsSet:o,sortableTasks:a,unknownTasks:r,durationChanged:l,isSorted:d,lines:e}}updateTasksAndNote(e){return n(this,void 0,void 0,(function*(){const{openTasks:t,completedTasks:i,tasksSet:n,projectsSet:s,sortableTasks:o,unknownTasks:a,durationChanged:r,isSorted:l,lines:d}=e;if(!l||r){const e=yield this.getUpdatedNoteContent(o,a,d,l,r);e&&(yield this.noteManager.updateNote(e))}this.tasks=t,this.updateRunningTasks(),this.updateCompletedTasks(Object.values(i)),this.updateAutocompleteLists(Array.from(n),Array.from(s)),yield this.getLogNotes()}))}getUpdatedNoteContent(e,t,i,s,o){return n(this,void 0,void 0,(function*(){if(!s){e.sort(((e,t)=>{const i=e.startTime-t.startTime;return"ascending"===this.logSortOrder?i:-i}));const n=i[0],s=e.map((e=>e.line)),o=[n];let a=0,r=0;for(let e=1;e=t:!!i&&e<=i)}getLogNotes(){return n(this,void 0,void 0,(function*(){const e=(yield this.joplin.data.get(["search"],{query:this.logNoteTag,fields:"id,title",type:"tag"})).items;if(e.length>0){this.logNotes=[];for(const t of e){let e=!0;for(;e;){const i=yield this.joplin.data.get(["tags",t.id,"notes"],{fields:["id","title"]});this.logNotes=this.logNotes.concat(i.items),e=i.has_more}}this.updateLogNotes()}else console.error(`No ${this.logNoteTag} tag found`),this.logNotes=[],this.updateLogNotes();return this.logNotes}))}updateAutocompleteLists(e,t){this.joplin.views.panels.postMessage(this.panel,{name:"updateAutocompleteLists",tasks:e,projects:t})}updateCompletedTasks(e){this.joplin.views.panels.postMessage(this.panel,{name:"updateCompletedTasks",tasks:e})}startTask(e,t){return n(this,void 0,void 0,(function*(){if(!this.noteId)return void this.joplin.views.panels.postMessage(this.panel,{name:"error",message:"Please select a note first."});if(this.fieldIndices||(yield this.scanNoteAndUpdateTasks()),!this.fieldIndices)return void console.error("Field indices not initialized");const i=this.getTaskKey(e,t);if(this.tasks[i])this.joplin.views.panels.postMessage(this.panel,{name:"error",message:`Task "${e}" for project "${t}" is already running.`});else{const n=new Date;this.tasks[i]={startTime:n.getTime(),project:t},this.updateRunningTasks();let o=yield this.joplin.data.get(["notes",this.noteId],{fields:["body"]}),a=o.body.trim();o=(0,s.clearNoteReferences)(o),a||(a=this.defaultHeader);const r=Math.max(...Object.values(this.fieldIndices)),l=new Array(r+1).fill("");l[this.fieldIndices.project]=t,l[this.fieldIndices.taskName]=e,l[this.fieldIndices.startDate]=(0,s.formatDate)(n),l[this.fieldIndices.startTime]=(0,s.formatTime)(n),"ascending"===this.logSortOrder?a+="\n"+l.join(","):(a=a.split("\n"),a.splice(1,0,l.join(",")),a=a.join("\n")),yield this.noteManager.updateNote(a),yield this.scanNoteAndUpdateTasks()}}))}stopTask(e,t){return n(this,void 0,void 0,(function*(){if(!this.noteId)return void console.error("No note selected. Cannot stop task.");if(!this.fieldIndices)return void console.error("Field indices not initialized");const i=this.getTaskKey(e,t);if(!this.tasks[i])return void console.error(`Task "${e}" for project "${t}" not found`);const{startTime:n}=this.tasks[i],o=new Date,a=o.getTime()-n;delete this.tasks[i],this.updateRunningTasks();let r=yield this.joplin.data.get(["notes",this.noteId],{fields:["body"]});const l=r.body.split("\n");r=(0,s.clearNoteReferences)(r);const d=(0,s.formatDate)(new Date(n)),u=(0,s.formatTime)(new Date(n)),c=l.findIndex((i=>{const n=i.split(",");return n[this.fieldIndices.project]===t&&n[this.fieldIndices.taskName]===e&&n[this.fieldIndices.startDate]===d&&n[this.fieldIndices.startTime]===u&&!n[this.fieldIndices.endDate]&&!n[this.fieldIndices.endTime]}));if(-1!==c){const e=l[c].split(",");e[this.fieldIndices.endDate]=(0,s.formatDate)(o),e[this.fieldIndices.endTime]=(0,s.formatTime)(o),e[this.fieldIndices.duration]=(0,s.formatDuration)(a),l[c]=e.join(",");const t=l.join("\n");yield this.noteManager.updateNote(t)}else console.error(`Could not find the open start entry for task: ${e}, project: ${t}`),this.joplin.views.panels.postMessage(this.panel,{name:"error",message:`Could not find the open start entry for task: ${e}, project: ${t}`});const p=this.currentStartDate,m=this.currentEndDate;this.currentStartDate=null,this.currentEndDate=null,yield this.scanNoteAndUpdateTasks(),this.currentStartDate=p,this.currentEndDate=m,yield this.scanNoteAndUpdateTasks()}))}getInitialData(){return n(this,void 0,void 0,(function*(){return{runningTasks:this.tasks,completedTasks:this.completedTasks,uniqueTasks:this.uniqueTasks,uniqueProjects:this.uniqueProjects,logNotes:yield this.getLogNotes(),defaultNoteId:this.noteId,sortBy:this.sortBy}}))}setNoteId(e){return n(this,void 0,void 0,(function*(){this.noteId=e,yield this.scanNoteAndUpdateTasks()}))}setLogNoteTag(e){return n(this,void 0,void 0,(function*(){this.logNoteTag=e,this.noteId="",this.tasks={},this.completedTasks=[],this.updateRunningTasks(),this.updateCompletedTasks([]),yield this.getLogNotes()}))}updateLogNotes(){this.joplin.views.panels.postMessage(this.panel,{name:"updateLogNotes",notes:this.logNotes})}setDateRange(e,t){return n(this,void 0,void 0,(function*(){this.currentStartDate=e,this.currentEndDate=t,yield this.scanNoteAndUpdateTasks()}))}clearTasks(){return n(this,void 0,void 0,(function*(){this.tasks={},this.completedTasks=[],this.updateRunningTasks(),this.updateCompletedTasks([])}))}initializeSortOrder(){return n(this,void 0,void 0,(function*(){this.sortBy=yield(0,o.getSummarySortOrder)()}))}updateSummarySortOrder(e){return n(this,void 0,void 0,(function*(){this.sortBy=e,this.joplin.views.panels.postMessage(this.panel,{name:"updateSortOrder",sortBy:this.sortBy})}))}updateLogSortOrder(){return n(this,void 0,void 0,(function*(){this.logSortOrder=yield(0,o.getLogSortOrder)()}))}updateEnforceSorting(e=null){return n(this,void 0,void 0,(function*(){this.enforceSorting=null!==e?e:yield(0,o.getEnforceSorting)()}))}}},185:(e,t)=>{"use strict";function i(e){return e.toLocaleDateString("en-CA")}function n(e){return e.toLocaleTimeString("en-US",{hour12:!1})}Object.defineProperty(t,"__esModule",{value:!0}),t.clearNoteReferences=t.formatDuration=t.formatTime=t.formatDate=t.formatLocalTime=void 0,t.formatLocalTime=function(e){return`${i(e)} ${n(e)}`},t.formatDate=i,t.formatTime=n,t.formatDuration=function(e){const t=Math.floor(e/1e3),i=Math.floor(t/3600),n=Math.floor(t%3600/60),s=t%60,o=e=>e.toString().padStart(2,"0");return`${o(i)}:${o(n)}:${o(s)}`},t.clearNoteReferences=function(e){return e?(e.body=null,e.title=null,e.id=null,e.parent_id=null,e.updated_time=null,e.created_time=null,e=null,null):null}}},t={};!function i(n){var s=t[n];if(void 0!==s)return s.exports;var o=t[n]={exports:{}};return e[n].call(o.exports,o,o.exports,i),o.exports}(156)})();manifest.json000644 0000001032 14714563747010423 0ustar00000000 000000 { "manifest_version": 1, "id": "joplin.plugin.alondmnt.time-slip", "app_min_version": "2.13", "platforms": ["desktop", "mobile"], "version": "1.0.2", "name": "Time Slip", "description": "A time tracker with logs stored and synced in Joplin notes.", "author": "Alon Diament", "homepage_url": "https://github.com/alondmnt/joplin-plugin-time-slip#readme", "repository_url": "https://github.com/alondmnt/joplin-plugin-time-slip", "keywords": ["time", "tracking"], "categories": ["productivity"], "screenshots": [], "icons": {} }timeTracker.css000644 0000017424 14714563747010722 0ustar00000000 000000 * { box-sizing: border-box; } #taskName, #projectName, #startButton, #openNoteButton, .running-task, .stopButton, .startButton, #noteSelector, .date-range input[type="date"], .autocomplete-list, #completedTasks table, #completedTasks th, #completedTasks td, #taskFilter { border-color: rgb(118, 118, 118); font-size: var(--joplin-font-size); } body { padding: 10px; overflow-y: auto; overflow-x: hidden; } #timeTracker { font-family: Avenir, Arial, sans-serif; font-size: var(--joplin-font-size); max-height: calc(100vh - 20px); /* Adjust if needed */ } .input-group, .note-selector-group { display: flex; gap: 5px; margin-bottom: 5px; position: relative; } #taskName, #projectName { width: 40%; min-height: 23px; color: var(--joplin-color); background-color: var(--joplin-background-color); border-width: 1px; border-radius: 3px; border-style: solid; } #startButton, #openNoteButton, .stopButton { width: 20%; min-height: 23px; cursor: pointer; color: var(--joplin-color); background-color: var(--joplin-background-color); border-width: 1px; border-radius: 3px; border-spacing: 5px; border-style: solid; font-size: var(--joplin-font-size); padding: 3px 8px; } #startButton:hover, #openNoteButton:hover, .stopButton:hover { background-color: var(--joplin-background-color-hover3); } #errorMessage { color: rgb(194, 28, 28); margin-bottom: 5px; margin-top: 5px; font-size: var(--joplin-font-size); } #runningTasks { overflow-y: auto; font-size: var(--joplin-font-size); box-sizing: border-box; margin: 0px; } .running-task { margin-bottom: 5px; padding: 5px; background-color: var(--joplin-background-color); border-width: 1px; border-style: solid; border-radius: 3px; display: flex; flex-direction: column; transition: background-color 0.2s, border-color 0.2s; } .running-task-header { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 5px; } .running-task-title-container { display: flex; flex-direction: column; } .running-task-title { font-weight: bold; } .running-task-project { font-size: calc(var(--joplin-font-size) * 0.9); color: var(--joplin-color-faded); } .running-task-info { display: flex; justify-content: space-between; align-items: center; } .running-task-start-time { flex: 1; text-align: left; } .running-task-duration { flex: 1; text-align: right; } ::-webkit-scrollbar { width: 7px; height: 7px; } ::-webkit-scrollbar-corner { background: none; } ::-webkit-scrollbar-track { border: none; } ::-webkit-scrollbar-thumb { background: rgba(100, 100, 100, 0.3); border-radius: 5px; } ::-webkit-scrollbar-track:hover { background: rgba(0, 0, 0, 0.1); } ::-webkit-scrollbar-thumb:hover { background: rgba(100, 100, 100, 0.7); } #completedTasks { margin-top: 0px; margin-bottom: 10px; } .completed-tasks-table { width: 100%; border-collapse: separate; border-spacing: 0; border-width: 1px; border-style: solid; border-radius: 3px; overflow: hidden; table-layout: auto; } .completed-tasks-table .header-cell, .completed-tasks-table td { padding: 5px; text-align: left; border-bottom-width: 1px; border-bottom-style: solid; } #completedTasks tr:last-child td { border-bottom: none; } .completed-tasks-table .header-cell { background-color: var(--joplin-background-color-hover3); font-weight: bold; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .completed-tasks-table tr:nth-child(even) { background-color: var(--joplin-background-color); } .completed-tasks-table tr:nth-child(odd) { background-color: var(--joplin-background-color3); } .completed-tasks-table td { word-wrap: anywhere; overflow-wrap: anywhere; } .startButton { padding: 3px 8px; background-color: var(--joplin-background-color); color: var(--joplin-color); border-width: 1px; border-style: solid; border-radius: 3px; cursor: pointer; transition: background-color 0.2s; } .startButton:hover { background-color: var(--joplin-background-color-hover3); } .autocomplete-list { position: absolute; border-width: 1px; border-style: solid; border-top: none; z-index: 99; top: 100%; left: 0; right: 0; padding: 0; max-height: 150px; overflow-y: auto; background-color: var(--joplin-background-color); box-shadow: 0 2px 5px rgba(180, 180, 180, 0.2); margin-top: -1px; } .autocomplete-list li { padding: 5px; cursor: pointer; background-color: var(--joplin-background-color); border-bottom-width: 1px; border-bottom-style: solid; } .autocomplete-list li:last-child { border-bottom: none; } .autocomplete-list li:hover, .autocomplete-list li.selected { background-color: var(--joplin-background-color-hover3); } .autocomplete-list li.selected { background-color: var(--joplin-background-color-hover3); } .autocomplete-list li:not(.selected) { background-color: var(--joplin-background-color); } #noteSelector { width: 80%; min-height: 23px; padding: 0 5px; color: var(--joplin-color); background-color: var(--joplin-background-color); border-width: 1px; border-style: solid; border-radius: 3px; font-family: Avenir, Arial, sans-serif; font-size: var(--joplin-font-size); } .date-range { display: flex; gap: 5px; width: 80%; } .date-range input[type="date"] { flex: 1; min-height: 23px; padding: 0 5px; color: var(--joplin-color); background-color: var(--joplin-background-color); border-width: 1px; border-style: solid; border-radius: 3px; font-family: Avenir, Arial, sans-serif; font-size: var(--joplin-font-size); } #aggregationSlider { -webkit-appearance: none; appearance: none; width: 100%; height: 5px; border-radius: 5px; background: var(--joplin-background-color3); outline: none; opacity: 0.7; -webkit-transition: .2s; transition: opacity .2s; } #aggregationSlider:hover { opacity: 1; } #aggregationSlider::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; width: 15px; height: 15px; border-radius: 50%; background: var(--joplin-color); cursor: pointer; } #aggregationSlider::-moz-range-thumb { width: 15px; height: 15px; border-radius: 50%; background: var(--joplin-color); cursor: pointer; } .slider-labels { display: flex; justify-content: space-between; font-size: var(--joplin-font-size); color: var(--joplin-color); margin-top: 5px; } .filter-group { display: flex; align-items: stretch; margin-bottom: 5px; gap: 5px; width: 100%; } #taskFilter { width: 20%; min-height: 23px; padding: 0 5px; color: var(--joplin-color); background-color: var(--joplin-background-color); border-width: 1px; border-style: solid; border-radius: 3px; } /* For smaller screens, stack the elements vertically */ @media (max-width: 300px) { .filter-group { flex-direction: column; } .date-range, #taskFilter { width: 100%; } } .hidden { display: none; } .section-divider { display: flex; align-items: center; margin-bottom: 2px; color: var(--joplin-color); } .section-divider hr { flex-grow: 1; border: none; height: 1px; background-color: rgb(118, 118, 118);; margin: 0px; } .section-divider span { font-weight: bold; white-space: nowrap; } .sortable { cursor: pointer; } .sortable:hover { text-decoration: underline; } .arrow-up::after { content: ' ▲'; } .arrow-down::after { content: ' ▼'; } timeTracker.js000644 0000034457 14714563747010553 0ustar00000000 000000 const taskNameInput=document.getElementById("taskName"),projectNameInput=document.getElementById("projectName"),startButton=document.getElementById("startButton"),runningTasksDiv=document.getElementById("runningTasks"),errorMessageDiv=document.getElementById("errorMessage"),noteSelector=document.getElementById("noteSelector");let selectedNoteName="";const completedTasksDiv=document.getElementById("completedTasks"),aggregationSlider=document.getElementById("aggregationSlider");let currentAggregationLevel=1;const taskFilter=document.getElementById("taskFilter");let runningTasksInterval,currentFilter="",tasks={},completedTasks=[],uniqueTasks=[],uniqueProjects=[],lastStartDate="",lastEndDate="",currentSortBy="duration";function requestInitialData(){webviewApi.postMessage({name:"requestInitialData"})}function formatDuration(e){const t=Math.floor(e/3600),n=Math.floor(e%3600/60),a=e%60,s=e=>e.toString().padStart(2,"0");return`${s(t)}:${s(n)}:${s(a)}`}function formatStartTime(e){const t=new Date(e);return`${t.getHours().toString().padStart(2,"0")}:${t.getMinutes().toString().padStart(2,"0")}:${t.getSeconds().toString().padStart(2,"0")}`}function startUpdatingRunningTasks(){runningTasksInterval||(runningTasksInterval=setInterval(updateRunningTasksDisplay,1e3))}function stopUpdatingRunningTasks(){runningTasksInterval&&(clearInterval(runningTasksInterval),runningTasksInterval=null)}function updateRunningTasksDisplay(){const e=Date.now();let t="";try{t=Object.entries(tasks).map((([t,{startTime:n,project:a}])=>{const[s,r]=t.split("|"),o=formatDuration(Math.floor((e-n)/1e3));return`
\n
\n
\n ${s}\n ${r}\n
\n \n
\n
\n ${formatStartTime(n)}\n ${o}\n
\n
`})).join("")}catch(e){console.error("Error while generating tasks HTML:",e),t="Error displaying tasks"}runningTasksDiv.innerHTML=t||"No tasks running",Object.keys(tasks).length>0?startUpdatingRunningTasks():stopUpdatingRunningTasks()}function updateNoteSelector(e){const t=noteSelector.value;noteSelector.innerHTML=e.length>0?"":'';const n=new Set;e.forEach((e=>{if(!n.has(e.id)){const t=document.createElement("option");t.value=e.id,t.textContent=e.title,noteSelector.appendChild(t),n.add(e.id)}})),e.length>0?t&&e.some((e=>e.id===t))?noteSelector.value=t:(noteSelector.value=e[0].id,noteSelector.dispatchEvent(new Event("change"))):noteSelector.dispatchEvent(new Event("change")),updateOpenNoteButtonVisibility()}function updateOpenNoteButtonVisibility(){const e=document.getElementById("openNoteButton");e&&(e.style.display=noteSelector.value?"inline-block":"none")}function openSelectedNote(){const e=noteSelector.value;e&&webviewApi.postMessage({name:"openNote",noteId:e})}function convertCsvToMarkdown(e){const t=e.trim().split("\n").map((e=>e.split(","))),n=t[0],a=t.slice(1);let s="| "+n.join(" | ")+" |\n";return s+="| "+n.map((()=>"---")).join(" | ")+" |\n",a.forEach((e=>{s+="| "+e.join(" | ")+" |\n"})),s}function aggregateTasks(e,t){if(1===t)return e.map((e=>({name:e.taskName,duration:e.duration,endTime:e.endTime,originalTask:e.taskName,originalProject:e.project})));const n=e.reduce(((e,n)=>{const a=2===t?n.project:"Total";return e[a]||(e[a]={name:a,duration:0,endTime:0,tasks:[]}),e[a].duration+=n.duration,e[a].endTime=Math.max(e[a].endTime,n.endTime),e[a].tasks.push(n),e}),{});return Object.values(n).map((e=>({name:e.name,duration:e.duration,endTime:e.endTime,originalTask:e.tasks[0].taskName,originalProject:e.tasks[0].project})))}function updateCompletedTasksDisplay(){const e=document.querySelector(".aggregation-level");let t="",n="";if(completedTasks.length>0){let a=aggregateTasks(completedTasks.filter((e=>e.taskName.toLowerCase().includes(currentFilter.toLowerCase())||e.project.toLowerCase().includes(currentFilter.toLowerCase()))),currentAggregationLevel);a.sort(((e,t)=>{if("duration"===currentSortBy)return t.duration-e.duration;if("endTime"===currentSortBy)return t.endTime-e.endTime;if("name"===currentSortBy){const n=1===currentAggregationLevel?e.originalProject+" "+e.originalTask:2===currentAggregationLevel?e.name:selectedNoteName||"",a=1===currentAggregationLevel?t.originalProject+" "+t.originalTask:2===currentAggregationLevel?t.name:selectedNoteName||"";return n.localeCompare(a)}}));const s=document.getElementById("timeTracker").offsetWidth>340;t+='';let r="Duration",o="End Time",i="Project",l="Task";"duration"===currentSortBy?r+='':"endTime"===currentSortBy?o+='':"name"===currentSortBy&&(i+='',l+=''),1===currentAggregationLevel?(n="Task,Project,Duration,End date,End time\n",t+=`\n \n \n ${s?`\n `:``}\n \n `):2===currentAggregationLevel?(n="Project,Duration,End date,End time\n",t+=`\n \n \n \n `):(n="Note,Duration,End date,End time\n",t+=`\n \n \n \n `),a.forEach((({name:e,duration:a,originalTask:r,originalProject:o,endTime:i})=>{const l=formatDuration(Math.floor(a/1e3)),c=formatDateTime(new Date(i)),d=c.replace("
",",");1===currentAggregationLevel?(n+=`${r},${o},${l},${d}\n`,t+=`\n \n \n ${s?`\n `:``}\n \n `):2===currentAggregationLevel?(n+=`${e},${l},${d}\n`,t+=`\n \n \n \n `):(n+=`${selectedNoteName||"No note selected"},${l},${d}\n`,t+=`\n \n \n \n `)})),t+="
${l}${i}${r}${o}\n ${"endTime"===currentSortBy?o:r}\n Action
${i}${r}${o}
Note${r}${o}
${r}${o}${l}${c}\n ${"endTime"===currentSortBy?c:l}\n
${e}${l}${c}
${selectedNoteName||"No note selected"}${l}${c}
",e.classList.remove("hidden")}else t+="

No completed tasks

",e.classList.add("hidden"),n="No completed tasks\n";completedTasksDiv.innerHTML=t,completedTasksDiv.setAttribute("data-csv-content",n)}function changeSortOrder(e){e!==currentSortBy&&(currentSortBy=e,webviewApi.postMessage({name:"changeSortOrder",sortBy:currentSortBy}))}function initializeDateInputs(){const e=document.getElementById("startDate"),t=document.getElementById("endDate");e.addEventListener("change",(()=>applyDateFilter(e,t))),t.addEventListener("change",(()=>applyDateFilter(e,t))),webviewApi.postMessage({name:"getDefaultDateRange"})}function applyDateFilter(e,t){const n=e.value||null,a=t.value||null;n===lastStartDate&&a===lastEndDate||(lastStartDate=n,lastEndDate=a,webviewApi.postMessage({name:"applyDateFilter",startDate:n,endDate:a}))}function createAutocomplete(e,t,n){let a=null,s=-1;const r=function(){c()},o=function(t){if(a&&"none"!==a.style.display)switch(t.key){case"ArrowDown":t.preventDefault(),u(1);break;case"ArrowUp":t.preventDefault(),u(-1);break;case"Enter":t.preventDefault(),-1===s?(n(e.value),d()):function(){const e=a.getElementsByTagName("li");s>=0&&se.toLowerCase().includes(r))).sort(((e,t)=>e.toLowerCase().localeCompare(t.toLowerCase())));0!==o.length?function(t){a||(a=document.createElement("ul"),a.className="autocomplete-list",e.parentNode.insertBefore(a,e.nextSibling)),a.innerHTML="",t.forEach(((e,t)=>{const n=document.createElement("li");n.textContent=e,n.addEventListener("click",(()=>m(e))),n.addEventListener("mouseenter",(()=>{s=t,p()})),a.appendChild(n)})),a.style.display="block",s=-1,p()}(o):d()}function d(){a&&(a.style.display="none")}function u(e){const t=a.getElementsByTagName("li");s=(s+e+t.length)%t.length,p()}function p(){const e=a.getElementsByTagName("li");for(let t=0;t=0&&e[s].scrollIntoView({block:"nearest"})}function m(t){e.value=t,d(),n(t)}return e.addEventListener("input",r),e.addEventListener("keydown",o),e.addEventListener("blur",i),document.addEventListener("click",l),{teardown:function(){e.removeEventListener("input",r),e.removeEventListener("keydown",o),e.removeEventListener("blur",i),document.removeEventListener("click",l),a&&(a.remove(),a=null)},updateItems:c}}startButton.addEventListener("click",(function(){const e=taskNameInput.value.trim(),t=projectNameInput.value.trim();e&&t?(webviewApi.postMessage({name:"start",taskName:e,projectName:t}),taskNameInput.value="",projectNameInput.value=""):console.log("Task name or project name is empty, not sending message")})),runningTasksDiv.addEventListener("click",(function(e){if(e.target.classList.contains("stopButton")){const t=e.target.getAttribute("data-task"),n=e.target.getAttribute("data-project");webviewApi.postMessage({name:"stop",taskName:t,projectName:n}),delete tasks[`${t}|${n}`],updateRunningTasksDisplay()}})),document.getElementById("completedTasks").addEventListener("click",(function(e){if(e.target.classList.contains("startButton")){const t=e.target.getAttribute("data-task"),n=e.target.getAttribute("data-project");webviewApi.postMessage({name:"start",taskName:t,projectName:n})}})),noteSelector.addEventListener("change",(function(){const e=this.value;selectedNoteName=this.options[this.selectedIndex].text,webviewApi.postMessage({name:"changeNote",noteId:e,startDate:lastStartDate,endDate:lastEndDate}),updateOpenNoteButtonVisibility()})),webviewApi.onMessage((function(e){const t=e.message;if("updateRunningTasks"===t.name)tasks=t.tasks||{},updateRunningTasksDisplay(),errorMessageDiv.textContent="";else if("updateCompletedTasks"===t.name)completedTasks=t.tasks||[],updateCompletedTasksDisplay();else if("updateAutocompleteLists"===t.name)uniqueTasks=t.tasks||[],uniqueProjects=t.projects||[],updateAutocompleteLists();else if("error"===t.name)errorMessageDiv.textContent=t.message,errorMessageDiv.style.color="red";else if("initialData"===t.name)tasks=t.runningTasks||{},completedTasks=t.completedTasks||[],uniqueTasks=t.uniqueTasks||[],uniqueProjects=t.uniqueProjects||[],updateRunningTasksDisplay(),updateCompletedTasksDisplay(),updateAutocompleteLists(),updateNoteSelector(t.logNotes),t.defaultNoteId&¬eSelector.querySelector(`option[value="${t.defaultNoteId}"]`)&&(noteSelector.value=t.defaultNoteId,selectedNoteName=noteSelector.options[noteSelector.selectedIndex].text,noteSelector.dispatchEvent(new Event("change"))),currentAggregationLevel=t.aggregationLevel||1,aggregationSlider.value=currentAggregationLevel,updateCompletedTasksDisplay(),taskNameInput.focus(),currentSortBy=t.sortBy||"duration";else if("updateLogNotes"===t.name)updateNoteSelector(t.notes);else if("defaultDateRange"===t.name){const e=new Date(t.startDate),n=new Date(t.endDate),a=document.getElementById("startDate"),s=document.getElementById("endDate");lastStartDate=e.toLocaleDateString("en-CA"),lastEndDate=n.toLocaleDateString("en-CA"),a.value=lastStartDate,s.value=lastEndDate,applyDateFilter(a,s)}else if("updateSortOrder"===t.name)currentSortBy=t.sortBy,updateCompletedTasksDisplay();else if("requestSummaryCSV"===t.name){const e=completedTasksDiv.getAttribute("data-csv-content");webviewApi.postMessage({name:"summaryCSV",content:e})}else if("requestSummaryMarkdown"===t.name){const e=convertCsvToMarkdown(completedTasksDiv.getAttribute("data-csv-content"));webviewApi.postMessage({name:"summaryMarkdown",content:e})}})),aggregationSlider.addEventListener("input",(function(){currentAggregationLevel=parseInt(this.value),updateCompletedTasksDisplay(),webviewApi.postMessage({name:"setAggregationLevel",level:currentAggregationLevel})})),taskFilter.addEventListener("input",(function(){currentFilter=this.value,updateCompletedTasksDisplay()})),taskFilter.addEventListener("keydown",(e=>{"Escape"===e.key&&(""!==taskFilter.value?(taskFilter.value="",currentFilter="",updateCompletedTasksDisplay()):taskNameInput.focus())}));const taskAutocomplete=createAutocomplete(taskNameInput,(()=>uniqueTasks),(e=>{projectNameInput.focus()})),projectAutocomplete=createAutocomplete(projectNameInput,(()=>uniqueProjects),(e=>{startButton.click()}));function updateAutocompleteLists(){taskAutocomplete.updateItems(),projectAutocomplete.updateItems()}function formatDateTime(e){return`${e.toLocaleDateString("en-CA")}
${e.toLocaleTimeString("en-CA",{hour12:!1})}`}function handleEscapeKey(e){""!==e.value?e.value="":taskNameInput.focus()}document.getElementById("openNoteButton").addEventListener("click",openSelectedNote),completedTasksDiv.addEventListener("click",(function(e){const t=e.target;t.classList.contains("sortable")&&changeSortOrder(t.dataset.sort)})),taskNameInput.addEventListener("keydown",(e=>{"Escape"===e.key&&handleEscapeKey(taskNameInput)})),projectNameInput.addEventListener("keydown",(e=>{"Escape"===e.key&&handleEscapeKey(projectNameInput)})),setTimeout(initializeDateInputs,500),setTimeout(requestInitialData,1e3);