joplin-plugin-explorer 1.5.0 → 1.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/publish/index.js +1 -1
- package/publish/manifest.json +1 -1
- package/publish/plugin.jpl +0 -0
- package/publish/webview/panel.css +133 -29
- package/publish/webview/panel.js +1 -1
package/package.json
CHANGED
package/publish/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(()=>{"use strict";var e={982(e){e.exports=require("crypto")},896(e){e.exports=require("fs")},928(e){e.exports=require("path")}},t={};function o(a){var n=t[a];if(void 0!==n)return n.exports;var i=t[a]={exports:{}};return e[a](i,i.exports,o),i.exports}const a={zh_CN:{newNotebook:"新建笔记本",newNote:"新建笔记",newTodo:"新建待办",sort:"排序",collapseAll:"全部折叠",expandAll:"全部展开",search:"搜索笔记内容...",searchResultCount:"找到 {count} 条结果",searchNoResult:"没有找到匹配的笔记",searching:"搜索中...",sync:"同步",syncing:"同步中...",syncDone:"✔ 同步完成",syncFailed:"⚠ 同步失败",loading:"加载中...",sortUpdatedDesc:"↓ 修改时间",sortUpdatedAsc:"↑ 修改时间",sortTitleAsc:"↑ 标题",sortTitleDesc:"↓ 标题",sortManual:"⇅ 手动排序",ctxNewNoteHere:"在此新建笔记",ctxNewTodoHere:"在此新建待办",ctxNewSubNotebook:"新建子笔记本",ctxRenameFolder:"重命名",ctxExportFolder:"导出笔记本",ctxDeleteFolder:"删除笔记本",ctxOpenNote:"打开笔记",ctxOpenInNewWindow:"在新窗口中打开",ctxCopyLink:"复制 Markdown 链接",ctxDuplicateNote:"复制副本",ctxSwitchNoteType:"笔记/待办 切换",ctxToggleTodo:"切换完成状态",ctxRenameNote:"重命名",ctxMoveNote:"移动到笔记本...",ctxNoteInfo:"笔记属性",ctxDeleteNote:"删除笔记",confirmDeleteFolder:"确定删除此笔记本及其所有内容吗?",confirmDeleteNote:"确定删除此笔记吗?",promptRename:"请输入新名称:",promptMoveNote:"请输入目标笔记本名称:",promptNewNotebookName:"请输入新笔记本名称:",dropCreateNotebook:"释放以创建新笔记本",searchSectionNotes:"笔记",searchSectionTags:"标签",searchSectionFolders:"笔记本",searchTagNoteCount:"{count} 条笔记",pinned:"收藏夹",tags:"标签",ctxRenameTag:"重命名标签",ctxDeleteTag:"删除标签",ctxUntagNote:"从标签移除",confirmDeleteTag:"删除该标签?(只删除标签本身,不会删除笔记)",ctxPublishNote:"发布笔记",ctxExport:"导出",refresh:"刷新",newItem:"新建",trash:"回收站",ctxRestoreNote:"恢复",ctxPermanentDelete:"彻底删除",ctxEmptyTrash:"清空回收站",confirmEmptyTrash:"清空回收站?所有已删除的笔记本和笔记将被永久删除,无法恢复。",ctxSetTags:"设置标签",ctxMoveToFolder:"移动到笔记本",ctxCopyExternalLink:"复制外部链接",ctxPin:"📌 收藏",ctxUnpin:"取消收藏",cancel:"取消"},zh_TW:{newNotebook:"新建筆記本",newNote:"新建筆記",newTodo:"新建待辦",sort:"排序",collapseAll:"全部摺疊",expandAll:"全部展開",search:"搜尋筆記內容...",searchResultCount:"找到 {count} 條結果",searchNoResult:"沒有找到匹配的筆記",searching:"搜尋中...",sync:"同步",syncing:"同步中...",syncDone:"✔ 同步完成",syncFailed:"⚠ 同步失敗",loading:"載入中...",sortUpdatedDesc:"↓ 修改時間",sortUpdatedAsc:"↑ 修改時間",sortTitleAsc:"↑ 標題",sortTitleDesc:"↓ 標題",sortManual:"⇅ 手動排序",ctxNewNoteHere:"在此新建筆記",ctxNewTodoHere:"在此新建待辦",ctxNewSubNotebook:"新建子筆記本",ctxRenameFolder:"重新命名",ctxExportFolder:"匯出筆記本",ctxDeleteFolder:"刪除筆記本",ctxOpenNote:"開啟筆記",ctxOpenInNewWindow:"在新視窗中開啟",ctxCopyLink:"複製 Markdown 連結",ctxDuplicateNote:"複製副本",ctxSwitchNoteType:"筆記/待辦 切換",ctxToggleTodo:"切換完成狀態",ctxRenameNote:"重新命名",ctxMoveNote:"移動到筆記本...",ctxNoteInfo:"筆記屬性",ctxDeleteNote:"刪除筆記",confirmDeleteFolder:"確定刪除此筆記本及其所有內容嗎?",confirmDeleteNote:"確定刪除此筆記嗎?",promptRename:"請輸入新名稱:",promptMoveNote:"請輸入目標筆記本名稱:",promptNewNotebookName:"請輸入新筆記本名稱:",dropCreateNotebook:"釋放以建立新筆記本",searchSectionNotes:"筆記",searchSectionTags:"標籤",searchSectionFolders:"筆記本",searchTagNoteCount:"{count} 條筆記",pinned:"收藏夾",tags:"標籤",ctxRenameTag:"重新命名標籤",ctxDeleteTag:"刪除標籤",ctxUntagNote:"自標籤移除",confirmDeleteTag:"刪除該標籤?(僅刪除標籤本身,不會刪除筆記)",ctxPublishNote:"發佈筆記",ctxExport:"匯出",refresh:"重新整理",newItem:"新增",trash:"垃圾桶",ctxRestoreNote:"還原",ctxPermanentDelete:"永久刪除",ctxEmptyTrash:"清空垃圾桶",confirmEmptyTrash:"清空垃圾桶?所有已刪除的筆記本和筆記將被永久刪除,無法還原。",ctxSetTags:"設定標籤",ctxMoveToFolder:"移動到筆記本",ctxCopyExternalLink:"複製外部連結",ctxPin:"📌 收藏",ctxUnpin:"取消收藏",cancel:"取消"},en_US:{newNotebook:"New Notebook",newNote:"New Note",newTodo:"New To-do",sort:"Sort",collapseAll:"Collapse All",expandAll:"Expand All",search:"Search note contents...",searchResultCount:"{count} results found",searchNoResult:"No matching notes found",searching:"Searching...",sync:"Synchronise",syncing:"Syncing...",syncDone:"✔ Sync Done",syncFailed:"⚠ Sync Failed",loading:"Loading...",sortUpdatedDesc:"↓ Updated",sortUpdatedAsc:"↑ Updated",sortTitleAsc:"↑ Title",sortTitleDesc:"↓ Title",sortManual:"⇅ Manual",ctxNewNoteHere:"New Note Here",ctxNewTodoHere:"New To-do Here",ctxNewSubNotebook:"New Sub-notebook",ctxRenameFolder:"Rename",ctxExportFolder:"Export Notebook",ctxDeleteFolder:"Delete Notebook",ctxOpenNote:"Open Note",ctxOpenInNewWindow:"Open in New Window",ctxCopyLink:"Copy Markdown Link",ctxDuplicateNote:"Duplicate",ctxSwitchNoteType:"Switch Note/To-do",ctxToggleTodo:"Toggle Completed",ctxRenameNote:"Rename",ctxMoveNote:"Move to Notebook...",ctxNoteInfo:"Note Properties",ctxDeleteNote:"Delete Note",confirmDeleteFolder:"Delete this notebook and all its contents?",confirmDeleteNote:"Delete this note?",promptRename:"Enter new name:",promptMoveNote:"Enter target notebook name:",promptNewNotebookName:"Enter new notebook name:",dropCreateNotebook:"Release to create a new notebook",searchSectionNotes:"Notes",searchSectionTags:"Tags",searchSectionFolders:"Notebooks",searchTagNoteCount:"{count} notes",pinned:"Pinned",tags:"Tags",ctxRenameTag:"Rename tag",ctxDeleteTag:"Delete tag",ctxUntagNote:"Remove from tag",confirmDeleteTag:"Delete this tag? (Only the tag is removed - notes are kept.)",ctxPublishNote:"Publish note",ctxExport:"Export",refresh:"Refresh",newItem:"New",trash:"Trash",ctxRestoreNote:"Restore",ctxPermanentDelete:"Delete permanently",ctxEmptyTrash:"Empty trash",confirmEmptyTrash:"Empty the trash? All deleted notebooks and notes will be permanently removed. This cannot be undone.",ctxSetTags:"Set tags",ctxMoveToFolder:"Move to notebook",ctxCopyExternalLink:"Copy external link",ctxPin:"📌 Pin",ctxUnpin:"Unpin",cancel:"Cancel"},ru:{newNotebook:"Новый блокнот",newNote:"Новая заметка",newTodo:"Новая задача",sort:"Сортировка",collapseAll:"Свернуть все",expandAll:"Развернуть все",search:"Искать в содержимом заметок...",searchResultCount:"Найдено результатов: {count}",searchNoResult:"Заметки не найдены",searching:"Поиск...",sync:"Синхронизировать",syncing:"Синхронизация...",syncDone:"✔ Синхронизация завершена",syncFailed:"⚠ Ошибка синхронизации",loading:"Загрузка...",sortUpdatedDesc:"↓ Обновлено",sortUpdatedAsc:"↑ Обновлено",sortTitleAsc:"↑ Название",sortTitleDesc:"↓ Название",sortManual:"⇅ Вручную",ctxNewNoteHere:"Создать заметку здесь",ctxNewTodoHere:"Создать задачу здесь",ctxNewSubNotebook:"Новый вложенный блокнот",ctxRenameFolder:"Переименовать",ctxExportFolder:"Экспортировать блокнот",ctxDeleteFolder:"Удалить блокнот",ctxOpenNote:"Открыть заметку",ctxOpenInNewWindow:"Открыть в новом окне",ctxCopyLink:"Скопировать Markdown-ссылку",ctxDuplicateNote:"Создать копию",ctxSwitchNoteType:"Переключить между заметкой и задачей",ctxToggleTodo:"Переключить статус выполнения",ctxRenameNote:"Переименовать",ctxMoveNote:"Переместить в блокнот...",ctxNoteInfo:"Свойства заметки",ctxDeleteNote:"Удалить заметку",confirmDeleteFolder:"Удалить блокнот и все его содержимое?",confirmDeleteNote:"Удалить заметку?",promptRename:"Введите новое название:",promptMoveNote:"Переместить в блокнот:",promptNewNotebookName:"Введите название нового блокнота:",dropCreateNotebook:"Отпустите, чтобы создать новый блокнот",searchSectionNotes:"Заметки",searchSectionTags:"Метки",searchSectionFolders:"Блокноты",searchTagNoteCount:"Заметок: {count}",pinned:"Закрепленные",tags:"Теги",ctxRenameTag:"Переименовать тег",ctxDeleteTag:"Удалить тег",ctxUntagNote:"Убрать из тега",confirmDeleteTag:"Удалить этот тег? (Удаляется только тег, заметки сохраняются.)",ctxPublishNote:"Опубликовать заметку",ctxExport:"Экспорт",refresh:"Обновить",newItem:"Создать",trash:"Корзина",ctxRestoreNote:"Восстановить",ctxPermanentDelete:"Удалить навсегда",ctxEmptyTrash:"Очистить корзину",confirmEmptyTrash:"Очистить корзину? Все удалённые блокноты и заметки будут удалены безвозвратно.",ctxSetTags:"Назначить теги",ctxMoveToFolder:"Переместить в блокнот",ctxCopyExternalLink:"Копировать внешнюю ссылку",ctxPin:"📌 Закрепить",ctxUnpin:"Открепить",cancel:"Отмена"},ja_JP:{newNotebook:"新規ノートブック",newNote:"新規ノート",newTodo:"新規タスク",sort:"並べ替え",collapseAll:"すべて折りたたむ",expandAll:"すべて展開",search:"ノート内容を検索...",searchResultCount:"{count} 件の結果",searchNoResult:"一致するノートが見つかりません",searching:"検索中...",sync:"同期",syncing:"同期中...",syncDone:"✔ 同期完了",syncFailed:"⚠ 同期に失敗しました",loading:"読み込み中...",sortUpdatedDesc:"↓ 更新日時",sortUpdatedAsc:"↑ 更新日時",sortTitleAsc:"↑ タイトル",sortTitleDesc:"↓ タイトル",sortManual:"⇅ 手動",ctxNewNoteHere:"ここに新規ノート",ctxNewTodoHere:"ここに新規タスク",ctxNewSubNotebook:"新規サブノートブック",ctxRenameFolder:"名前を変更",ctxExportFolder:"ノートブックをエクスポート",ctxDeleteFolder:"ノートブックを削除",ctxOpenNote:"ノートを開く",ctxOpenInNewWindow:"新しいウィンドウで開く",ctxCopyLink:"Markdownリンクをコピー",ctxDuplicateNote:"複製",ctxSwitchNoteType:"ノート/タスク切り替え",ctxToggleTodo:"完了状態を切り替え",ctxRenameNote:"名前を変更",ctxMoveNote:"ノートブックに移動...",ctxNoteInfo:"ノートプロパティ",ctxDeleteNote:"ノートを削除",confirmDeleteFolder:"このノートブックとその内容をすべて削除しますか?",confirmDeleteNote:"このノートを削除しますか?",promptRename:"新しい名前を入力:",promptMoveNote:"移動先のノートブック名:",promptNewNotebookName:"新しいノートブック名を入力:",dropCreateNotebook:"ドロップして新規ノートブックを作成",searchSectionNotes:"ノート",searchSectionTags:"タグ",searchSectionFolders:"ノートブック",searchTagNoteCount:"{count} 件のノート",pinned:"ピン留め",tags:"タグ",ctxRenameTag:"タグ名を変更",ctxDeleteTag:"タグを削除",ctxUntagNote:"タグから外す",confirmDeleteTag:"このタグを削除しますか?(タグのみ削除され、ノートは残ります)",ctxPublishNote:"ノートを公開",ctxExport:"エクスポート",refresh:"更新",newItem:"新規",trash:"ゴミ箱",ctxRestoreNote:"復元",ctxPermanentDelete:"完全に削除",ctxEmptyTrash:"ゴミ箱を空にする",confirmEmptyTrash:"ゴミ箱を空にしますか?削除済みのノートブックとノートは完全に削除され、元に戻せません。",ctxSetTags:"タグを設定",ctxMoveToFolder:"ノートブックへ移動",ctxCopyExternalLink:"外部リンクをコピー",ctxPin:"📌 ピン留め",ctxUnpin:"ピン解除",cancel:"キャンセル"}},n=o(896),i=o(928),s=o(982);function l(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}const r={".gif":"image/gif",".ico":"image/x-icon",".jpeg":"image/jpeg",".jpg":"image/jpeg",".png":"image/png",".svg":"image/svg+xml",".webp":"image/webp"};function d(e,t){const o="icon"+(t?" "+t:"");return"image"===e.type?'<span class="'+o+'"><img class="custom-icon" src="'+l(e.value)+'" /></span>':'<span class="'+o+'">'+l(e.value)+"</span>"}const c={};async function p(e,t,o,a){const l=o+":"+String(e);if(c[l])return c[l];const d=await async function(e,t,o,a){const l="string"==typeof e?e.trim():"";if(!l)return{type:"text",value:t};if(/^data:image\//i.test(l)||/^https?:\/\//i.test(l))return{type:"image",value:l};const d=function(e){const t=e.trim();return/^file:\/\//i.test(t)?decodeURIComponent(t.replace(/^file:\/\//i,"")):0===t.indexOf("~/")&&process&&process.env&&process.env.HOME?i.join(process.env.HOME,t.substring(2)):i.isAbsolute(t)?t:null}(l);if(!d)return{type:"text",value:l};const c=i.extname(d).toLowerCase(),p=r[c];if(!p)return console.warn("Joplin Explorer: unsupported icon file type",d),{type:"text",value:t};const u=i.join(a,"custom-icons"),f=s.createHash("sha1").update(d).digest("hex"),m=i.join(u,o+"-"+f+c);try{await n.promises.mkdir(u,{recursive:!0}),(await n.promises.stat(d)).isFile()&&await n.promises.copyFile(d,m)}catch(e){console.warn("Joplin Explorer: failed to copy icon file",d,e)}try{return{type:"image",value:"data:"+p+";base64,"+(await n.promises.readFile(m)).toString("base64")}}catch(e){return console.warn("Joplin Explorer: failed to load icon file",m,e),{type:"text",value:t}}}(e,t,o,a);return c[l]=d,d}function u(e,t){const o=e.order||0,a=t.order||0;return o!==a?a-o:(e.title||"").localeCompare(t.title||"")}function f(e,t=!0,o={type:"text",value:"📂"},a={type:"text",value:"📁"}){let n=e.icon;if(n&&"string"==typeof n)try{n=JSON.parse(n)}catch(e){n=null}return n&&n.emoji?{type:"text",value:String(n.emoji)}:t?a:o}function m(e){return e.is_todo?e.todo_completed?"☑":"☐":"📝"}function w(e,t,o,a=0,n=!0,i={type:"text",value:"📂"},s={type:"text",value:"📁"}){let r="";for(const c of e){const e=8+18*a;if("folder"===c.type){const p=c.total_count||c.note_count||0,u=!0===o[c.id],m=u?"▶":"▼",g=u?"toggle":"toggle expanded";r+='<div class="tree-item folder'+(u?" collapsed":"")+'" style="padding-left:'+e+'px" data-id="'+c.id+'" data-type="folder">',n&&(r+='<span class="'+g+'">'+m+"</span>"),r+=d(f(c,!1,i,s),"folder-icon icon-when-open"),r+=d(f(c,!0,i,s),"folder-icon icon-when-collapsed"),r+='<span class="label">'+l(c.title)+"</span>",r+='<span class="count">'+p+"</span>",r+="</div>",r+='<div class="children'+(u?" collapsed":"")+'" data-folder-id="'+c.id+'">',c.children&&(r+=w(c.children,t,o,a+1,n,i,s)),r+="</div>"}else{const o=c.id===t?" selected":"",a=m(c);r+='<div class="tree-item note'+o+'" style="padding-left:'+e+'px" data-id="'+c.id+'" data-type="note" data-todo="'+(c.is_todo?1:0)+'">',r+='<span class="icon note-icon">'+a+"</span>",r+='<span class="label">'+l(c.title)+"</span>",r+="</div>"}}return r}function g(e,t){const o=e.slice();switch(t){case"title_asc":o.sort((e,t)=>(e.title||"").localeCompare(t.title||""));break;case"title_desc":o.sort((e,t)=>(t.title||"").localeCompare(e.title||""));break;case"updated_asc":o.sort((e,t)=>(e.user_updated_time||0)-(t.user_updated_time||0));break;case"manual":o.sort((e,t)=>{const o=e.order||0,a=t.order||0;return o!==a?a-o:(t.user_updated_time||0)-(e.user_updated_time||0)});break;default:o.sort((e,t)=>(t.user_updated_time||0)-(e.user_updated_time||0))}return o}joplin.plugins.register({onStart:async function(){const e=(o=await joplin.settings.globalValue("locale")||"en_US",a[o]||a[o.split("_")[0]]||a.en_US),t=await joplin.views.panels.create("notesInListPanel");var o;await joplin.views.panels.addScript(t,"webview/panel.css"),await joplin.views.panels.addScript(t,"webview/panel.js"),await joplin.views.panels.setHtml(t,'<div id="notes-in-list-root"><p style="padding:12px;">'+e.loading+"</p></div>"),await joplin.views.panels.show(t,!0);try{await joplin.settings.registerSection("joplinExplorer",{label:"Joplin Explorer",iconName:"fas fa-columns"}),await joplin.settings.registerSettings({pinnedItems:{section:"joplinExplorer",type:2,value:'{"notes":[],"folders":[]}',public:!1,label:"Pinned Items (JSON)"},folderOrder:{section:"joplinExplorer",type:2,value:"{}",public:!1,label:"Folder Manual Order (JSON)"},noteSortMode:{section:"joplinExplorer",type:2,value:"updated_desc",public:!1,label:"Note Sort Mode"},uiState:{section:"joplinExplorer",type:2,value:"{}",public:!1,label:"UI State (JSON)"},showTagsSection:{section:"joplinExplorer",type:3,value:!0,public:!0,label:"Show tags section",description:"Show Joplin tags as folders below the notebook tree."},autoRefresh:{section:"joplinExplorer",type:3,value:!0,public:!0,label:"Auto refresh on external changes",description:"Poll Joplin's change feed every 5 seconds and refresh the panel when notes are created, moved or deleted by other plugins or sync. Edits to the currently open note are ignored (they already update live)."},restoreUiState:{section:"joplinExplorer",type:3,value:!0,public:!0,label:"Restore last view state on startup",description:"Remember collapsed/expanded folders and sections between sessions. When off, the tree starts fully collapsed."},tagsDefaultExpanded:{section:"joplinExplorer",type:3,value:!1,public:!0,label:"Tags section expanded by default",description:"Only used when the last view state is not restored: start with the tags section expanded."},expandAllMode:{section:"joplinExplorer",type:2,value:"restore",isEnum:!0,options:{restore:"Restore the state before Collapse All",skeleton:"Folders only (leaf notebooks stay collapsed)",all:"Everything"},public:!0,label:"Expand All behavior",description:"What the Expand All button restores. Default: the tree as it was before the last Collapse All."},showFolderToggles:{section:"joplinExplorer",type:3,value:!0,public:!0,label:"Show toggle arrows",description:"Show expand/collapse arrows before folders and the pinned section."},openFolderIcon:{section:"joplinExplorer",type:2,value:"📂",public:!0,label:"Open folder icon",description:"Emoji, image URL, data URI, or local image path for expanded folders without a custom notebook icon."},closedFolderIcon:{section:"joplinExplorer",type:2,value:"📁",public:!0,label:"Closed folder icon",description:"Emoji, image URL, data URI, or local image path for collapsed folders without a custom notebook icon."},openPinnedIcon:{section:"joplinExplorer",type:2,value:"📌",public:!0,label:"Open pinned icon",description:"Emoji, image URL, data URI, or local image path for the expanded pinned section."},closedPinnedIcon:{section:"joplinExplorer",type:2,value:"📌",public:!0,label:"Closed pinned icon",description:"Emoji, image URL, data URI, or local image path for the collapsed pinned section."}})}catch(e){console.error("Joplin Explorer: failed to register settings",e)}const n=await joplin.views.dialogs.create("explorerInputDialog"),i=await joplin.views.dialogs.create("explorerConfirmDialog"),s=await joplin.views.dialogs.create("explorerInfoDialog");async function r(t){return await joplin.views.dialogs.setHtml(i,'<div style="padding:10px;min-width:280px;"><div style="font-size:13px;">'+l(t)+"</div></div>"),await joplin.views.dialogs.setButtons(i,[{id:"ok",title:"OK"},{id:"cancel",title:e.cancel||"Cancel"}]),"ok"===(await joplin.views.dialogs.open(i)).id}async function h(e,t){await joplin.views.dialogs.setHtml(s,'<div style="padding:10px;min-width:320px;"><div style="font-size:14px;font-weight:bold;margin-bottom:10px;">'+l(e)+'</div><div style="font-size:12px;line-height:1.8;white-space:pre-wrap;">'+l(t)+"</div></div>"),await joplin.views.dialogs.setButtons(s,[{id:"ok",title:"OK"}]),await joplin.views.dialogs.open(s)}async function x(t,o){await joplin.views.dialogs.setHtml(n,'<div style="padding:10px;min-width:300px;"><div style="margin-bottom:8px;font-size:13px;">'+l(t)+'</div><form name="inputForm"><input name="value" type="text" value="'+l(o||"")+'" style="width:100%;box-sizing:border-box;padding:6px 8px;font-size:13px;" /></form></div>'),await joplin.views.dialogs.setButtons(n,[{id:"ok",title:"OK"},{id:"cancel",title:e.cancel||"Cancel"}]);const a=await joplin.views.dialogs.open(n);return"ok"===a.id&&a.formData&&a.formData.inputForm&&a.formData.inputForm.value||null}let y="",N={},_="updated_desc";try{const e=String(await joplin.settings.value("noteSortMode")||"");["updated_desc","updated_asc","title_asc","title_desc","manual"].indexOf(e)>=0&&(_=e)}catch(e){}let b=[],v={},j=[],T=[],k=!1,S=!1,I=!0,D=null,E=[],F={},C=!0,M=!1;if(S=!0!==await joplin.settings.value("tagsDefaultExpanded"),!1!==await joplin.settings.value("restoreUiState"))try{const e=String(await joplin.settings.value("uiState")||"{}"),t=JSON.parse(e);t&&"object"==typeof t&&(t.collapsedFolders&&"object"==typeof t.collapsedFolders&&!Array.isArray(t.collapsedFolders)&&(N=t.collapsedFolders,M=!0),"boolean"==typeof t.tagsCollapsed&&(S=t.tagsCollapsed),"boolean"==typeof t.pinnedCollapsed&&(k=t.pinnedCollapsed),"boolean"==typeof t.trashCollapsed&&(I=t.trashCollapsed))}catch(e){}let O=null;function R(){O&&clearTimeout(O),O=setTimeout(async()=>{O=null;try{await joplin.settings.setValue("uiState",JSON.stringify({collapsedFolders:N,tagsCollapsed:S,pinnedCollapsed:k,trashCollapsed:I}))}catch(e){console.error("Joplin Explorer: failed to save UI state",e)}},500)}const A=await joplin.plugins.dataDir();let U=null;function J(e=600){U&&clearTimeout(U),U=setTimeout(async()=>{U=null,await q()},e)}let P=null,L={};async function H(){try{await joplin.settings.setValue("pinnedItems",JSON.stringify(T))}catch(e){console.error("Joplin Explorer: failed to save pinned items",e)}}async function z(){try{await joplin.settings.setValue("folderOrder",JSON.stringify(F))}catch(e){console.error("Joplin Explorer: failed to save folder order",e)}}function W(e){let t=e;for(;t;){delete N[t];const e=v[t];t=e?e.parent_id:null}}async function q(){try{const o=await async function(){let e=[],t=1,o=!0;for(;o;){const a=await joplin.data.get(["folders"],{fields:["id","title","parent_id","icon"],page:t,limit:100});e=e.concat(a.items),o=a.has_more,t++}return e}();await async function(){try{const e=await joplin.settings.value("folderOrder"),t=e?JSON.parse(e):{};F=t&&"object"==typeof t&&!Array.isArray(t)?t:{}}catch(e){F={}}}();let a=!1;const n=new Set(o.map(e=>e.id));for(const e of Object.keys(F))n.has(e)||(delete F[e],a=!0);a&&await z();for(const e of o)e.order=F[e.id]||0;b=o,v={};for(const e of o)v[e.id]=e;if(C){if(!M)for(const e of o)N[e.id]=!0;const e=await joplin.workspace.selectedNote();e&&(y=e.id,W(e.parent_id)),C=!1}const i=await async function(){let e=[],t=1,o=!0;for(;o;){const a=await joplin.data.get(["notes"],{fields:["id","title","parent_id","is_todo","todo_completed","updated_time","user_updated_time","order"],page:t,limit:100});e=e.concat(a.items),o=a.has_more,t++}return e}(),s={};for(const e of o)s[e.id]=[];for(const e of i)s[e.parent_id]&&s[e.parent_id].push(e);for(const e of Object.keys(s))s[e]=g(s[e],_);const r=[];for(const e of Object.keys(s))for(const t of s[e])r.push(t);j=r;const c=await joplin.settings.value("showFolderToggles"),h=await joplin.settings.value("openFolderIcon"),x=await joplin.settings.value("closedFolderIcon"),O=await joplin.settings.value("openPinnedIcon"),R=await joplin.settings.value("closedPinnedIcon"),U=await p(h,"📂","openFolderIcon",A),J=await p(x,"📁","closedFolderIcon",A),P=await p(O,"📌","openPinnedIcon",A),L=await p(R,"📌","closedPinnedIcon",A),q=!1!==c,V=function(e,t){const o={},a={},n={};for(const t of e)o[t.id]={type:"folder",id:t.id,title:t.title,parent_id:t.parent_id,icon:t.icon,order:t.order||0,note_count:0,children:[]},a[t.id]=[],n[t.id]=[];for(const e of Object.keys(t))if(n[e])for(const o of t[e])n[e].push({type:"note",id:o.id,title:o.title||"(untitled)",is_todo:o.is_todo,todo_completed:o.todo_completed});const i=[];for(const t of e){const e=o[t.id];t.parent_id&&o[t.parent_id]?a[t.parent_id].push(e):i.push(e)}function s(e){const t=a[e.id].sort(u);for(const e of t)s(e);e.note_count=n[e.id].length,e.children=t.concat(n[e.id])}i.sort(u);for(const e of i)s(e);const l=i;function r(e){let t=0;if(!e.children)return 0;for(const o of e.children)"note"===o.type?t++:"folder"===o.type&&(r(o),t+=o.total_count||0);return e.total_count=t,t}for(const e of l)r(e);return l}(o,s),B=w(V,y,N,0,q,U,J);if(!1!==await joplin.settings.value("showTagsSection"))try{let e=[],t=1,o=!0;for(;o;){const a=await joplin.data.get(["tags"],{fields:["id","title"],page:t,limit:100});e=e.concat(a.items),o=a.has_more,t++}e.sort((e,t)=>(e.title||"").localeCompare(t.title||""));let a=e.map(()=>"");e.length<=200&&(a=await Promise.all(e.map(e=>joplin.data.get(["tags",e.id,"notes"],{fields:["id"],limit:100}).then(e=>0===e.items.length?"0":e.has_more?"100+":String(e.items.length)).catch(()=>""))),e=e.filter((e,t)=>"0"!==a[t]),a=a.filter(e=>"0"!==e)),E=e.map((e,t)=>({id:e.id,title:e.title||"",count:a[t]||""}))}catch(e){E=[]}else E=[];await async function(){try{const e=await joplin.settings.value("pinnedItems");if(!e)return;const t=JSON.parse(e);if(t&&!Array.isArray(t)&&t.notes&&t.folders){T=[];for(const e of t.folders)T.push({id:e,type:"folder"});for(const e of t.notes)T.push({id:e,type:"note"});await H()}else Array.isArray(t)&&(T=t)}catch(e){T=[]}}();const G=new Set(o.map(e=>e.id)),Q=new Set(r.map(e=>e.id)),X=T.length;T=T.filter(e=>"folder"===e.type?G.has(e.id):Q.has(e.id)),T.length!==X&&await H();let Y="";const Z=T.length;if(Z>0){Y+='<div class="pinned-section-header'+(k?" collapsed":"")+'" id="pinned-header">',q&&(Y+='<span class="toggle">'+(k?"▶":"▼")+"</span>"),Y+=d(P,"icon-when-open")+d(L,"icon-when-collapsed")+'<span class="label">'+e.pinned+'</span><span class="count">'+Z+"</span></div>",Y+='<div class="pinned-section-body'+(k?" collapsed":"")+'" id="pinned-body">';for(const e of T)if("folder"===e.type){const t=v[e.id]||null;if(t){const e=f(t,!0,U,J);Y+='<div class="tree-item folder pinned-item" data-id="'+t.id+'" data-type="folder">',Y+=d(e,"folder-icon"),Y+='<span class="label">'+l(t.title)+"</span>",Y+="</div>"}}else{let t=null;for(const o of r)if(o.id===e.id){t=o;break}if(t){const e=t.id===y?" selected":"",o=m(t);Y+='<div class="tree-item note pinned-item'+e+'" data-id="'+t.id+'" data-type="note" data-todo="'+(t.is_todo?1:0)+'">',Y+='<span class="icon note-icon">'+o+"</span>",Y+='<span class="label">'+l(t.title)+"</span>",Y+="</div>"}}Y+="</div>"}let $="";if(E.length>0){$+='<div class="tags-section-header'+(S?" collapsed":"")+'" id="tags-header">',q&&($+='<span class="toggle">'+(S?"▶":"▼")+"</span>"),$+='<span class="icon">🏷️</span><span class="label">'+e.tags+'</span><span class="count">'+E.length+"</span></div>",$+='<div class="tags-section-body'+(S?" collapsed":"")+'" id="tags-body">';for(const e of E)$+='<div class="tree-item folder tag-folder collapsed" data-tag-id="'+e.id+'" data-type="tag">',q&&($+='<span class="toggle">▶</span>'),$+='<span class="icon">🏷️</span>',$+='<span class="label">'+l(e.title)+"</span>",e.count&&($+='<span class="count">'+e.count+"</span>"),$+="</div>",$+='<div class="tag-children collapsed" data-tag-id="'+e.id+'"></div>';$+="</div>"}let ee="";try{const t={};let o=0,a=!1,n=1,i=!0;for(;i;){const e=await joplin.data.get(["folders"],{fields:["id","deleted_time"],include_deleted:"1",page:n,limit:100});for(const a of e.items||[])a.deleted_time>0&&(t[a.id]=!0,o++);i=e.has_more,n++}const s=(await joplin.data.get(["notes"],{fields:["id","parent_id","deleted_time"],include_deleted:"1",order_by:"deleted_time",order_dir:"DESC",limit:100})).items||[];for(const e of s){if(!e.deleted_time)break;t[e.parent_id]||o++}100===s.length&&s[99].deleted_time>0&&(a=!0),(o>0||a)&&(ee+='<div class="trash-section-header'+(I?" collapsed":"")+'" id="trash-header">',q&&(ee+='<span class="toggle">'+(I?"▶":"▼")+"</span>"),ee+='<span class="icon">🗑️</span><span class="label">'+e.trash+'</span><span class="count">'+o+(a?"+":"")+"</span></div>",ee+='<div class="trash-children'+(I?" collapsed":"")+'" id="trash-children"></div>')}catch(e){}const te=l(JSON.stringify(T)),oe=o.length>0&&o.every(e=>!0===N[e.id]),ae={updated_desc:e.sortUpdatedDesc,updated_asc:e.sortUpdatedAsc,title_asc:e.sortTitleAsc,title_desc:e.sortTitleDesc,manual:e.sortManual},ne=l(JSON.stringify(e)),ie=String(await joplin.settings.value("expandAllMode")||"restore"),se='<div id="notes-in-list-root" data-i18n="'+ne+'" data-pinned="'+te+'" data-sort="'+l(_)+'" data-expand-mode="'+l(ie)+'" data-collapse-snapshot="'+l(JSON.stringify(D))+'"> <div class="toolbar"> <button id="btn-new" title="'+e.newItem+'">+</button> <button id="btn-sort" title="'+e.sort+'">'+ae[_]+'</button> <button id="btn-collapse-all" data-mode="'+(oe?"expand":"collapse")+'" title="'+(oe?e.expandAll:e.collapseAll)+'">'+(oe?"▼":"▲")+'</button> <button id="btn-refresh" title="'+e.refresh+'">↻</button> </div> <div class="search-bar"> <input id="search-input" type="text" placeholder="🔍 '+e.search+'" /> </div> <div id="tree-container">'+Y+B+$+ee+' <div id="drop-zone-empty" class="drop-zone-empty">+ '+e.dropCreateNotebook+'</div> </div> <div id="search-results" style="display:none;"></div> <div class="bottom-bar"> <button id="btn-sync" title="'+e.sync+'">🔄 '+e.sync+"</button> </div></div>";if(await joplin.views.panels.setHtml(t,se),ee&&!I)try{const e=await K();await joplin.views.panels.postMessage(t,{name:"trashNotes",folders:e.folders,notes:e.notes})}catch(e){}}catch(e){console.error("Notes In List: refresh error",e),await joplin.views.panels.setHtml(t,'<div style="padding:12px;color:red;">Error: '+l(String(e))+"</div>")}}async function V(e){try{const o=j.findIndex(t=>t.id===e),a=await joplin.data.get(["notes",e],{fields:["id","title","parent_id","is_todo","todo_completed","updated_time","user_updated_time","order"]});if(o<0||j[o].parent_id!==a.parent_id)return void await q();const n=j[o],i=0===_.indexOf("title_")&&(n.title||"")!==(a.title||""),s=0===_.indexOf("updated_")&&n.user_updated_time!==a.user_updated_time;if(j[o]=a,i||s)return void await q();await joplin.views.panels.postMessage(t,{name:"updateNote",id:a.id,title:a.title||"(untitled)",icon:m(a)})}catch(e){await q()}}async function B(e){let t=[],o=1,a=!0;for(;a&&t.length<200;){const n=await joplin.data.get(["tags",e,"notes"],{fields:["id","title","is_todo","todo_completed"],page:o,limit:50});t=t.concat(n.items),a=n.has_more,o++}return t.map(e=>({id:e.id,title:e.title||"(untitled)",is_todo:e.is_todo,todo_completed:e.todo_completed}))}async function K(){const e=[],t={},o={};try{let a=1,n=!0;for(;n;){const i=await joplin.data.get(["folders"],{fields:["id","title","parent_id","deleted_time"],include_deleted:"1",page:a,limit:100});for(const a of i.items||[])o[a.id]=a.parent_id||"",a.deleted_time>0&&(e.push({id:a.id,title:a.title||"(untitled)",parent_id:a.parent_id}),t[a.id]=!0);n=i.has_more,a++}}catch(e){}const a=[],n={},i=[];for(const o of e)o.parent_id&&t[o.parent_id]?(n[o.parent_id]=n[o.parent_id]||[]).push(o):i.push(o);const s=(e,t)=>{a.push({id:e.id,title:e.title,depth:t});for(const o of n[e.id]||[])s(o,t+1)};for(const e of i)s(e,0);await Promise.all(a.map(async e=>{try{const t=await joplin.data.get(["folders",e.id,"notes"],{fields:["id"],include_deleted:"1",limit:1});e.hasNotes=!(!t.items||!t.items.length)}catch(t){e.hasNotes=!0}}));const l=[];let r=1,d=!0;for(;d&&l.length<200;){const e=await joplin.data.get(["notes"],{fields:["id","title","parent_id","is_todo","todo_completed","deleted_time"],include_deleted:"1",order_by:"deleted_time",order_dir:"DESC",page:r,limit:50});let a=!1;for(const n of e.items||[]){if(!n.deleted_time){a=!0;break}let e=!1,i=n.parent_id,s=0;for(;i&&s++<50;){if(t[i]){e=!0;break}i=o[i]||""}e||l.push({id:n.id,title:n.title||"(untitled)",is_todo:n.is_todo,todo_completed:n.todo_completed})}if(a)break;d=e.has_more,r++}return{folders:a,notes:l}}async function G(e){const t={};try{let e=1,o=!0;for(;o;){const a=await joplin.data.get(["folders"],{fields:["id","parent_id"],include_deleted:"1",page:e,limit:100});for(const e of a.items||[])e.parent_id&&(t[e.parent_id]=t[e.parent_id]||[]).push(e.id);o=a.has_more,e++}}catch(e){}const o=async e=>{for(const a of t[e]||[])await o(a);try{let t=1,o=!0;for(;o;){const a=await joplin.data.get(["folders",e,"notes"],{fields:["id"],include_deleted:"1",page:t,limit:100});for(const e of a.items||[])try{await joplin.data.delete(["notes",e.id],{permanent:"1"})}catch(e){}o=(a.items||[]).length>0&&a.has_more}}catch(e){}try{await joplin.data.delete(["folders",e],{permanent:"1"})}catch(e){}};await o(e)}await joplin.settings.onChange(async e=>{e.keys&&e.keys.indexOf("autoRefresh")>=0&&await Z(),e.keys&&(e.keys.indexOf("expandAllMode")>=0||e.keys.indexOf("showTagsSection")>=0||e.keys.indexOf("showFolderToggles")>=0||e.keys.indexOf("openFolderIcon")>=0||e.keys.indexOf("closedFolderIcon")>=0||e.keys.indexOf("openPinnedIcon")>=0||e.keys.indexOf("closedPinnedIcon")>=0)&&(function(){for(const e of Object.keys(c))delete c[e]}(),await q())}),await joplin.views.panels.onMessage(t,async o=>{if("openNote"===o.name)y=o.id,await joplin.commands.execute("openNote",o.id);else if("refresh"===o.name)await q();else if("toggleFolder"===o.name)N[o.id]?delete N[o.id]:N[o.id]=!0,R();else if("collapseAll"===o.name){for(const e of b)N[e.id]=!0;Array.isArray(o.prevCollapsed)&&(D=o.prevCollapsed.map(String)),R()}else if("expandAll"===o.name){if(N={},Array.isArray(o.collapsedIds))for(const e of o.collapsedIds)N[String(e)]=!0;R()}else if("panelReady"===o.name)await q();else if("refreshView"===o.name)await q();else if("newNotebook"===o.name){const o=await x(e.promptNewNotebookName,"");if(!o||!o.trim())return;const a=await joplin.data.post(["folders"],null,{title:o.trim()});delete N[a.id],await q(),await joplin.views.panels.postMessage(t,{name:"scrollToFolder",folderId:a.id})}else if("newNote"===o.name){await joplin.commands.execute("newNote");const e=await joplin.workspace.selectedNote();e&&(y=e.id,W(e.parent_id)),await q()}else if("newTodo"===o.name){await joplin.commands.execute("newTodo");const e=await joplin.workspace.selectedNote();e&&(y=e.id,W(e.parent_id)),await q()}else if("search"===o.name)await async function(e){const o=e.query;if(o&&o.trim())try{const a=o.toLowerCase(),n={};for(const e of b)n[e.id]=e.title;let i=[],s=1,l=!0;for(;l&&i.length<100;){const e=await joplin.data.get(["search"],{query:o,fields:["id","title","body","parent_id","is_todo","todo_completed"],page:s,limit:20});i=i.concat(e.items),l=e.has_more,s++}const r=new Set(i.map(e=>e.id)),d=[];for(const e of j)!r.has(e.id)&&(e.title||"").toLowerCase().indexOf(a)>=0&&d.push(e);for(let e=0;e<d.length&&e<50;e++)try{const t=await joplin.data.get(["notes",d[e].id],{fields:["id","title","body","parent_id","is_todo","todo_completed"]});i.push(t)}catch(e){}const c=[];for(const e of i){let t="";const o=e.body||"",i=o.toLowerCase().indexOf(a);if(i>=0){const e=Math.max(0,i-40),n=Math.min(o.length,i+a.length+80);t=(e>0?"...":"")+o.substring(e,n).replace(/\n/g," ")+(n<o.length?"...":"")}else t=o.substring(0,120).replace(/\n/g," ")+(o.length>120?"...":"");c.push({id:e.id,title:e.title||"(untitled)",is_todo:e.is_todo,todo_completed:e.todo_completed,snippet:t,folderName:n[e.parent_id]||""})}let p=[],u=1,f=!0;for(;f;){const e=await joplin.data.get(["tags"],{fields:["id","title"],page:u,limit:100});p=p.concat(e.items),f=e.has_more,u++}const m=[];for(const e of p)if((e.title||"").toLowerCase().indexOf(a)>=0){let t=0;try{const o=await joplin.data.get(["tags",e.id,"notes"],{fields:["id"],limit:100});t=o.has_more?o.items.length+"+":o.items.length}catch(e){}m.push({id:e.id,title:e.title,noteCount:t})}const w=[];for(const e of b)if((e.title||"").toLowerCase().indexOf(a)>=0){let t="";if(e.icon&&"string"==typeof e.icon)try{const o=JSON.parse(e.icon);o&&o.emoji&&(t=String(o.emoji))}catch(e){}w.push({id:e.id,title:e.title,parent_id:e.parent_id,iconEmoji:t})}await joplin.views.panels.postMessage(t,{name:"searchResults",notes:c,tags:m,folders:w,query:o,searchId:e.searchId})}catch(e){console.error("Joplin Explorer: search error",e)}else await joplin.views.panels.postMessage(t,{name:"searchResults",results:null,query:"",searchId:e.searchId})}(o);else if("loadTagNotes"===o.name)try{const e=o.tagId;let a=[],n=1,i=!0;for(;i&&a.length<100;){const t=await joplin.data.get(["tags",e,"notes"],{fields:["id","title","parent_id","is_todo","todo_completed"],page:n,limit:50});a=a.concat(t.items),i=t.has_more,n++}const s={};for(const e of b)s[e.id]=e.title;const l=a.map(e=>({id:e.id,title:e.title||"(untitled)",is_todo:e.is_todo,todo_completed:e.todo_completed,snippet:"",folderName:s[e.parent_id]||""}));await joplin.views.panels.postMessage(t,{name:"tagNotes",tagId:e,notes:l})}catch(e){console.error("Joplin Explorer: loadTagNotes error",e)}else if("toggleTagsSection"===o.name)S=!S,R();else if("tagFolderNotes"===o.name)try{const e=await B(o.tagId);await joplin.views.panels.postMessage(t,{name:"tagFolderNotes",tagId:o.tagId,notes:e})}catch(e){console.error("Joplin Explorer: tagFolderNotes error",e)}else if("tagNoteAdd"===o.name)try{await joplin.data.post(["tags",o.tagId,"notes"],null,{id:o.noteId});const e=await B(o.tagId);await joplin.views.panels.postMessage(t,{name:"tagFolderNotes",tagId:o.tagId,notes:e})}catch(e){console.error("Joplin Explorer: tagNoteAdd error",e)}else if("toggleTrashSection"===o.name)I=!I,R();else if("trashFolderNotes"===o.name)try{let e=[],a=1,n=!0;for(;n&&e.length<200;){const t=await joplin.data.get(["folders",o.folderId,"notes"],{fields:["id","title","is_todo","todo_completed"],include_deleted:"1",page:a,limit:50});e=e.concat((t.items||[]).map(e=>({id:e.id,title:e.title||"(untitled)",is_todo:e.is_todo,todo_completed:e.todo_completed}))),n=t.has_more,a++}await joplin.views.panels.postMessage(t,{name:"trashFolderNotes",folderId:o.folderId,notes:e})}catch(e){console.error("Joplin Explorer: trashFolderNotes error",e)}else if("trashNotes"===o.name)try{const e=await K();await joplin.views.panels.postMessage(t,{name:"trashNotes",folders:e.folders,notes:e.notes})}catch(e){console.error("Joplin Explorer: trashNotes error",e)}else if("locateFolder"===o.name)try{W(o.folderId),await q(),await joplin.views.panels.postMessage(t,{name:"exitSearchAndLocate",folderId:o.folderId})}catch(e){console.error("Joplin Explorer: locateFolder error",e)}else if("locatePinnedFolder"===o.name)try{W(o.folderId),await q(),await joplin.views.panels.postMessage(t,{name:"scrollToFolder",folderId:o.folderId})}catch(e){console.error("Joplin Explorer: locatePinnedFolder error",e)}else if("reorderPinned"===o.name)try{const e=o.dragId,t=o.targetId,a=o.position,n=T.findIndex(t=>t.id===e);if(n<0)return;const i=T[n];T.splice(n,1);let s=T.findIndex(e=>e.id===t);s<0?T.push(i):("after"===a&&s++,T.splice(s,0,i)),await H(),await q()}catch(e){console.error("Joplin Explorer: reorderPinned error",e)}else if("togglePinnedCollapse"===o.name)k=!k,R();else if("cycleSort"===o.name){const e=["updated_desc","updated_asc","title_asc","title_desc","manual"],t=e.indexOf(_);_=e[(t+1)%e.length];try{await joplin.settings.setValue("noteSortMode",_)}catch(e){}await q()}else if("sync"===o.name)try{await joplin.commands.execute("synchronize")}catch(o){console.error("Joplin Explorer: sync command failed",o),await joplin.views.panels.postMessage(t,{name:"syncState",state:"error"});const a=o&&o.message?String(o.message):String(o);await h(e.syncFailed,a)}else if("contextMenu"===o.name)await async function(o){const a=o.action,n=o.id,i=o.itemType;try{if("folder"===i)switch(a){case"newNote":{const t=await joplin.data.post(["notes"],null,{title:e.newNote,parent_id:n});await joplin.commands.execute("openNote",t.id),y=t.id,W(n);break}case"newTodo":{const t=await joplin.data.post(["notes"],null,{title:e.newTodo,parent_id:n,is_todo:1});await joplin.commands.execute("openNote",t.id),y=t.id,W(n);break}case"newSubNotebook":{const t=await x(e.newNotebook,"");if(t&&t.trim()){const e=await joplin.data.post(["folders"],null,{title:t.trim(),parent_id:n});delete N[n],delete N[e.id]}break}case"deleteFolder":{const t=await joplin.data.get(["folders",n],{fields:["title"]});await r(e.confirmDeleteFolder+"\n\n"+t.title)&&await joplin.data.delete(["folders",n]);break}case"renameFolder":{const t=await joplin.data.get(["folders",n],{fields:["title"]}),o=await x(e.promptRename,t.title);o&&o.trim()&&await joplin.data.put(["folders",n],null,{title:o.trim()});break}case"exportFolder":try{await joplin.commands.execute("exportFolders",[n])}catch(e){}break;case"pinFolder":T.some(e=>e.id===n)||(T.push({id:n,type:"folder"}),await H());break;case"unpinFolder":T=T.filter(e=>e.id!==n),await H()}else if("note"===i)switch(a){case"openNote":await joplin.commands.execute("openNote",n),y=n;break;case"openInNewWindow":try{await joplin.commands.execute("openNoteInNewWindow",n)}catch(e){await joplin.commands.execute("openNote",n)}break;case"copyLink":{const e=await joplin.data.get(["notes",n],{fields:["id","title"]}),o="["+e.title+"](:/"+e.id+")";try{await joplin.clipboard.writeText(o)}catch(e){await joplin.views.panels.postMessage(t,{name:"copyText",text:o})}break}case"duplicateNote":{const e=await joplin.data.get(["notes",n],{fields:["title","body","parent_id","is_todo"]}),t=await joplin.data.post(["notes"],null,{title:e.title+" (copy)",body:e.body,parent_id:e.parent_id,is_todo:e.is_todo});await joplin.commands.execute("openNote",t.id),y=t.id;break}case"switchNoteType":{const e=await joplin.data.get(["notes",n],{fields:["is_todo"]});await joplin.data.put(["notes",n],null,{is_todo:e.is_todo?0:1});break}case"toggleTodo":{const e=await joplin.data.get(["notes",n],{fields:["is_todo","todo_completed"]});e.is_todo&&await joplin.data.put(["notes",n],null,{todo_completed:e.todo_completed?0:Date.now()});break}case"publishNote":try{await joplin.commands.execute("showShareNoteDialog",[n])}catch(e){}break;case"exportPdf":try{await joplin.commands.execute("exportPdf",[n])}catch(e){}break;case"exportNote":try{const e=await joplin.views.dialogs.showOpenDialog({properties:["openDirectory"]}),t=Array.isArray(e)?e[0]:e;t&&await joplin.commands.execute("exportNotes",[n],o.format||"md",t)}catch(e){console.error("Joplin Explorer: exportNote error",e)}break;case"setTags":try{await joplin.commands.execute("setTags",[n])}catch(e){}break;case"moveToFolderDialog":try{await joplin.commands.execute("moveToFolder",[n])}catch(e){}break;case"copyExternalLink":{const e="joplin://x-callback-url/openNote?id="+n;try{await joplin.clipboard.writeText(e)}catch(o){await joplin.views.panels.postMessage(t,{name:"copyText",text:e})}break}case"renameNote":{const t=await joplin.data.get(["notes",n],{fields:["title"]}),o=await x(e.promptRename,t.title);o&&o.trim()&&await joplin.data.put(["notes",n],null,{title:o.trim()});break}case"moveNote":if(o.targetFolderName){let e=null;for(const t of b)if(t.title===o.targetFolderName){e=t;break}e&&await joplin.data.put(["notes",n],null,{parent_id:e.id})}break;case"noteInfo":{const t=await joplin.data.get(["notes",n],{fields:["id","title","created_time","updated_time","is_todo","parent_id","body"]}),o=v[t.parent_id]?v[t.parent_id].title:"",a=(t.body||"").length,i="ID: "+t.id+"\n"+(e.ctxRenameNote||"Title")+": "+t.title+"\n"+(e.newNotebook||"Notebook")+": "+o+"\n"+(e.sortUpdatedDesc?e.sortUpdatedDesc.replace(/[↓↑\u2193\u2191]\s*/,""):"Created")+": "+new Date(t.created_time).toLocaleString()+"\n"+(e.sortUpdatedAsc?e.sortUpdatedAsc.replace(/[↓↑\u2193\u2191]\s*/,""):"Updated")+": "+new Date(t.updated_time).toLocaleString()+"\nType: "+(t.is_todo?"To-do":"Note")+"\nSize: "+a+" chars";await h(t.title,i);break}case"deleteNote":{const t=await joplin.data.get(["notes",n],{fields:["title"]});await r(e.confirmDeleteNote+"\n\n"+t.title)&&await joplin.data.delete(["notes",n]);break}case"untagNote":if(o.tagId){await joplin.data.delete(["tags",o.tagId,"notes",n]);try{const e=await B(o.tagId);await joplin.views.panels.postMessage(t,{name:"tagFolderNotes",tagId:o.tagId,notes:e})}catch(e){}}break;case"pinNote":T.some(e=>e.id===n)||(T.push({id:n,type:"note"}),await H());break;case"unpinNote":T=T.filter(e=>e.id!==n),await H()}else if("tag"===i)switch(a){case"renameTag":{const t=await joplin.data.get(["tags",n],{fields:["title"]}),o=await x(e.ctxRenameTag,t.title);o&&o.trim()&&await joplin.data.put(["tags",n],null,{title:o.trim()});break}case"deleteTag":{const t=await joplin.data.get(["tags",n],{fields:["title"]});await r(e.confirmDeleteTag+"\n\n"+t.title)&&await joplin.data.delete(["tags",n]);break}}else if("trashSection"===i){if("emptyTrash"===a&&await r(e.confirmEmptyTrash)){try{await joplin.commands.execute("emptyTrash")}catch(e){const t=await K();for(const e of t.folders)0===e.depth&&await G(e.id);for(const e of t.notes)try{await joplin.data.delete(["notes",e.id],{permanent:"1"})}catch(e){}}try{const e=await K();await joplin.views.panels.postMessage(t,{name:"trashNotes",folders:e.folders,notes:e.notes})}catch(e){}}}else if("trashNote"===i||"trashFolder"===i){const o="trashFolder"===i;switch(a){case"restoreItem":try{await joplin.commands.execute(o?"restoreFolder":"restoreNote",[n])}catch(e){console.error("Joplin Explorer: restore error",e)}break;case"permanentDeleteItem":{const t=o?"folders":"notes";let a="";try{const e=await joplin.data.get([t,n],{fields:["title"],include_deleted:"1"});a=e?e.title:""}catch(e){}if(await r(e.confirmDeleteNote+"\n\n"+a))if(o)await G(n);else try{await joplin.data.delete(["notes",n],{permanent:"1"})}catch(e){try{await joplin.commands.execute("permanentlyDeleteNote",[n])}catch(e){}}break}}try{const e=await K();await joplin.views.panels.postMessage(t,{name:"trashNotes",folders:e.folders,notes:e.notes})}catch(e){}}await q()}catch(e){console.error("Notes In List: context menu error",e)}}(o);else if("dragDrop"===o.name)await async function(e){try{const t=e.dragId,o=e.dragType,a=e.targetId,n=e.position;if("note"===o)if(v[a])await joplin.data.put(["notes",t],null,{parent_id:a});else{const e=await joplin.data.get(["notes",a],{fields:["parent_id"]});"manual"!==_||"above"!==n&&"below"!==n?await joplin.data.put(["notes",t],null,{parent_id:e.parent_id}):await async function(e,t,o){const a=(await joplin.data.get(["notes",t],{fields:["parent_id"]})).parent_id,n=j.filter(t=>t.parent_id===a&&t.id!==e).sort((e,t)=>{const o=e.order||0,a=t.order||0;return o!==a?a-o:(t.user_updated_time||0)-(e.user_updated_time||0)}),i=n.findIndex(e=>e.id===t),s=i<0?n.length:"above"===o?i:i+1,l=s>0?n[s-1]:null,r=s<n.length?n[s]:null,d=l?l.order||0:null,c=r?r.order||0:null,p=1e6;if(n.every(e=>0===(e.order||0))||null!==d&&null!==c&&d-c<2){const t=Date.now(),o=n.slice();o.splice(s,0,null);let i=t;const l=[];for(let e=0;e<o.length;e++){const a=t-e*p,n=o[e];null===n?i=a:l.push(joplin.data.put(["notes",n.id],null,{order:a}))}return await Promise.all(l),void await joplin.data.put(["notes",e],null,{parent_id:a,order:i})}let u;u=null!==d&&null!==c?(d+c)/2:null!==d?d-p:null!==c?c+p:Date.now(),await joplin.data.put(["notes",e],null,{parent_id:a,order:u})}(t,a,n)}else if("folder"===o){const e=!!v[a];"into"===n?e&&t!==a&&await joplin.data.put(["folders",t],null,{parent_id:a}):!e||"above"!==n&&"below"!==n||await async function(e,t,o){const a=v[t],n=v[e];if(!a||!n||e===t)return;const i=a.parent_id||"";let s=i;for(;s;){if(s===e)return;s=v[s]&&v[s].parent_id||""}const l=b.filter(t=>(t.parent_id||"")===i&&t.id!==e).sort((e,t)=>{const o=e.order||0,a=t.order||0;return o!==a?a-o:(e.title||"").localeCompare(t.title||"")}),r=l.findIndex(e=>e.id===t),d=r<0?l.length:"above"===o?r:r+1,c=d>0?l[d-1]:null,p=d<l.length?l[d]:null,u=c?c.order||0:null,f=p?p.order||0:null,m=l.every(e=>0===(e.order||0)),w=null!==u&&null!==f&&u-f<2,g=1e6;if((n.parent_id||"")!==i&&await joplin.data.put(["folders",e],null,{parent_id:i}),m||w){const t=Date.now(),o=l.slice();o.splice(d,0,null);for(let a=0;a<o.length;a++){const n=t-a*g,i=o[a];null===i?F[e]=n:F[i.id]=n}return void await z()}let h;h=null!==u&&null!==f?(u+f)/2:null!==u?u-g:null!==f?f+g:Date.now(),F[e]=h,await z()}(t,a,n)}await q()}catch(e){console.error("Notes In List: drag drop error",e)}}(o);else if("dragToEmpty"===o.name)try{const t=o.dragId,a=o.dragType,n=await x(e.promptNewNotebookName,"");if(!n||!n.trim())return;const i=await joplin.data.post(["folders"],null,{title:n.trim()});"note"===a?await joplin.data.put(["notes",t],null,{parent_id:i.id}):"folder"===a&&t!==i.id&&await joplin.data.put(["folders",t],null,{parent_id:i.id}),await q()}catch(e){console.error("Notes In List: drag to empty error",e)}});let Q="",X=null;async function Y(){try{if(!Q){const e=await joplin.data.get(["events"]);return void(Q=String(e.cursor||""))}let e=!1,t=0;for(;t++<20;){const t=await joplin.data.get(["events"],{cursor:Q});for(const o of t.items||[])2===Number(o.type)&&o.item_id===y||(e=!0);if(t.cursor&&(Q=String(t.cursor)),!t.has_more)break}e&&J(300)}catch(e){X&&(clearInterval(X),X=null),console.warn("Joplin Explorer: change-events polling disabled",e)}}async function Z(){const e=!1!==await joplin.settings.value("autoRefresh");X&&(clearInterval(X),X=null),e&&(Q="",await Y(),X=setInterval(Y,5e3))}await Z(),await joplin.workspace.onNoteSelectionChange(async()=>{const e=await joplin.workspace.selectedNote();e&&e.id!==y&&(y=e.id,await joplin.views.panels.postMessage(t,{name:"selectNote",id:e.id}))}),await joplin.workspace.onNoteChange(async e=>{var t;e&&e.id?(t=e.id,L[t]=!0,P&&clearTimeout(P),P=setTimeout(async()=>{P=null;const e=Object.keys(L);L={};for(const t of e)await V(t)},600)):J()});try{await joplin.workspace.onSyncStart(async()=>{await joplin.views.panels.postMessage(t,{name:"syncState",state:"syncing"})})}catch(e){console.warn("Joplin Explorer: onSyncStart not available",e)}try{await joplin.workspace.onSyncComplete(async o=>{const a=!(!o||!o.withErrors);await q(),await joplin.views.panels.postMessage(t,{name:"syncState",state:a?"error":"done"}),a&&await h(e.syncFailed,"Joplin reported errors during synchronisation. Open the Synchronisation Status screen (Tools → Synchronisation Status) to see the details.")})}catch(e){console.warn("Joplin Explorer: onSyncComplete not available",e)}await q()}})})();
|
|
1
|
+
(()=>{"use strict";var e={982(e){e.exports=require("crypto")},896(e){e.exports=require("fs")},928(e){e.exports=require("path")}},t={};function o(a){var i=t[a];if(void 0!==i)return i.exports;var n=t[a]={exports:{}};return e[a](n,n.exports,o),n.exports}const a={zh_CN:{newNotebook:"新建笔记本",newNote:"新建笔记",newTodo:"新建待办",sort:"排序",collapseAll:"全部折叠",expandAll:"全部展开",search:"搜索笔记内容...",searchResultCount:"找到 {count} 条结果",searchNoResult:"没有找到匹配的笔记",searching:"搜索中...",sync:"同步",syncing:"同步中...",syncDone:"✔ 同步完成",syncFailed:"⚠ 同步失败",loading:"加载中...",sortUpdatedDesc:"↓ 修改时间",sortUpdatedAsc:"↑ 修改时间",sortTitleAsc:"↑ 标题",sortTitleDesc:"↓ 标题",sortManual:"⇅ 手动排序",ctxNewNoteHere:"在此新建笔记",ctxNewTodoHere:"在此新建待办",ctxNewSubNotebook:"新建子笔记本",ctxRenameFolder:"重命名",ctxExportFolder:"导出笔记本",ctxDeleteFolder:"删除笔记本",ctxOpenNote:"打开笔记",ctxOpenInNewWindow:"在新窗口中打开",ctxCopyLink:"复制 Markdown 链接",ctxDuplicateNote:"复制副本",ctxSwitchNoteType:"笔记/待办 切换",ctxToggleTodo:"切换完成状态",ctxRenameNote:"重命名",ctxMoveNote:"移动到笔记本...",ctxNoteInfo:"笔记属性",ctxDeleteNote:"删除笔记",confirmDeleteFolder:"确定删除此笔记本及其所有内容吗?",confirmDeleteNote:"确定删除此笔记吗?",promptRename:"请输入新名称:",promptMoveNote:"请输入目标笔记本名称:",promptNewNotebookName:"请输入新笔记本名称:",dropCreateNotebook:"释放以创建新笔记本",searchSectionNotes:"笔记",searchSectionTags:"标签",searchSectionFolders:"笔记本",searchTagNoteCount:"{count} 条笔记",pinned:"收藏夹",tags:"标签",ctxRenameTag:"重命名标签",ctxDeleteTag:"删除标签",ctxUntagNote:"从标签移除",confirmDeleteTag:"删除该标签?(只删除标签本身,不会删除笔记)",ctxPublishNote:"发布笔记",ctxExport:"导出",refresh:"刷新",newItem:"新建",trash:"回收站",ctxRestoreNote:"恢复",ctxPermanentDelete:"彻底删除",ctxEmptyTrash:"清空回收站",confirmEmptyTrash:"清空回收站?所有已删除的笔记本和笔记将被永久删除,无法恢复。",smartFolders:"智能文件夹",smartRecent:"最近更新",smartTodos:"未完成待办",pvType:"类型",pvSize:"大小",pvCreated:"创建",pvUpdated:"更新",pvNote:"笔记",pvTodo:"待办",pvChars:"字符",ctxSetTags:"设置标签",ctxMoveToFolder:"移动到笔记本",ctxCopyExternalLink:"复制外部链接",ctxPin:"📌 收藏",ctxUnpin:"取消收藏",cancel:"取消"},zh_TW:{newNotebook:"新建筆記本",newNote:"新建筆記",newTodo:"新建待辦",sort:"排序",collapseAll:"全部摺疊",expandAll:"全部展開",search:"搜尋筆記內容...",searchResultCount:"找到 {count} 條結果",searchNoResult:"沒有找到匹配的筆記",searching:"搜尋中...",sync:"同步",syncing:"同步中...",syncDone:"✔ 同步完成",syncFailed:"⚠ 同步失敗",loading:"載入中...",sortUpdatedDesc:"↓ 修改時間",sortUpdatedAsc:"↑ 修改時間",sortTitleAsc:"↑ 標題",sortTitleDesc:"↓ 標題",sortManual:"⇅ 手動排序",ctxNewNoteHere:"在此新建筆記",ctxNewTodoHere:"在此新建待辦",ctxNewSubNotebook:"新建子筆記本",ctxRenameFolder:"重新命名",ctxExportFolder:"匯出筆記本",ctxDeleteFolder:"刪除筆記本",ctxOpenNote:"開啟筆記",ctxOpenInNewWindow:"在新視窗中開啟",ctxCopyLink:"複製 Markdown 連結",ctxDuplicateNote:"複製副本",ctxSwitchNoteType:"筆記/待辦 切換",ctxToggleTodo:"切換完成狀態",ctxRenameNote:"重新命名",ctxMoveNote:"移動到筆記本...",ctxNoteInfo:"筆記屬性",ctxDeleteNote:"刪除筆記",confirmDeleteFolder:"確定刪除此筆記本及其所有內容嗎?",confirmDeleteNote:"確定刪除此筆記嗎?",promptRename:"請輸入新名稱:",promptMoveNote:"請輸入目標筆記本名稱:",promptNewNotebookName:"請輸入新筆記本名稱:",dropCreateNotebook:"釋放以建立新筆記本",searchSectionNotes:"筆記",searchSectionTags:"標籤",searchSectionFolders:"筆記本",searchTagNoteCount:"{count} 條筆記",pinned:"收藏夾",tags:"標籤",ctxRenameTag:"重新命名標籤",ctxDeleteTag:"刪除標籤",ctxUntagNote:"自標籤移除",confirmDeleteTag:"刪除該標籤?(僅刪除標籤本身,不會刪除筆記)",ctxPublishNote:"發佈筆記",ctxExport:"匯出",refresh:"重新整理",newItem:"新增",trash:"垃圾桶",ctxRestoreNote:"還原",ctxPermanentDelete:"永久刪除",ctxEmptyTrash:"清空垃圾桶",confirmEmptyTrash:"清空垃圾桶?所有已刪除的筆記本和筆記將被永久刪除,無法還原。",smartFolders:"智慧資料夾",smartRecent:"最近更新",smartTodos:"未完成待辦",pvType:"類型",pvSize:"大小",pvCreated:"建立",pvUpdated:"更新",pvNote:"筆記",pvTodo:"待辦",pvChars:"字元",ctxSetTags:"設定標籤",ctxMoveToFolder:"移動到筆記本",ctxCopyExternalLink:"複製外部連結",ctxPin:"📌 收藏",ctxUnpin:"取消收藏",cancel:"取消"},en_US:{newNotebook:"New Notebook",newNote:"New Note",newTodo:"New To-do",sort:"Sort",collapseAll:"Collapse All",expandAll:"Expand All",search:"Search note contents...",searchResultCount:"{count} results found",searchNoResult:"No matching notes found",searching:"Searching...",sync:"Synchronise",syncing:"Syncing...",syncDone:"✔ Sync Done",syncFailed:"⚠ Sync Failed",loading:"Loading...",sortUpdatedDesc:"↓ Updated",sortUpdatedAsc:"↑ Updated",sortTitleAsc:"↑ Title",sortTitleDesc:"↓ Title",sortManual:"⇅ Manual",ctxNewNoteHere:"New Note Here",ctxNewTodoHere:"New To-do Here",ctxNewSubNotebook:"New Sub-notebook",ctxRenameFolder:"Rename",ctxExportFolder:"Export Notebook",ctxDeleteFolder:"Delete Notebook",ctxOpenNote:"Open Note",ctxOpenInNewWindow:"Open in New Window",ctxCopyLink:"Copy Markdown Link",ctxDuplicateNote:"Duplicate",ctxSwitchNoteType:"Switch Note/To-do",ctxToggleTodo:"Toggle Completed",ctxRenameNote:"Rename",ctxMoveNote:"Move to Notebook...",ctxNoteInfo:"Note Properties",ctxDeleteNote:"Delete Note",confirmDeleteFolder:"Delete this notebook and all its contents?",confirmDeleteNote:"Delete this note?",promptRename:"Enter new name:",promptMoveNote:"Enter target notebook name:",promptNewNotebookName:"Enter new notebook name:",dropCreateNotebook:"Release to create a new notebook",searchSectionNotes:"Notes",searchSectionTags:"Tags",searchSectionFolders:"Notebooks",searchTagNoteCount:"{count} notes",pinned:"Pinned",tags:"Tags",ctxRenameTag:"Rename tag",ctxDeleteTag:"Delete tag",ctxUntagNote:"Remove from tag",confirmDeleteTag:"Delete this tag? (Only the tag is removed - notes are kept.)",ctxPublishNote:"Publish note",ctxExport:"Export",refresh:"Refresh",newItem:"New",trash:"Trash",ctxRestoreNote:"Restore",ctxPermanentDelete:"Delete permanently",ctxEmptyTrash:"Empty trash",confirmEmptyTrash:"Empty the trash? All deleted notebooks and notes will be permanently removed. This cannot be undone.",smartFolders:"Smart folders",smartRecent:"Recently updated",smartTodos:"Open to-dos",pvType:"Type",pvSize:"Size",pvCreated:"Created",pvUpdated:"Updated",pvNote:"Note",pvTodo:"To-do",pvChars:"chars",ctxSetTags:"Set tags",ctxMoveToFolder:"Move to notebook",ctxCopyExternalLink:"Copy external link",ctxPin:"📌 Pin",ctxUnpin:"Unpin",cancel:"Cancel"},ru:{newNotebook:"Новый блокнот",newNote:"Новая заметка",newTodo:"Новая задача",sort:"Сортировка",collapseAll:"Свернуть все",expandAll:"Развернуть все",search:"Искать в содержимом заметок...",searchResultCount:"Найдено результатов: {count}",searchNoResult:"Заметки не найдены",searching:"Поиск...",sync:"Синхронизировать",syncing:"Синхронизация...",syncDone:"✔ Синхронизация завершена",syncFailed:"⚠ Ошибка синхронизации",loading:"Загрузка...",sortUpdatedDesc:"↓ Обновлено",sortUpdatedAsc:"↑ Обновлено",sortTitleAsc:"↑ Название",sortTitleDesc:"↓ Название",sortManual:"⇅ Вручную",ctxNewNoteHere:"Создать заметку здесь",ctxNewTodoHere:"Создать задачу здесь",ctxNewSubNotebook:"Новый вложенный блокнот",ctxRenameFolder:"Переименовать",ctxExportFolder:"Экспортировать блокнот",ctxDeleteFolder:"Удалить блокнот",ctxOpenNote:"Открыть заметку",ctxOpenInNewWindow:"Открыть в новом окне",ctxCopyLink:"Скопировать Markdown-ссылку",ctxDuplicateNote:"Создать копию",ctxSwitchNoteType:"Переключить между заметкой и задачей",ctxToggleTodo:"Переключить статус выполнения",ctxRenameNote:"Переименовать",ctxMoveNote:"Переместить в блокнот...",ctxNoteInfo:"Свойства заметки",ctxDeleteNote:"Удалить заметку",confirmDeleteFolder:"Удалить блокнот и все его содержимое?",confirmDeleteNote:"Удалить заметку?",promptRename:"Введите новое название:",promptMoveNote:"Переместить в блокнот:",promptNewNotebookName:"Введите название нового блокнота:",dropCreateNotebook:"Отпустите, чтобы создать новый блокнот",searchSectionNotes:"Заметки",searchSectionTags:"Метки",searchSectionFolders:"Блокноты",searchTagNoteCount:"Заметок: {count}",pinned:"Закрепленные",tags:"Теги",ctxRenameTag:"Переименовать тег",ctxDeleteTag:"Удалить тег",ctxUntagNote:"Убрать из тега",confirmDeleteTag:"Удалить этот тег? (Удаляется только тег, заметки сохраняются.)",ctxPublishNote:"Опубликовать заметку",ctxExport:"Экспорт",refresh:"Обновить",newItem:"Создать",trash:"Корзина",ctxRestoreNote:"Восстановить",ctxPermanentDelete:"Удалить навсегда",ctxEmptyTrash:"Очистить корзину",confirmEmptyTrash:"Очистить корзину? Все удалённые блокноты и заметки будут удалены безвозвратно.",smartFolders:"Умные папки",smartRecent:"Недавно обновлённые",smartTodos:"Незавершённые задачи",pvType:"Тип",pvSize:"Размер",pvCreated:"Создано",pvUpdated:"Обновлено",pvNote:"Заметка",pvTodo:"Задача",pvChars:"симв.",ctxSetTags:"Назначить теги",ctxMoveToFolder:"Переместить в блокнот",ctxCopyExternalLink:"Копировать внешнюю ссылку",ctxPin:"📌 Закрепить",ctxUnpin:"Открепить",cancel:"Отмена"},ja_JP:{newNotebook:"新規ノートブック",newNote:"新規ノート",newTodo:"新規タスク",sort:"並べ替え",collapseAll:"すべて折りたたむ",expandAll:"すべて展開",search:"ノート内容を検索...",searchResultCount:"{count} 件の結果",searchNoResult:"一致するノートが見つかりません",searching:"検索中...",sync:"同期",syncing:"同期中...",syncDone:"✔ 同期完了",syncFailed:"⚠ 同期に失敗しました",loading:"読み込み中...",sortUpdatedDesc:"↓ 更新日時",sortUpdatedAsc:"↑ 更新日時",sortTitleAsc:"↑ タイトル",sortTitleDesc:"↓ タイトル",sortManual:"⇅ 手動",ctxNewNoteHere:"ここに新規ノート",ctxNewTodoHere:"ここに新規タスク",ctxNewSubNotebook:"新規サブノートブック",ctxRenameFolder:"名前を変更",ctxExportFolder:"ノートブックをエクスポート",ctxDeleteFolder:"ノートブックを削除",ctxOpenNote:"ノートを開く",ctxOpenInNewWindow:"新しいウィンドウで開く",ctxCopyLink:"Markdownリンクをコピー",ctxDuplicateNote:"複製",ctxSwitchNoteType:"ノート/タスク切り替え",ctxToggleTodo:"完了状態を切り替え",ctxRenameNote:"名前を変更",ctxMoveNote:"ノートブックに移動...",ctxNoteInfo:"ノートプロパティ",ctxDeleteNote:"ノートを削除",confirmDeleteFolder:"このノートブックとその内容をすべて削除しますか?",confirmDeleteNote:"このノートを削除しますか?",promptRename:"新しい名前を入力:",promptMoveNote:"移動先のノートブック名:",promptNewNotebookName:"新しいノートブック名を入力:",dropCreateNotebook:"ドロップして新規ノートブックを作成",searchSectionNotes:"ノート",searchSectionTags:"タグ",searchSectionFolders:"ノートブック",searchTagNoteCount:"{count} 件のノート",pinned:"ピン留め",tags:"タグ",ctxRenameTag:"タグ名を変更",ctxDeleteTag:"タグを削除",ctxUntagNote:"タグから外す",confirmDeleteTag:"このタグを削除しますか?(タグのみ削除され、ノートは残ります)",ctxPublishNote:"ノートを公開",ctxExport:"エクスポート",refresh:"更新",newItem:"新規",trash:"ゴミ箱",ctxRestoreNote:"復元",ctxPermanentDelete:"完全に削除",ctxEmptyTrash:"ゴミ箱を空にする",confirmEmptyTrash:"ゴミ箱を空にしますか?削除済みのノートブックとノートは完全に削除され、元に戻せません。",smartFolders:"スマートフォルダ",smartRecent:"最近更新",smartTodos:"未完了の ToDo",pvType:"種類",pvSize:"サイズ",pvCreated:"作成",pvUpdated:"更新",pvNote:"ノート",pvTodo:"ToDo",pvChars:"文字",ctxSetTags:"タグを設定",ctxMoveToFolder:"ノートブックへ移動",ctxCopyExternalLink:"外部リンクをコピー",ctxPin:"📌 ピン留め",ctxUnpin:"ピン解除",cancel:"キャンセル"}},i=o(896),n=o(928),s=o(982);function l(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}const r={".gif":"image/gif",".ico":"image/x-icon",".jpeg":"image/jpeg",".jpg":"image/jpeg",".png":"image/png",".svg":"image/svg+xml",".webp":"image/webp"};function d(e,t){const o="icon"+(t?" "+t:"");return"image"===e.type?'<span class="'+o+'"><img class="custom-icon" src="'+l(e.value)+'" /></span>':'<span class="'+o+'">'+l(e.value)+"</span>"}const c={};async function p(e,t,o,a){const l=o+":"+String(e);if(c[l])return c[l];const d=await async function(e,t,o,a){const l="string"==typeof e?e.trim():"";if(!l)return{type:"text",value:t};if(/^data:image\//i.test(l)||/^https?:\/\//i.test(l))return{type:"image",value:l};const d=function(e){const t=e.trim();return/^file:\/\//i.test(t)?decodeURIComponent(t.replace(/^file:\/\//i,"")):0===t.indexOf("~/")&&process&&process.env&&process.env.HOME?n.join(process.env.HOME,t.substring(2)):n.isAbsolute(t)?t:null}(l);if(!d)return{type:"text",value:l};const c=n.extname(d).toLowerCase(),p=r[c];if(!p)return console.warn("Joplin Explorer: unsupported icon file type",d),{type:"text",value:t};const m=n.join(a,"custom-icons"),u=s.createHash("sha1").update(d).digest("hex"),f=n.join(m,o+"-"+u+c);try{await i.promises.mkdir(m,{recursive:!0}),(await i.promises.stat(d)).isFile()&&await i.promises.copyFile(d,f)}catch(e){console.warn("Joplin Explorer: failed to copy icon file",d,e)}try{return{type:"image",value:"data:"+p+";base64,"+(await i.promises.readFile(f)).toString("base64")}}catch(e){return console.warn("Joplin Explorer: failed to load icon file",f,e),{type:"text",value:t}}}(e,t,o,a);return c[l]=d,d}function m(e,t){const o=e.order||0,a=t.order||0;return o!==a?a-o:(e.title||"").localeCompare(t.title||"")}function u(e,t=!0,o={type:"text",value:"📂"},a={type:"text",value:"📁"}){let i=e.icon;if(i&&"string"==typeof i)try{i=JSON.parse(i)}catch(e){i=null}return i&&i.emoji?{type:"text",value:String(i.emoji)}:t?a:o}function f(e){return e.is_todo?e.todo_completed?"☑":"☐":"📝"}function w(e,t,o,a=0,i=!0,n={type:"text",value:"📂"},s={type:"text",value:"📁"}){let r="";for(const c of e){const e=8+18*a;if("folder"===c.type){const p=c.total_count||c.note_count||0,m=!0===o[c.id],f=m?"▶":"▼",g=m?"toggle":"toggle expanded";r+='<div class="tree-item folder'+(m?" collapsed":"")+'" style="padding-left:'+e+'px" data-id="'+c.id+'" data-type="folder">',i&&(r+='<span class="'+g+'">'+f+"</span>"),r+=d(u(c,!1,n,s),"folder-icon icon-when-open"),r+=d(u(c,!0,n,s),"folder-icon icon-when-collapsed"),r+='<span class="label">'+l(c.title)+"</span>",r+='<span class="count">'+p+"</span>",r+="</div>",r+='<div class="children'+(m?" collapsed":"")+'" data-folder-id="'+c.id+'">',c.children&&(r+=w(c.children,t,o,a+1,i,n,s)),r+="</div>"}else{const o=c.id===t?" selected":"",a=f(c);r+='<div class="tree-item note'+o+'" style="padding-left:'+e+'px" data-id="'+c.id+'" data-type="note" data-todo="'+(c.is_todo?1:0)+'">',r+='<span class="icon note-icon">'+a+"</span>",r+='<span class="label">'+l(c.title)+"</span>",r+="</div>"}}return r}function g(e,t){const o=e.slice();switch(t){case"title_asc":o.sort((e,t)=>(e.title||"").localeCompare(t.title||""));break;case"title_desc":o.sort((e,t)=>(t.title||"").localeCompare(e.title||""));break;case"updated_asc":o.sort((e,t)=>(e.user_updated_time||0)-(t.user_updated_time||0));break;case"manual":o.sort((e,t)=>{const o=e.order||0,a=t.order||0;return o!==a?a-o:(t.user_updated_time||0)-(e.user_updated_time||0)});break;default:o.sort((e,t)=>(t.user_updated_time||0)-(e.user_updated_time||0))}return o}joplin.plugins.register({onStart:async function(){const e=(o=await joplin.settings.globalValue("locale")||"en_US",a[o]||a[o.split("_")[0]]||a.en_US),t=await joplin.views.panels.create("notesInListPanel");var o;await joplin.views.panels.addScript(t,"webview/panel.css"),await joplin.views.panels.addScript(t,"webview/panel.js"),await joplin.views.panels.setHtml(t,'<div id="notes-in-list-root"><p style="padding:12px;">'+e.loading+"</p></div>"),await joplin.views.panels.show(t,!0);try{await joplin.settings.registerSection("joplinExplorer",{label:"Joplin Explorer",iconName:"fas fa-columns"}),await joplin.settings.registerSettings({pinnedItems:{section:"joplinExplorer",type:2,value:'{"notes":[],"folders":[]}',public:!1,label:"Pinned Items (JSON)"},folderOrder:{section:"joplinExplorer",type:2,value:"{}",public:!1,label:"Folder Manual Order (JSON)"},noteSortMode:{section:"joplinExplorer",type:2,value:"updated_desc",public:!1,label:"Note Sort Mode"},uiState:{section:"joplinExplorer",type:2,value:"{}",public:!1,label:"UI State (JSON)"},showTagsSection:{section:"joplinExplorer",type:3,value:!0,public:!0,label:"Show tags section",description:"Show Joplin tags as folders below the notebook tree."},autoRefresh:{section:"joplinExplorer",type:3,value:!0,public:!0,label:"Auto refresh on external changes",description:"Poll Joplin's change feed every 5 seconds and refresh the panel when notes are created, moved or deleted by other plugins or sync. Edits to the currently open note are ignored (they already update live)."},restoreUiState:{section:"joplinExplorer",type:3,value:!0,public:!0,label:"Restore last view state on startup",description:"Remember collapsed/expanded folders and sections between sessions. When off, the tree starts fully collapsed."},showSmartFolders:{section:"joplinExplorer",type:3,value:!0,public:!0,label:"Show smart folders",description:"Saved searches rendered as folders: Recently updated, Open to-dos, and your own rules."},smartFolderRules:{section:"joplinExplorer",type:2,value:"",public:!0,label:"Custom smart folders",description:'Name:query pairs separated by ";", using Joplin search syntax. Example: Work:notebook:Work updated:day-30;Starred:tag:star'},smartFolderLimit:{section:"joplinExplorer",type:1,value:5,minimum:1,maximum:50,public:!0,label:"Smart folder result limit",description:"Maximum notes shown per smart folder (newest first). Default: 5."},hoverPreview:{section:"joplinExplorer",type:3,value:!0,public:!0,label:"Note preview on hover",description:"Show title, updated time and a body snippet when hovering a note."},hoverPreviewLength:{section:"joplinExplorer",type:1,value:200,minimum:50,maximum:1e3,public:!0,label:"Hover preview length (characters)"},expandAllMode:{section:"joplinExplorer",type:2,value:"restore",isEnum:!0,options:{restore:"Restore the state before Collapse All",skeleton:"Folders only (leaf notebooks stay collapsed)",all:"Everything"},public:!0,label:"Expand All behavior",description:"What the Expand All button restores. Default: the tree as it was before the last Collapse All."},showFolderToggles:{section:"joplinExplorer",type:3,value:!0,public:!0,label:"Show toggle arrows",description:"Show expand/collapse arrows before folders and the pinned section."},openFolderIcon:{section:"joplinExplorer",type:2,value:"📂",public:!0,label:"Open folder icon",description:"Emoji, image URL, data URI, or local image path for expanded folders without a custom notebook icon."},closedFolderIcon:{section:"joplinExplorer",type:2,value:"📁",public:!0,label:"Closed folder icon",description:"Emoji, image URL, data URI, or local image path for collapsed folders without a custom notebook icon."},openPinnedIcon:{section:"joplinExplorer",type:2,value:"📌",public:!0,label:"Open pinned icon",description:"Emoji, image URL, data URI, or local image path for the expanded pinned section."},closedPinnedIcon:{section:"joplinExplorer",type:2,value:"📌",public:!0,label:"Closed pinned icon",description:"Emoji, image URL, data URI, or local image path for the collapsed pinned section."}})}catch(e){console.error("Joplin Explorer: failed to register settings",e)}const i=await joplin.views.dialogs.create("explorerInputDialog"),n=await joplin.views.dialogs.create("explorerConfirmDialog"),s=await joplin.views.dialogs.create("explorerInfoDialog");async function r(t){return await joplin.views.dialogs.setHtml(n,'<div style="padding:10px;min-width:280px;"><div style="font-size:13px;">'+l(t)+"</div></div>"),await joplin.views.dialogs.setButtons(n,[{id:"ok",title:"OK"},{id:"cancel",title:e.cancel||"Cancel"}]),"ok"===(await joplin.views.dialogs.open(n)).id}async function h(e,t){await joplin.views.dialogs.setHtml(s,'<div style="padding:10px;min-width:320px;"><div style="font-size:14px;font-weight:bold;margin-bottom:10px;">'+l(e)+'</div><div style="font-size:12px;line-height:1.8;white-space:pre-wrap;">'+l(t)+"</div></div>"),await joplin.views.dialogs.setButtons(s,[{id:"ok",title:"OK"}]),await joplin.views.dialogs.open(s)}async function y(t,o){await joplin.views.dialogs.setHtml(i,'<div style="padding:10px;min-width:300px;"><div style="margin-bottom:8px;font-size:13px;">'+l(t)+'</div><form name="inputForm"><input name="value" type="text" value="'+l(o||"")+'" style="width:100%;box-sizing:border-box;padding:6px 8px;font-size:13px;" /></form></div>'),await joplin.views.dialogs.setButtons(i,[{id:"ok",title:"OK"},{id:"cancel",title:e.cancel||"Cancel"}]);const a=await joplin.views.dialogs.open(i);return"ok"===a.id&&a.formData&&a.formData.inputForm&&a.formData.inputForm.value||null}let x="",v={},_="updated_desc";try{const e=String(await joplin.settings.value("noteSortMode")||"");["updated_desc","updated_asc","title_asc","title_desc","manual"].indexOf(e)>=0&&(_=e)}catch(e){}let N=[],b={},j=[],T=[],S=!1,k=!1,F=!0,I=!1,D={},E=!0,C=null,R=[],M={},O=!0,A=!1;if(k=!0,!1!==await joplin.settings.value("restoreUiState"))try{const e=String(await joplin.settings.value("uiState")||"{}"),t=JSON.parse(e);t&&"object"==typeof t&&(t.collapsedFolders&&"object"==typeof t.collapsedFolders&&!Array.isArray(t.collapsedFolders)&&(v=t.collapsedFolders,A=!0),"boolean"==typeof t.tagsCollapsed&&(k=t.tagsCollapsed),"boolean"==typeof t.pinnedCollapsed&&(S=t.pinnedCollapsed),"boolean"==typeof t.trashCollapsed&&(F=t.trashCollapsed),"boolean"==typeof t.smartCollapsed&&(I=t.smartCollapsed),t.seenFolders&&"object"==typeof t.seenFolders&&!Array.isArray(t.seenFolders)&&(D=t.seenFolders,E=!1))}catch(e){}let U=null;function P(){U&&clearTimeout(U),U=setTimeout(async()=>{U=null;try{await joplin.settings.setValue("uiState",JSON.stringify({collapsedFolders:v,tagsCollapsed:k,pinnedCollapsed:S,trashCollapsed:F,smartCollapsed:I,seenFolders:D}))}catch(e){console.error("Joplin Explorer: failed to save UI state",e)}},500)}const J=await joplin.plugins.dataDir();let L=null;function H(e=600){L&&clearTimeout(L),L=setTimeout(async()=>{L=null,await K()},e)}let q=null,z={};async function W(){try{await joplin.settings.setValue("pinnedItems",JSON.stringify(T))}catch(e){console.error("Joplin Explorer: failed to save pinned items",e)}}async function V(){try{await joplin.settings.setValue("folderOrder",JSON.stringify(M))}catch(e){console.error("Joplin Explorer: failed to save folder order",e)}}function B(e){let t=e;for(;t;){delete v[t];const e=b[t];t=e?e.parent_id:null}}async function K(){try{const o=await async function(){let e=[],t=1,o=!0;for(;o;){const a=await joplin.data.get(["folders"],{fields:["id","title","parent_id","icon"],page:t,limit:100});e=e.concat(a.items),o=a.has_more,t++}return e}();await async function(){try{const e=await joplin.settings.value("folderOrder"),t=e?JSON.parse(e):{};M=t&&"object"==typeof t&&!Array.isArray(t)?t:{}}catch(e){M={}}}();let a=!1;const i=new Set(o.map(e=>e.id));for(const e of Object.keys(M))i.has(e)||(delete M[e],a=!0);a&&await V();for(const e of o)e.order=M[e.id]||0;N=o,b={};for(const e of o)b[e.id]=e;let n=!1;for(const e of o)D[e.id]||(D[e.id]=!0,E||(v[e.id]=!0),n=!0);if(E&&(E=!1,n=!0),n&&P(),O){if(!A)for(const e of o)v[e.id]=!0;const e=await joplin.workspace.selectedNote();e&&(x=e.id,B(e.parent_id)),O=!1}const s=await async function(){let e=[],t=1,o=!0;for(;o;){const a=await joplin.data.get(["notes"],{fields:["id","title","parent_id","is_todo","todo_completed","updated_time","user_updated_time","order"],page:t,limit:100});e=e.concat(a.items),o=a.has_more,t++}return e}(),r={};for(const e of o)r[e.id]=[];for(const e of s)r[e.parent_id]&&r[e.parent_id].push(e);for(const e of Object.keys(r))r[e]=g(r[e],_);const c=[];for(const e of Object.keys(r))for(const t of r[e])c.push(t);j=c;const h=await joplin.settings.value("showFolderToggles"),y=await joplin.settings.value("openFolderIcon"),U=await joplin.settings.value("closedFolderIcon"),L=await joplin.settings.value("openPinnedIcon"),H=await joplin.settings.value("closedPinnedIcon"),q=await p(y,"📂","openFolderIcon",J),z=await p(U,"📁","closedFolderIcon",J),K=await p(L,"📌","openPinnedIcon",J),$=await p(H,"📌","closedPinnedIcon",J),G=!1!==h,X=function(e,t){const o={},a={},i={};for(const t of e)o[t.id]={type:"folder",id:t.id,title:t.title,parent_id:t.parent_id,icon:t.icon,order:t.order||0,note_count:0,children:[]},a[t.id]=[],i[t.id]=[];for(const e of Object.keys(t))if(i[e])for(const o of t[e])i[e].push({type:"note",id:o.id,title:o.title||"(untitled)",is_todo:o.is_todo,todo_completed:o.todo_completed});const n=[];for(const t of e){const e=o[t.id];t.parent_id&&o[t.parent_id]?a[t.parent_id].push(e):n.push(e)}function s(e){const t=a[e.id].sort(m);for(const e of t)s(e);e.note_count=i[e.id].length,e.children=t.concat(i[e.id])}n.sort(m);for(const e of n)s(e);const l=n;function r(e){let t=0;if(!e.children)return 0;for(const o of e.children)"note"===o.type?t++:"folder"===o.type&&(r(o),t+=o.total_count||0);return e.total_count=t,t}for(const e of l)r(e);return l}(o,r),ee=w(X,x,v,0,G,q,z);if(!1!==await joplin.settings.value("showTagsSection"))try{let e=[],t=1,o=!0;for(;o;){const a=await joplin.data.get(["tags"],{fields:["id","title"],page:t,limit:100});e=e.concat(a.items),o=a.has_more,t++}e.sort((e,t)=>(e.title||"").localeCompare(t.title||""));let a=e.map(()=>"");e.length<=200&&(a=await Promise.all(e.map(e=>joplin.data.get(["tags",e.id,"notes"],{fields:["id"],limit:100}).then(e=>0===e.items.length?"0":e.has_more?"100+":String(e.items.length)).catch(()=>""))),e=e.filter((e,t)=>"0"!==a[t]),a=a.filter(e=>"0"!==e)),R=e.map((e,t)=>({id:e.id,title:e.title||"",count:a[t]||""}))}catch(e){R=[]}else R=[];await async function(){try{const e=await joplin.settings.value("pinnedItems");if(!e)return;const t=JSON.parse(e);if(t&&!Array.isArray(t)&&t.notes&&t.folders){T=[];for(const e of t.folders)T.push({id:e,type:"folder"});for(const e of t.notes)T.push({id:e,type:"note"});await W()}else Array.isArray(t)&&(T=t)}catch(e){T=[]}}();const te=new Set(o.map(e=>e.id)),oe=new Set(c.map(e=>e.id)),ae=T.length;T=T.filter(e=>"folder"===e.type?te.has(e.id):oe.has(e.id)),T.length!==ae&&await W();let ie="";const ne=T.length;if(ne>0){ie+='<div class="pinned-section-header'+(S?" collapsed":"")+'" id="pinned-header">',G&&(ie+='<span class="toggle">'+(S?"▶":"▼")+"</span>"),ie+=d(K,"icon-when-open")+d($,"icon-when-collapsed")+'<span class="label">'+e.pinned+'</span><span class="count">'+ne+"</span></div>",ie+='<div class="pinned-section-body'+(S?" collapsed":"")+'" id="pinned-body">';for(const e of T)if("folder"===e.type){const t=b[e.id]||null;if(t){const e=u(t,!0,q,z);ie+='<div class="tree-item folder pinned-item" data-id="'+t.id+'" data-type="folder">',ie+=d(e,"folder-icon"),ie+='<span class="label">'+l(t.title)+"</span>",ie+="</div>"}}else{let t=null;for(const o of c)if(o.id===e.id){t=o;break}if(t){const e=t.id===x?" selected":"",o=f(t);ie+='<div class="tree-item note pinned-item'+e+'" data-id="'+t.id+'" data-type="note" data-todo="'+(t.is_todo?1:0)+'">',ie+='<span class="icon note-icon">'+o+"</span>",ie+='<span class="label">'+l(t.title)+"</span>",ie+="</div>"}}ie+="</div>"}let se="";if(R.length>0){se+='<div class="tags-section-header'+(k?" collapsed":"")+'" id="tags-header">',G&&(se+='<span class="toggle">'+(k?"▶":"▼")+"</span>"),se+='<span class="icon">🏷️</span><span class="label">'+e.tags+'</span><span class="count">'+R.length+"</span></div>",se+='<div class="tags-section-body'+(k?" collapsed":"")+'" id="tags-body">';for(const e of R)se+='<div class="tree-item folder tag-folder collapsed" data-tag-id="'+e.id+'" data-type="tag">',G&&(se+='<span class="toggle">▶</span>'),se+='<span class="icon">🏷️</span>',se+='<span class="label">'+l(e.title)+"</span>",e.count&&(se+='<span class="count">'+e.count+"</span>"),se+="</div>",se+='<div class="tag-children collapsed" data-tag-id="'+e.id+'"></div>';se+="</div>"}let le="";try{const t={};let o=0,a=!1,i=1,n=!0;for(;n;){const e=await joplin.data.get(["folders"],{fields:["id","deleted_time"],include_deleted:"1",page:i,limit:100});for(const a of e.items||[])a.deleted_time>0&&(t[a.id]=!0,o++);n=e.has_more,i++}const s=(await joplin.data.get(["notes"],{fields:["id","parent_id","deleted_time"],include_deleted:"1",order_by:"deleted_time",order_dir:"DESC",limit:100})).items||[];for(const e of s){if(!e.deleted_time)break;t[e.parent_id]||o++}100===s.length&&s[99].deleted_time>0&&(a=!0),(o>0||a)&&(le+='<div class="trash-section-header'+(F?" collapsed":"")+'" id="trash-header">',G&&(le+='<span class="toggle">'+(F?"▶":"▼")+"</span>"),le+='<span class="icon">🗑️</span><span class="label">'+e.trash+'</span><span class="count">'+o+(a?"+":"")+"</span></div>",le+='<div class="trash-children'+(F?" collapsed":"")+'" id="trash-children"></div>')}catch(e){}let re="";if(!1!==await joplin.settings.value("showSmartFolders")){const t=[{id:"recent",title:e.smartRecent,query:"updated:day-7"},{id:"todos",title:e.smartTodos,query:"type:todo iscompleted:0"}],o=String(await joplin.settings.value("smartFolderRules")||"").trim();if(o){const e=o.split(";");for(let o=0;o<e.length;o++){const a=e[o].trim();if(!a)continue;const i=a.indexOf(":");i<=0||t.push({id:"rule"+o,title:a.slice(0,i).trim(),query:a.slice(i+1).trim()})}}re+='<div class="smart-section-header'+(I?" collapsed":"")+'" id="smart-header">',G&&(re+='<span class="toggle">'+(I?"▶":"▼")+"</span>"),re+='<span class="icon">🔍</span><span class="label">'+e.smartFolders+"</span></div>",re+='<div class="smart-section-body'+(I?" collapsed":"")+'" id="smart-body">';for(const e of t){if(!e.title||!e.query)continue;let t=0,o=!1;try{if("recent"===e.id)t=(await Y(1)).length;else if("todos"===e.id){const e=await Z(101);t=Math.min(e.length,100),o=e.length>100}else{let a=1,i=!0;for(;i&&t<=100;){const o=await joplin.data.get(["search"],{query:e.query,fields:["id"],page:a,limit:100});t+=(o.items||[]).length,i=o.has_more,a++}t>100&&(t=100,o=!0)}}catch(e){}const a=t>0;re+='<div class="tree-item folder smart-folder collapsed'+(a?"":" smart-empty")+'" style="padding-left:26px" data-smart-id="'+e.id+'" data-query="'+l(e.query)+'" data-type="smart"><span class="toggle">▶</span><span class="icon">🔍</span><span class="label">'+l(e.title)+"</span>"+(a&&"recent"!==e.id?'<span class="count">'+t+(o?"+":"")+"</span>":"")+"</div>",a&&(re+='<div class="smart-children collapsed" data-smart-id="'+e.id+'"></div>')}re+="</div>"}const de=l(JSON.stringify(T)),ce=o.length>0&&o.every(e=>!0===v[e.id]),pe={updated_desc:e.sortUpdatedDesc,updated_asc:e.sortUpdatedAsc,title_asc:e.sortTitleAsc,title_desc:e.sortTitleDesc,manual:e.sortManual},me=l(JSON.stringify(e)),ue=String(await joplin.settings.value("expandAllMode")||"restore"),fe=!1!==await joplin.settings.value("hoverPreview")?"1":"0",we='<div id="notes-in-list-root" data-i18n="'+me+'" data-pinned="'+de+'" data-sort="'+l(_)+'" data-expand-mode="'+l(ue)+'" data-hover-preview="'+fe+'" data-collapse-snapshot="'+l(JSON.stringify(C))+'"> <div class="toolbar"> <button id="btn-new" title="'+e.newItem+'">+</button> <button id="btn-sort" title="'+e.sort+'">'+pe[_]+'</button> <button id="btn-collapse-all" data-mode="'+(ce?"expand":"collapse")+'" title="'+(ce?e.expandAll:e.collapseAll)+'">'+(ce?"▼":"▲")+'</button> <button id="btn-refresh" title="'+e.refresh+'">↻</button> </div> <div class="search-bar"> <input id="search-input" type="text" placeholder="🔍 '+e.search+'" /> </div> <div id="tree-container">'+ie+re+'<div id="main-tree">'+ee+"</div>"+se+le+' <div id="drop-zone-empty" class="drop-zone-empty">+ '+e.dropCreateNotebook+'</div> </div> <div id="search-results" style="display:none;"></div> <div class="bottom-bar"> <button id="btn-sync" title="'+e.sync+'">🔄 '+e.sync+"</button> </div></div>";if(await joplin.views.panels.setHtml(t,we),le&&!F)try{const e=await Q();await joplin.views.panels.postMessage(t,{name:"trashNotes",folders:e.folders,notes:e.notes})}catch(e){}}catch(e){console.error("Notes In List: refresh error",e),await joplin.views.panels.setHtml(t,'<div style="padding:12px;color:red;">Error: '+l(String(e))+"</div>")}}async function $(e){try{const o=j.findIndex(t=>t.id===e),a=await joplin.data.get(["notes",e],{fields:["id","title","parent_id","is_todo","todo_completed","updated_time","user_updated_time","order"]});if(o<0||j[o].parent_id!==a.parent_id)return void await K();const i=j[o],n=0===_.indexOf("title_")&&(i.title||"")!==(a.title||""),s=0===_.indexOf("updated_")&&i.user_updated_time!==a.user_updated_time;if(j[o]=a,n||s)return void await K();await joplin.views.panels.postMessage(t,{name:"updateNote",id:a.id,title:a.title||"(untitled)",icon:f(a)})}catch(e){await K()}}async function G(e){let t=[],o=1,a=!0;for(;a&&t.length<200;){const i=await joplin.data.get(["tags",e,"notes"],{fields:["id","title","is_todo","todo_completed"],page:o,limit:50});t=t.concat(i.items),a=i.has_more,o++}return t.map(e=>({id:e.id,title:e.title||"(untitled)",is_todo:e.is_todo,todo_completed:e.todo_completed}))}async function Q(){const e=[],t={},o={};try{let a=1,i=!0;for(;i;){const n=await joplin.data.get(["folders"],{fields:["id","title","parent_id","deleted_time"],include_deleted:"1",page:a,limit:100});for(const a of n.items||[])o[a.id]=a.parent_id||"",a.deleted_time>0&&(e.push({id:a.id,title:a.title||"(untitled)",parent_id:a.parent_id}),t[a.id]=!0);i=n.has_more,a++}}catch(e){}const a=[],i={},n=[];for(const o of e)o.parent_id&&t[o.parent_id]?(i[o.parent_id]=i[o.parent_id]||[]).push(o):n.push(o);const s=(e,t)=>{a.push({id:e.id,title:e.title,depth:t});for(const o of i[e.id]||[])s(o,t+1)};for(const e of n)s(e,0);await Promise.all(a.map(async e=>{try{const t=await joplin.data.get(["folders",e.id,"notes"],{fields:["id"],include_deleted:"1",limit:1});e.hasNotes=!(!t.items||!t.items.length)}catch(t){e.hasNotes=!0}}));const l=[];let r=1,d=!0;for(;d&&l.length<200;){const e=await joplin.data.get(["notes"],{fields:["id","title","parent_id","is_todo","todo_completed","deleted_time"],include_deleted:"1",order_by:"deleted_time",order_dir:"DESC",page:r,limit:50});let a=!1;for(const i of e.items||[]){if(!i.deleted_time){a=!0;break}let e=!1,n=i.parent_id,s=0;for(;n&&s++<50;){if(t[n]){e=!0;break}n=o[n]||""}e||l.push({id:i.id,title:i.title||"(untitled)",is_todo:i.is_todo,todo_completed:i.todo_completed})}if(a)break;d=e.has_more,r++}return{folders:a,notes:l}}async function X(e){const t={};try{let e=1,o=!0;for(;o;){const a=await joplin.data.get(["folders"],{fields:["id","parent_id"],include_deleted:"1",page:e,limit:100});for(const e of a.items||[])e.parent_id&&(t[e.parent_id]=t[e.parent_id]||[]).push(e.id);o=a.has_more,e++}}catch(e){}const o=async e=>{for(const a of t[e]||[])await o(a);try{let t=1,o=!0;for(;o;){const a=await joplin.data.get(["folders",e,"notes"],{fields:["id"],include_deleted:"1",page:t,limit:100});for(const e of a.items||[])try{await joplin.data.delete(["notes",e.id],{permanent:"1"})}catch(e){}o=(a.items||[]).length>0&&a.has_more}}catch(e){}try{await joplin.data.delete(["folders",e],{permanent:"1"})}catch(e){}};await o(e)}async function Y(e){return((await joplin.data.get(["notes"],{fields:["id","title","is_todo","todo_completed","user_updated_time"],order_by:"user_updated_time",order_dir:"DESC",limit:Math.min(e,100)})).items||[]).map(e=>({id:e.id,title:e.title||"(untitled)",is_todo:e.is_todo,todo_completed:e.todo_completed}))}async function Z(e){const t=[];let o=1,a=!0;for(;a&&t.length<e&&o<=10;){const e=await joplin.data.get(["notes"],{fields:["id","title","is_todo","todo_completed","user_updated_time"],order_by:"is_todo",order_dir:"DESC",page:o,limit:100});let i=!1;for(const o of e.items||[]){if(!o.is_todo){i=!0;break}o.todo_completed||t.push({id:o.id,title:o.title||"(untitled)",is_todo:o.is_todo,todo_completed:o.todo_completed,user_updated_time:o.user_updated_time||0})}if(i)break;a=e.has_more,o++}return t.sort((e,t)=>(t.user_updated_time||0)-(e.user_updated_time||0)),t.slice(0,e)}await joplin.settings.onChange(async e=>{e.keys&&e.keys.indexOf("autoRefresh")>=0&&await ae(),e.keys&&(e.keys.indexOf("showSmartFolders")>=0||e.keys.indexOf("smartFolderRules")>=0||e.keys.indexOf("hoverPreview")>=0||e.keys.indexOf("expandAllMode")>=0||e.keys.indexOf("showTagsSection")>=0||e.keys.indexOf("showFolderToggles")>=0||e.keys.indexOf("openFolderIcon")>=0||e.keys.indexOf("closedFolderIcon")>=0||e.keys.indexOf("openPinnedIcon")>=0||e.keys.indexOf("closedPinnedIcon")>=0)&&(function(){for(const e of Object.keys(c))delete c[e]}(),await K())}),await joplin.views.panels.onMessage(t,async o=>{if("openNote"===o.name)x=o.id,await joplin.commands.execute("openNote",o.id);else if("refresh"===o.name)await K();else if("toggleFolder"===o.name)v[o.id]?delete v[o.id]:v[o.id]=!0,P();else if("collapseAll"===o.name){for(const e of N)v[e.id]=!0;Array.isArray(o.prevCollapsed)&&(C=o.prevCollapsed.map(String)),P()}else if("expandAll"===o.name){if(v={},Array.isArray(o.collapsedIds))for(const e of o.collapsedIds)v[String(e)]=!0;P()}else if("panelReady"===o.name)await K();else if("notePreview"===o.name)try{if(!1===await joplin.settings.value("hoverPreview"))return;const e=Number(await joplin.settings.value("hoverPreviewLength"))||200,a=await joplin.data.get(["notes",o.id],{fields:["id","title","body","is_todo","user_created_time","user_updated_time"],include_deleted:"1"});if(!a)return;const i=String(a.body||"").replace(/```[\s\S]*?```/g," ").replace(/!\[[^\]]*\]\([^)]*\)/g," ").replace(/\[([^\]]*)\]\([^)]*\)/g,"$1").replace(/^#{1,6}\s+/gm,"").replace(/[`*_>~]/g,"").replace(/\s+/g," ").trim().slice(0,e);await joplin.views.panels.postMessage(t,{name:"notePreview",id:o.id,title:a.title||"(untitled)",created:a.user_created_time||0,updated:a.user_updated_time||0,isTodo:!!a.is_todo,size:String(a.body||"").length,snippet:i})}catch(e){}else if("refreshView"===o.name)await K();else if("newNotebook"===o.name){const o=await y(e.promptNewNotebookName,"");if(!o||!o.trim())return;const a=await joplin.data.post(["folders"],null,{title:o.trim()});D[a.id]=!0,delete v[a.id],await K(),await joplin.views.panels.postMessage(t,{name:"scrollToFolder",folderId:a.id})}else if("newNote"===o.name){await joplin.commands.execute("newNote");const e=await joplin.workspace.selectedNote();e&&(x=e.id,B(e.parent_id)),await K()}else if("newTodo"===o.name){await joplin.commands.execute("newTodo");const e=await joplin.workspace.selectedNote();e&&(x=e.id,B(e.parent_id)),await K()}else if("search"===o.name)await async function(e){const o=e.query;if(o&&o.trim())try{const a=o.toLowerCase(),i={};for(const e of N)i[e.id]=e.title;let n=[],s=1,l=!0;for(;l&&n.length<100;){const e=await joplin.data.get(["search"],{query:o,fields:["id","title","body","parent_id","is_todo","todo_completed"],page:s,limit:20});n=n.concat(e.items),l=e.has_more,s++}const r=new Set(n.map(e=>e.id)),d=[];for(const e of j)!r.has(e.id)&&(e.title||"").toLowerCase().indexOf(a)>=0&&d.push(e);for(let e=0;e<d.length&&e<50;e++)try{const t=await joplin.data.get(["notes",d[e].id],{fields:["id","title","body","parent_id","is_todo","todo_completed"]});n.push(t)}catch(e){}const c=[];for(const e of n){let t="";const o=e.body||"",n=o.toLowerCase().indexOf(a);if(n>=0){const e=Math.max(0,n-40),i=Math.min(o.length,n+a.length+80);t=(e>0?"...":"")+o.substring(e,i).replace(/\n/g," ")+(i<o.length?"...":"")}else t=o.substring(0,120).replace(/\n/g," ")+(o.length>120?"...":"");c.push({id:e.id,title:e.title||"(untitled)",is_todo:e.is_todo,todo_completed:e.todo_completed,snippet:t,folderName:i[e.parent_id]||""})}let p=[],m=1,u=!0;for(;u;){const e=await joplin.data.get(["tags"],{fields:["id","title"],page:m,limit:100});p=p.concat(e.items),u=e.has_more,m++}const f=[];for(const e of p)if((e.title||"").toLowerCase().indexOf(a)>=0){let t=0;try{const o=await joplin.data.get(["tags",e.id,"notes"],{fields:["id"],limit:100});t=o.has_more?o.items.length+"+":o.items.length}catch(e){}f.push({id:e.id,title:e.title,noteCount:t})}const w=[];for(const e of N)if((e.title||"").toLowerCase().indexOf(a)>=0){let t="";if(e.icon&&"string"==typeof e.icon)try{const o=JSON.parse(e.icon);o&&o.emoji&&(t=String(o.emoji))}catch(e){}w.push({id:e.id,title:e.title,parent_id:e.parent_id,iconEmoji:t})}await joplin.views.panels.postMessage(t,{name:"searchResults",notes:c,tags:f,folders:w,query:o,searchId:e.searchId})}catch(e){console.error("Joplin Explorer: search error",e)}else await joplin.views.panels.postMessage(t,{name:"searchResults",results:null,query:"",searchId:e.searchId})}(o);else if("loadTagNotes"===o.name)try{const e=o.tagId;let a=[],i=1,n=!0;for(;n&&a.length<100;){const t=await joplin.data.get(["tags",e,"notes"],{fields:["id","title","parent_id","is_todo","todo_completed"],page:i,limit:50});a=a.concat(t.items),n=t.has_more,i++}const s={};for(const e of N)s[e.id]=e.title;const l=a.map(e=>({id:e.id,title:e.title||"(untitled)",is_todo:e.is_todo,todo_completed:e.todo_completed,snippet:"",folderName:s[e.parent_id]||""}));await joplin.views.panels.postMessage(t,{name:"tagNotes",tagId:e,notes:l})}catch(e){console.error("Joplin Explorer: loadTagNotes error",e)}else if("toggleTagsSection"===o.name)k=!k,P();else if("tagFolderNotes"===o.name)try{const e=await G(o.tagId);await joplin.views.panels.postMessage(t,{name:"tagFolderNotes",tagId:o.tagId,notes:e})}catch(e){console.error("Joplin Explorer: tagFolderNotes error",e)}else if("tagNoteAdd"===o.name)try{await joplin.data.post(["tags",o.tagId,"notes"],null,{id:o.noteId});const e=await G(o.tagId);await joplin.views.panels.postMessage(t,{name:"tagFolderNotes",tagId:o.tagId,notes:e})}catch(e){console.error("Joplin Explorer: tagNoteAdd error",e)}else if("toggleSmartSection"===o.name)I=!I,P();else if("smartFolderNotes"===o.name)try{const e=Math.max(1,Number(await joplin.settings.value("smartFolderLimit"))||5);if("recent"===o.smartId||"todos"===o.smartId){const a="recent"===o.smartId?await Y(e):await Z(e);return void await joplin.views.panels.postMessage(t,{name:"smartFolderNotes",smartId:o.smartId,notes:a})}let a=[],i=1,n=!0;for(;n&&a.length<100;){const e=await joplin.data.get(["search"],{query:String(o.query||""),fields:["id","title","is_todo","todo_completed","user_updated_time"],page:i,limit:50});a=a.concat((e.items||[]).map(e=>({id:e.id,title:e.title||"(untitled)",is_todo:e.is_todo,todo_completed:e.todo_completed,user_updated_time:e.user_updated_time||0}))),n=e.has_more,i++}a.sort((e,t)=>(t.user_updated_time||0)-(e.user_updated_time||0)),await joplin.views.panels.postMessage(t,{name:"smartFolderNotes",smartId:o.smartId,notes:a.slice(0,e)})}catch(e){console.error("Joplin Explorer: smartFolderNotes error",e)}else if("toggleTrashSection"===o.name)F=!F,P();else if("trashFolderNotes"===o.name)try{let e=[],a=1,i=!0;for(;i&&e.length<200;){const t=await joplin.data.get(["folders",o.folderId,"notes"],{fields:["id","title","is_todo","todo_completed"],include_deleted:"1",page:a,limit:50});e=e.concat((t.items||[]).map(e=>({id:e.id,title:e.title||"(untitled)",is_todo:e.is_todo,todo_completed:e.todo_completed}))),i=t.has_more,a++}await joplin.views.panels.postMessage(t,{name:"trashFolderNotes",folderId:o.folderId,notes:e})}catch(e){console.error("Joplin Explorer: trashFolderNotes error",e)}else if("trashNotes"===o.name)try{const e=await Q();await joplin.views.panels.postMessage(t,{name:"trashNotes",folders:e.folders,notes:e.notes})}catch(e){console.error("Joplin Explorer: trashNotes error",e)}else if("locateFolder"===o.name)try{B(o.folderId),await K(),await joplin.views.panels.postMessage(t,{name:"exitSearchAndLocate",folderId:o.folderId})}catch(e){console.error("Joplin Explorer: locateFolder error",e)}else if("locatePinnedFolder"===o.name)try{B(o.folderId),await K(),await joplin.views.panels.postMessage(t,{name:"scrollToFolder",folderId:o.folderId})}catch(e){console.error("Joplin Explorer: locatePinnedFolder error",e)}else if("reorderPinned"===o.name)try{const e=o.dragId,t=o.targetId,a=o.position,i=T.findIndex(t=>t.id===e);if(i<0)return;const n=T[i];T.splice(i,1);let s=T.findIndex(e=>e.id===t);s<0?T.push(n):("after"===a&&s++,T.splice(s,0,n)),await W(),await K()}catch(e){console.error("Joplin Explorer: reorderPinned error",e)}else if("togglePinnedCollapse"===o.name)S=!S,P();else if("cycleSort"===o.name){const e=["updated_desc","updated_asc","title_asc","title_desc","manual"],t=e.indexOf(_);_=e[(t+1)%e.length];try{await joplin.settings.setValue("noteSortMode",_)}catch(e){}await K()}else if("sync"===o.name)try{await joplin.commands.execute("synchronize")}catch(o){console.error("Joplin Explorer: sync command failed",o),await joplin.views.panels.postMessage(t,{name:"syncState",state:"error"});const a=o&&o.message?String(o.message):String(o);await h(e.syncFailed,a)}else if("contextMenu"===o.name)await async function(o){const a=o.action,i=o.id,n=o.itemType;try{if("folder"===n)switch(a){case"newNote":{const t=await joplin.data.post(["notes"],null,{title:e.newNote,parent_id:i});await joplin.commands.execute("openNote",t.id),x=t.id,B(i);break}case"newTodo":{const t=await joplin.data.post(["notes"],null,{title:e.newTodo,parent_id:i,is_todo:1});await joplin.commands.execute("openNote",t.id),x=t.id,B(i);break}case"newSubNotebook":{const t=await y(e.newNotebook,"");if(t&&t.trim()){const e=await joplin.data.post(["folders"],null,{title:t.trim(),parent_id:i});D[e.id]=!0,delete v[i],delete v[e.id]}break}case"deleteFolder":{const t=await joplin.data.get(["folders",i],{fields:["title"]});await r(e.confirmDeleteFolder+"\n\n"+t.title)&&await joplin.data.delete(["folders",i]);break}case"renameFolder":{const t=await joplin.data.get(["folders",i],{fields:["title"]}),o=await y(e.promptRename,t.title);o&&o.trim()&&await joplin.data.put(["folders",i],null,{title:o.trim()});break}case"exportFolder":try{await joplin.commands.execute("exportFolders",[i])}catch(e){}break;case"pinFolder":T.some(e=>e.id===i)||(T.push({id:i,type:"folder"}),await W());break;case"unpinFolder":T=T.filter(e=>e.id!==i),await W()}else if("note"===n)switch(a){case"openNote":await joplin.commands.execute("openNote",i),x=i;break;case"openInNewWindow":try{await joplin.commands.execute("openNoteInNewWindow",i)}catch(e){await joplin.commands.execute("openNote",i)}break;case"copyLink":{const e=await joplin.data.get(["notes",i],{fields:["id","title"]}),o="["+e.title+"](:/"+e.id+")";try{await joplin.clipboard.writeText(o)}catch(e){await joplin.views.panels.postMessage(t,{name:"copyText",text:o})}break}case"duplicateNote":{const e=await joplin.data.get(["notes",i],{fields:["title","body","parent_id","is_todo"]}),t=await joplin.data.post(["notes"],null,{title:e.title+" (copy)",body:e.body,parent_id:e.parent_id,is_todo:e.is_todo});await joplin.commands.execute("openNote",t.id),x=t.id;break}case"switchNoteType":{const e=await joplin.data.get(["notes",i],{fields:["is_todo"]});await joplin.data.put(["notes",i],null,{is_todo:e.is_todo?0:1});break}case"toggleTodo":{const e=await joplin.data.get(["notes",i],{fields:["is_todo","todo_completed"]});e.is_todo&&await joplin.data.put(["notes",i],null,{todo_completed:e.todo_completed?0:Date.now()});break}case"publishNote":try{await joplin.commands.execute("showShareNoteDialog",[i])}catch(e){}break;case"exportPdf":try{await joplin.commands.execute("exportPdf",[i])}catch(e){}break;case"exportNote":try{const e=await joplin.views.dialogs.showOpenDialog({properties:["openDirectory"]}),t=Array.isArray(e)?e[0]:e;t&&await joplin.commands.execute("exportNotes",[i],o.format||"md",t)}catch(e){console.error("Joplin Explorer: exportNote error",e)}break;case"setTags":try{await joplin.commands.execute("setTags",[i])}catch(e){}break;case"moveToFolderDialog":try{await joplin.commands.execute("moveToFolder",[i])}catch(e){}break;case"copyExternalLink":{const e="joplin://x-callback-url/openNote?id="+i;try{await joplin.clipboard.writeText(e)}catch(o){await joplin.views.panels.postMessage(t,{name:"copyText",text:e})}break}case"renameNote":{const t=await joplin.data.get(["notes",i],{fields:["title"]}),o=await y(e.promptRename,t.title);o&&o.trim()&&await joplin.data.put(["notes",i],null,{title:o.trim()});break}case"moveNote":if(o.targetFolderName){let e=null;for(const t of N)if(t.title===o.targetFolderName){e=t;break}e&&await joplin.data.put(["notes",i],null,{parent_id:e.id})}break;case"noteInfo":{const t=await joplin.data.get(["notes",i],{fields:["id","title","created_time","updated_time","is_todo","parent_id","body"]}),o=b[t.parent_id]?b[t.parent_id].title:"",a=(t.body||"").length,n="ID: "+t.id+"\n"+(e.ctxRenameNote||"Title")+": "+t.title+"\n"+(e.newNotebook||"Notebook")+": "+o+"\n"+(e.sortUpdatedDesc?e.sortUpdatedDesc.replace(/[↓↑\u2193\u2191]\s*/,""):"Created")+": "+new Date(t.created_time).toLocaleString()+"\n"+(e.sortUpdatedAsc?e.sortUpdatedAsc.replace(/[↓↑\u2193\u2191]\s*/,""):"Updated")+": "+new Date(t.updated_time).toLocaleString()+"\nType: "+(t.is_todo?"To-do":"Note")+"\nSize: "+a+" chars";await h(t.title,n);break}case"deleteNote":{const t=await joplin.data.get(["notes",i],{fields:["title"]});await r(e.confirmDeleteNote+"\n\n"+t.title)&&await joplin.data.delete(["notes",i]);break}case"untagNote":if(o.tagId){await joplin.data.delete(["tags",o.tagId,"notes",i]);try{const e=await G(o.tagId);await joplin.views.panels.postMessage(t,{name:"tagFolderNotes",tagId:o.tagId,notes:e})}catch(e){}}break;case"pinNote":T.some(e=>e.id===i)||(T.push({id:i,type:"note"}),await W());break;case"unpinNote":T=T.filter(e=>e.id!==i),await W()}else if("tag"===n)switch(a){case"renameTag":{const t=await joplin.data.get(["tags",i],{fields:["title"]}),o=await y(e.ctxRenameTag,t.title);o&&o.trim()&&await joplin.data.put(["tags",i],null,{title:o.trim()});break}case"deleteTag":{const t=await joplin.data.get(["tags",i],{fields:["title"]});await r(e.confirmDeleteTag+"\n\n"+t.title)&&await joplin.data.delete(["tags",i]);break}}else if("trashSection"===n){if("emptyTrash"===a&&await r(e.confirmEmptyTrash)){try{await joplin.commands.execute("emptyTrash")}catch(e){const t=await Q();for(const e of t.folders)0===e.depth&&await X(e.id);for(const e of t.notes)try{await joplin.data.delete(["notes",e.id],{permanent:"1"})}catch(e){}}try{const e=await Q();await joplin.views.panels.postMessage(t,{name:"trashNotes",folders:e.folders,notes:e.notes})}catch(e){}}}else if("trashNote"===n||"trashFolder"===n){const o="trashFolder"===n;switch(a){case"restoreItem":try{await joplin.commands.execute(o?"restoreFolder":"restoreNote",[i])}catch(e){console.error("Joplin Explorer: restore error",e)}break;case"permanentDeleteItem":{const t=o?"folders":"notes";let a="";try{const e=await joplin.data.get([t,i],{fields:["title"],include_deleted:"1"});a=e?e.title:""}catch(e){}if(await r(e.confirmDeleteNote+"\n\n"+a))if(o)await X(i);else try{await joplin.data.delete(["notes",i],{permanent:"1"})}catch(e){try{await joplin.commands.execute("permanentlyDeleteNote",[i])}catch(e){}}break}}try{const e=await Q();await joplin.views.panels.postMessage(t,{name:"trashNotes",folders:e.folders,notes:e.notes})}catch(e){}}await K()}catch(e){console.error("Notes In List: context menu error",e)}}(o);else if("dragDrop"===o.name)await async function(e){try{const t=e.dragId,o=e.dragType,a=e.targetId,i=e.position;if("note"===o)if(b[a])await joplin.data.put(["notes",t],null,{parent_id:a});else{const e=await joplin.data.get(["notes",a],{fields:["parent_id"]});"manual"!==_||"above"!==i&&"below"!==i?await joplin.data.put(["notes",t],null,{parent_id:e.parent_id}):await async function(e,t,o){const a=(await joplin.data.get(["notes",t],{fields:["parent_id"]})).parent_id,i=j.filter(t=>t.parent_id===a&&t.id!==e).sort((e,t)=>{const o=e.order||0,a=t.order||0;return o!==a?a-o:(t.user_updated_time||0)-(e.user_updated_time||0)}),n=i.findIndex(e=>e.id===t),s=n<0?i.length:"above"===o?n:n+1,l=s>0?i[s-1]:null,r=s<i.length?i[s]:null,d=l?l.order||0:null,c=r?r.order||0:null,p=1e6;if(i.every(e=>0===(e.order||0))||null!==d&&null!==c&&d-c<2){const t=Date.now(),o=i.slice();o.splice(s,0,null);let n=t;const l=[];for(let e=0;e<o.length;e++){const a=t-e*p,i=o[e];null===i?n=a:l.push(joplin.data.put(["notes",i.id],null,{order:a}))}return await Promise.all(l),void await joplin.data.put(["notes",e],null,{parent_id:a,order:n})}let m;m=null!==d&&null!==c?(d+c)/2:null!==d?d-p:null!==c?c+p:Date.now(),await joplin.data.put(["notes",e],null,{parent_id:a,order:m})}(t,a,i)}else if("folder"===o){const e=!!b[a];"into"===i?e&&t!==a&&await joplin.data.put(["folders",t],null,{parent_id:a}):!e||"above"!==i&&"below"!==i||await async function(e,t,o){const a=b[t],i=b[e];if(!a||!i||e===t)return;const n=a.parent_id||"";let s=n;for(;s;){if(s===e)return;s=b[s]&&b[s].parent_id||""}const l=N.filter(t=>(t.parent_id||"")===n&&t.id!==e).sort((e,t)=>{const o=e.order||0,a=t.order||0;return o!==a?a-o:(e.title||"").localeCompare(t.title||"")}),r=l.findIndex(e=>e.id===t),d=r<0?l.length:"above"===o?r:r+1,c=d>0?l[d-1]:null,p=d<l.length?l[d]:null,m=c?c.order||0:null,u=p?p.order||0:null,f=l.every(e=>0===(e.order||0)),w=null!==m&&null!==u&&m-u<2,g=1e6;if((i.parent_id||"")!==n&&await joplin.data.put(["folders",e],null,{parent_id:n}),f||w){const t=Date.now(),o=l.slice();o.splice(d,0,null);for(let a=0;a<o.length;a++){const i=t-a*g,n=o[a];null===n?M[e]=i:M[n.id]=i}return void await V()}let h;h=null!==m&&null!==u?(m+u)/2:null!==m?m-g:null!==u?u+g:Date.now(),M[e]=h,await V()}(t,a,i)}await K()}catch(e){console.error("Notes In List: drag drop error",e)}}(o);else if("dragToEmpty"===o.name)try{const t=o.dragId,a=o.dragType,i=await y(e.promptNewNotebookName,"");if(!i||!i.trim())return;const n=await joplin.data.post(["folders"],null,{title:i.trim()});D[n.id]=!0,delete v[n.id],"note"===a?await joplin.data.put(["notes",t],null,{parent_id:n.id}):"folder"===a&&t!==n.id&&await joplin.data.put(["folders",t],null,{parent_id:n.id}),await K()}catch(e){console.error("Notes In List: drag to empty error",e)}});let ee="",te=null;async function oe(){try{if(!ee){const e=await joplin.data.get(["events"]);return void(ee=String(e.cursor||""))}let e=!1,t=0;for(;t++<20;){const t=await joplin.data.get(["events"],{cursor:ee});for(const o of t.items||[])2===Number(o.type)&&o.item_id===x||(e=!0);if(t.cursor&&(ee=String(t.cursor)),!t.has_more)break}e&&H(300)}catch(e){te&&(clearInterval(te),te=null),console.warn("Joplin Explorer: change-events polling disabled",e)}}async function ae(){const e=!1!==await joplin.settings.value("autoRefresh");te&&(clearInterval(te),te=null),e&&(ee="",await oe(),te=setInterval(oe,5e3))}await ae(),await joplin.workspace.onNoteSelectionChange(async()=>{const e=await joplin.workspace.selectedNote();e&&e.id!==x&&(x=e.id,await joplin.views.panels.postMessage(t,{name:"selectNote",id:e.id}))}),await joplin.workspace.onNoteChange(async e=>{var t;e&&e.id?(t=e.id,z[t]=!0,q&&clearTimeout(q),q=setTimeout(async()=>{q=null;const e=Object.keys(z);z={};for(const t of e)await $(t)},600)):H()});try{await joplin.workspace.onSyncStart(async()=>{await joplin.views.panels.postMessage(t,{name:"syncState",state:"syncing"})})}catch(e){console.warn("Joplin Explorer: onSyncStart not available",e)}try{await joplin.workspace.onSyncComplete(async o=>{const a=!(!o||!o.withErrors);await K(),await joplin.views.panels.postMessage(t,{name:"syncState",state:a?"error":"done"}),a&&await h(e.syncFailed,"Joplin reported errors during synchronisation. Open the Synchronisation Status screen (Tools → Synchronisation Status) to see the details.")})}catch(e){console.warn("Joplin Explorer: onSyncComplete not available",e)}await K()}})})();
|
package/publish/manifest.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"manifest_version": 1,
|
|
3
3
|
"id": "com.github.joplin-explorer",
|
|
4
4
|
"app_min_version": "2.6.0",
|
|
5
|
-
"version": "1.5.
|
|
5
|
+
"version": "1.5.2",
|
|
6
6
|
"name": "Joplin Explorer",
|
|
7
7
|
"description": "A unified sidebar that displays notebooks and notes together in a single tree view",
|
|
8
8
|
"author": "lim0513",
|
package/publish/plugin.jpl
CHANGED
|
Binary file
|
|
@@ -296,28 +296,119 @@ html, body {
|
|
|
296
296
|
margin: 4px 0;
|
|
297
297
|
}
|
|
298
298
|
|
|
299
|
-
/*
|
|
300
|
-
|
|
299
|
+
/* Hover preview tooltip */
|
|
300
|
+
#note-preview {
|
|
301
|
+
position: fixed;
|
|
302
|
+
max-width: 260px;
|
|
303
|
+
z-index: 9998;
|
|
304
|
+
background: var(--joplin-background-color, #fff);
|
|
305
|
+
border: 1px solid var(--joplin-divider-color, #ccc);
|
|
306
|
+
border-radius: 6px;
|
|
307
|
+
box-shadow: 0 4px 14px rgba(0, 0, 0, 0.2);
|
|
308
|
+
padding: 8px 10px;
|
|
309
|
+
font-size: 12px;
|
|
310
|
+
pointer-events: none;
|
|
311
|
+
}
|
|
312
|
+
.note-preview-title {
|
|
313
|
+
font-weight: 600;
|
|
314
|
+
margin-bottom: 2px;
|
|
315
|
+
}
|
|
316
|
+
.note-preview-meta {
|
|
317
|
+
color: var(--joplin-color-faded, #888);
|
|
318
|
+
font-size: 10px;
|
|
319
|
+
margin-bottom: 5px;
|
|
320
|
+
}
|
|
321
|
+
.note-preview-body {
|
|
322
|
+
color: var(--joplin-color, #ddd);
|
|
323
|
+
opacity: 0.85;
|
|
324
|
+
line-height: 1.45;
|
|
325
|
+
word-break: break-word;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/* ---- unified section chrome ----
|
|
329
|
+
* One soft line ABOVE each section header plus breathing room; bodies draw
|
|
330
|
+
* no borders at all, so no state combination can double up lines. */
|
|
331
|
+
.pinned-section-header,
|
|
332
|
+
.smart-section-header,
|
|
333
|
+
.trash-section-header,
|
|
334
|
+
.tags-section-header {
|
|
301
335
|
display: flex;
|
|
302
336
|
align-items: center;
|
|
303
|
-
padding:
|
|
337
|
+
padding: 4px 8px;
|
|
304
338
|
gap: 5px;
|
|
305
|
-
margin:
|
|
339
|
+
margin: 5px 4px 1px;
|
|
306
340
|
min-height: 24px;
|
|
307
|
-
|
|
341
|
+
padding: 3px 8px;
|
|
342
|
+
border-top: 1px solid rgba(127, 127, 127, 0.22);
|
|
343
|
+
border-radius: 0 0 3px 3px;
|
|
308
344
|
cursor: pointer;
|
|
309
345
|
user-select: none;
|
|
310
346
|
color: var(--joplin-color-faded, #888);
|
|
311
|
-
font-weight:
|
|
347
|
+
font-weight: 600;
|
|
348
|
+
font-size: 13px;
|
|
349
|
+
letter-spacing: 0.4px;
|
|
350
|
+
}
|
|
351
|
+
/* Chevron sits right after the section name (Claude-sidebar style); the
|
|
352
|
+
* count keeps the right edge. */
|
|
353
|
+
.pinned-section-header .label,
|
|
354
|
+
.smart-section-header .label,
|
|
355
|
+
.trash-section-header .label,
|
|
356
|
+
.tags-section-header .label {
|
|
357
|
+
flex: 0 1 auto;
|
|
358
|
+
}
|
|
359
|
+
.pinned-section-header .toggle,
|
|
360
|
+
.smart-section-header .toggle,
|
|
361
|
+
.trash-section-header .toggle,
|
|
362
|
+
.tags-section-header .toggle {
|
|
363
|
+
order: 3;
|
|
364
|
+
width: auto;
|
|
365
|
+
margin-left: 2px;
|
|
366
|
+
font-size: 8px;
|
|
367
|
+
opacity: 0.75;
|
|
368
|
+
}
|
|
369
|
+
.pinned-section-header .count,
|
|
370
|
+
.smart-section-header .count,
|
|
371
|
+
.trash-section-header .count,
|
|
372
|
+
.tags-section-header .count {
|
|
373
|
+
order: 4; /* after the chevron (order 3): text › ......... count */
|
|
374
|
+
margin-left: auto;
|
|
375
|
+
}
|
|
376
|
+
.pinned-section-header .icon,
|
|
377
|
+
.smart-section-header .icon,
|
|
378
|
+
.trash-section-header .icon,
|
|
379
|
+
.tags-section-header .icon {
|
|
380
|
+
font-size: 12px;
|
|
381
|
+
opacity: 0.85;
|
|
312
382
|
}
|
|
313
|
-
|
|
314
|
-
.
|
|
383
|
+
.pinned-section-header:hover,
|
|
384
|
+
.smart-section-header:hover,
|
|
385
|
+
.trash-section-header:hover,
|
|
386
|
+
.tags-section-header:hover {
|
|
315
387
|
background: var(--joplin-background-color-hover3, rgba(100, 100, 100, 0.12));
|
|
316
388
|
}
|
|
389
|
+
/* The notebook tree has no header row - its wrapper draws the same
|
|
390
|
+
* section-opening line as the headers do. */
|
|
391
|
+
#main-tree {
|
|
392
|
+
margin: 5px 4px 1px;
|
|
393
|
+
padding-top: 4px;
|
|
394
|
+
border-top: 1px solid rgba(127, 127, 127, 0.22);
|
|
395
|
+
}
|
|
317
396
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
397
|
+
/* Expand animation: children fade/slide in when the USER toggles a section
|
|
398
|
+
* or folder (JS adds .anim-expand only on interactive expands, so panel
|
|
399
|
+
* re-renders don't flash). */
|
|
400
|
+
@keyframes sectionExpand {
|
|
401
|
+
from { opacity: 0; transform: translateY(-4px); }
|
|
402
|
+
to { opacity: 1; transform: none; }
|
|
403
|
+
}
|
|
404
|
+
.anim-expand { animation: sectionExpand 0.16s ease-out; }
|
|
405
|
+
|
|
406
|
+
/* Whichever section comes first sits right under the search bar's own
|
|
407
|
+
* border - no extra line there. */
|
|
408
|
+
#tree-container > div:first-child {
|
|
409
|
+
border-top: none;
|
|
410
|
+
margin-top: 0;
|
|
411
|
+
padding-top: 4px;
|
|
321
412
|
}
|
|
322
413
|
|
|
323
414
|
.pinned-section-body.collapsed {
|
|
@@ -328,27 +419,40 @@ html, body {
|
|
|
328
419
|
padding-left: 26px !important;
|
|
329
420
|
}
|
|
330
421
|
|
|
331
|
-
/*
|
|
332
|
-
|
|
333
|
-
.
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
margin: 6px 4px 1px;
|
|
339
|
-
min-height: 24px;
|
|
340
|
-
border-radius: 3px;
|
|
341
|
-
border-top: 1px solid var(--joplin-divider-color, #ddd);
|
|
342
|
-
cursor: pointer;
|
|
343
|
-
user-select: none;
|
|
344
|
-
color: var(--joplin-color-faded, #888);
|
|
345
|
-
font-weight: 700;
|
|
422
|
+
/* Expandable rows inside sections put their chevron AFTER the text, like
|
|
423
|
+
* the section headers - icons of all first-level rows align at the same
|
|
424
|
+
* left edge as pinned rows. */
|
|
425
|
+
.smart-folder .label,
|
|
426
|
+
.tag-folder .label,
|
|
427
|
+
.trash-note.folder .label {
|
|
428
|
+
flex: 0 1 auto;
|
|
346
429
|
}
|
|
347
|
-
.
|
|
348
|
-
.
|
|
349
|
-
|
|
430
|
+
.smart-folder .toggle,
|
|
431
|
+
.tag-folder .toggle,
|
|
432
|
+
.trash-note.folder .toggle {
|
|
433
|
+
order: 3;
|
|
434
|
+
width: auto;
|
|
435
|
+
margin-left: 2px;
|
|
436
|
+
font-size: 8px;
|
|
437
|
+
opacity: 0.75;
|
|
350
438
|
}
|
|
439
|
+
.smart-folder .count,
|
|
440
|
+
.tag-folder .count {
|
|
441
|
+
order: 4; /* after the chevron: text › ......... count */
|
|
442
|
+
margin-left: auto;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
/* ---- tags section (tags as folders) ---- */
|
|
351
446
|
.tags-section-body.collapsed { display: none; }
|
|
447
|
+
/* Smart folders sit right under the pinned body, whose border-bottom
|
|
448
|
+
* already draws the divider - a border-top here doubled the line. The
|
|
449
|
+
* section closes with its own bottom divider before the tree instead. */
|
|
450
|
+
.smart-section-body.collapsed { display: none; }
|
|
451
|
+
/* Empty smart folder: keeps its folder shape (arrow included) but dimmed,
|
|
452
|
+
* and clicking it does nothing (no children container exists). */
|
|
453
|
+
.smart-folder.smart-empty { opacity: 0.45; }
|
|
454
|
+
.smart-folder.smart-empty:hover { background: none; cursor: default; }
|
|
455
|
+
.smart-children.collapsed { display: none; }
|
|
352
456
|
.trash-children.collapsed { display: none; }
|
|
353
457
|
/* Rows carry inline padding (depth-based); containers only need hide/show */
|
|
354
458
|
.trash-folder-children.collapsed { display: none; }
|
package/publish/webview/panel.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var _savedScrollTop=0,_isFirstRender=!0;function postMsg(e){webviewApi.postMessage(e)}function currentSortMode(){var e=document.getElementById("notes-in-list-root");return e&&e.dataset.sort||""}postMsg({name:"panelReady"}),document.addEventListener("scroll",function(e){e.target&&"tree-container"===e.target.id&&(_savedScrollTop=e.target.scrollTop)},!0);var _observer=new MutationObserver(function(){var e=document.getElementById("tree-container");if(e)if(_isFirstRender){_isFirstRender=!1;var t=e.querySelector(".tree-item.note.selected");t&&setTimeout(function(){t.scrollIntoView({block:"nearest",behavior:"instant"})},30)}else e.scrollTop=_savedScrollTop});function loadI18n(){var e=document.getElementById("notes-in-list-root");if(e&&e.dataset.i18n)try{window._i18n=JSON.parse(e.dataset.i18n)}catch(e){}}function T(e){return window._i18n||loadI18n(),window._i18n&&window._i18n[e]||e}function getPinnedData(){var e=document.getElementById("notes-in-list-root");if(e&&e.dataset.pinned)try{return JSON.parse(e.dataset.pinned)}catch(e){}return[]}function isPinned(e){for(var t=getPinnedData(),a=0;a<t.length;a++)if(t[a].id===e)return!0;return!1}function showInlineInput(e,t,a){var n=document.getElementById("inline-input-overlay");n&&n.remove();var s=document.createElement("div");s.id="inline-input-overlay",s.className="inline-input-overlay",s.innerHTML='<div class="inline-input-dialog"><div class="inline-input-label">'+e+'</div><input class="inline-input-field" type="text" value="'+(t||"").replace(/"/g,""")+'" /><div class="inline-input-buttons"><button class="inline-input-ok">OK</button><button class="inline-input-cancel">'+(T("cancel")||"Cancel")+"</button></div></div>",document.body.appendChild(s);var d=s.querySelector(".inline-input-field");function o(){var e=d.value;s.remove(),a(e)}function i(){s.remove(),a(null)}d.focus(),d.select(),s.querySelector(".inline-input-ok").addEventListener("click",o),s.querySelector(".inline-input-cancel").addEventListener("click",i),d.addEventListener("keydown",function(e){"Enter"===e.key&&o(),"Escape"===e.key&&i()}),s.addEventListener("click",function(e){e.target===s&&i()})}function toggleFolderLocal(e,t){var a=e.classList.toggle("collapsed"),n=document.querySelector('.children[data-folder-id="'+t+'"]');n&&n.classList.toggle("collapsed",a);var s=e.querySelector(".toggle");s&&(s.textContent=a?"▶":"▼",s.classList.toggle("expanded",!a))}function collapseAllLocal(){var e=document.getElementById("tree-container");e&&(e.querySelectorAll(".tree-item.folder").forEach(function(e){if(!e.classList.contains("pinned-item")){e.classList.add("collapsed");var t=e.querySelector(".toggle");t&&(t.textContent="▶",t.classList.remove("expanded"))}}),e.querySelectorAll(".children").forEach(function(e){e.classList.add("collapsed")}))}function expandAllLocal(){var e=document.getElementById("tree-container");if(!e)return[];var t=[];return e.querySelectorAll(".tree-item.folder").forEach(function(e){if(!e.classList.contains("pinned-item")&&!e.classList.contains("tag-folder")){var a=e.dataset.id,n=document.querySelector('.children[data-folder-id="'+a+'"]'),s=n&&n.querySelector(".tree-item.folder"),d=e.querySelector(".toggle");s?(e.classList.remove("collapsed"),n&&n.classList.remove("collapsed"),d&&(d.textContent="▼",d.classList.add("expanded"))):(e.classList.add("collapsed"),n&&n.classList.add("collapsed"),d&&(d.textContent="▶",d.classList.remove("expanded")),a&&t.push(a))}}),t}function applyCollapsedSet(e){for(var t={},a=0;a<e.length;a++)t[e[a]]=!0;var n=[],s=document.getElementById("tree-container");return s?(s.querySelectorAll(".tree-item.folder").forEach(function(e){if(!e.classList.contains("pinned-item")&&!e.classList.contains("tag-folder")){var a=e.dataset.id,s=document.querySelector('.children[data-folder-id="'+a+'"]'),d=e.querySelector(".toggle"),o=!!t[a];e.classList.toggle("collapsed",o),s&&s.classList.toggle("collapsed",o),d&&(d.textContent=o?"▶":"▼",d.classList.toggle("expanded",!o)),o&&a&&n.push(a)}}),n):n}_observer.observe(document.body,{childList:!0,subtree:!0});var _collapseSnapshot=null;function expandAncestorsLocal(e){for(var t=e.closest(".children");t;){t.classList.remove("collapsed");var a=document.querySelector('.tree-item.folder:not(.pinned-item)[data-id="'+t.dataset.folderId+'"]');if(a){a.classList.remove("collapsed");var n=a.querySelector(".toggle");n&&(n.textContent="▼",n.classList.add("expanded"))}t=t.parentElement?t.parentElement.closest(".children"):null}}document.addEventListener("click",function(e){var t=e.target.closest(".ctx-item");if(t){if(t.dataset.msg){postMsg({name:t.dataset.msg});var a=document.getElementById("ctx-menu");return void(a&&a.remove())}if(t.classList.contains("ctx-drill")){var n=document.getElementById("ctx-menu"),s=n?n.querySelector(".ctx-export-template"):null;return void(n&&s&&(window._ctxMainHtml=n.innerHTML,n.innerHTML='<div class="ctx-item ctx-back">◂ '+(s.dataset.title||"")+'</div><div class="ctx-sep"></div>'+s.innerHTML))}if(t.classList.contains("ctx-back")){var d=document.getElementById("ctx-menu");return void(d&&window._ctxMainHtml&&(d.innerHTML=window._ctxMainHtml))}if(!t.dataset.action)return;postMsg({name:"contextMenu",action:t.dataset.action,id:t.dataset.id,itemType:t.dataset.type,tagId:t.dataset.tagId,format:t.dataset.format});var o=document.getElementById("ctx-menu");o&&o.remove()}else{var i=document.getElementById("ctx-menu");i&&i.remove();var r=e.target.closest(".search-tag-item");if(r)r.dataset.tagId&&postMsg({name:"loadTagNotes",tagId:r.dataset.tagId});else{var c=e.target.closest(".search-folder-item");if(c)c.dataset.folderId&&postMsg({name:"locateFolder",folderId:c.dataset.folderId});else{var l=e.target.closest(".pinned-section-header");if(l){var p=l.classList.toggle("collapsed"),g=document.getElementById("pinned-body");g&&g.classList.toggle("collapsed",p);var v=l.querySelector(".toggle");return v&&(v.textContent=p?"▶":"▼"),void postMsg({name:"togglePinnedCollapse"})}var m=e.target.closest(".tags-section-header");if(m){var u=m.classList.toggle("collapsed"),f=document.getElementById("tags-body");f&&f.classList.toggle("collapsed",u);var h=m.querySelector(".toggle");return h&&(h.textContent=u?"▶":"▼"),void postMsg({name:"toggleTagsSection"})}var y=e.target.closest(".trash-section-header");if(y){var x=y.classList.toggle("collapsed"),L=document.getElementById("trash-children");L&&L.classList.toggle("collapsed",x);var S=y.querySelector(".toggle");return S&&(S.textContent=x?"▶":"▼"),postMsg({name:"toggleTrashSection"}),void(x||!L||L.dataset.loaded||postMsg({name:"trashNotes"}))}var I=e.target.closest(".tag-folder");if(I){var b=I.dataset.tagId,E=document.querySelector('.tag-children[data-tag-id="'+b+'"]');if(!E)return;var w=E.classList.toggle("collapsed");I.classList.toggle("collapsed",w);var M=I.querySelector(".toggle");return M&&(M.textContent=w?"▶":"▼"),void(w||E.dataset.loaded||postMsg({name:"tagFolderNotes",tagId:b}))}var N=e.target.closest(".search-section-header");if(N){var q=document.getElementById("search-section-"+N.dataset.section);if(q){var _=N.querySelector(".section-toggle");q.classList.contains("collapsed")?(q.classList.remove("collapsed"),_&&(_.textContent="▼")):(q.classList.add("collapsed"),_&&(_.textContent="▶"))}}else{var B=e.target.closest(".tree-item");if(B){if("1"===B.dataset.trash){if("folder"===B.dataset.type){var C=document.querySelector('.trash-folder-children[data-folder-id="'+B.dataset.id+'"]');if(C){var D=C.classList.toggle("collapsed"),A=B.querySelector(".toggle");A&&(A.textContent=D?"▶":"▼"),D||C.dataset.loaded||postMsg({name:"trashFolderNotes",folderId:B.dataset.id})}}else"note"===B.dataset.type&&postMsg({name:"openNote",id:B.dataset.id});return}var k=B.dataset.type,F=B.dataset.id,H=B.classList.contains("pinned-item");"note"===k?(document.querySelectorAll(".tree-item.note.selected").forEach(function(e){e.classList.remove("selected")}),B.classList.add("selected"),postMsg({name:"openNote",id:F})):"folder"===k&&(H?postMsg({name:"locatePinnedFolder",folderId:F}):(toggleFolderLocal(B,F),postMsg({name:"toggleFolder",id:F})))}else{var R=e.target.closest("button");if(R)switch(R.id){case"btn-new":var P=document.getElementById("ctx-menu");if(P){P.remove();break}var O=document.getElementById("btn-new");if(!O)break;var Y=O.getBoundingClientRect();document.body.insertAdjacentHTML("beforeend",'<div id="ctx-menu" class="context-menu" style="left:'+Y.left+"px;top:"+(Y.bottom+2)+'px;"><div class="ctx-item" data-msg="newNotebook"><span class="ctx-icon">📁</span>'+T("newNotebook")+'</div><div class="ctx-item" data-msg="newNote"><span class="ctx-icon">📝</span>'+T("newNote")+'</div><div class="ctx-item" data-msg="newTodo"><span class="ctx-icon">☐</span>'+T("newTodo")+"</div></div>");break;case"btn-sort":postMsg({name:"cycleSort"});break;case"btn-collapse-all":var J=document.getElementById("btn-collapse-all");if(J&&"expand"===J.dataset.mode){var j,V=document.getElementById("notes-in-list-root"),W=V&&V.dataset.expandMode||"restore";if("all"===W)j=applyCollapsedSet([]);else if("restore"===W){var z=_collapseSnapshot;if(!z&&V)try{z=JSON.parse(V.dataset.collapseSnapshot||"null")}catch(e){z=null}j=Array.isArray(z)?applyCollapsedSet(z):expandAllLocal()}else j=expandAllLocal();postMsg({name:"expandAll",collapsedIds:j}),J.dataset.mode="collapse",J.textContent="▲",J.title=T("collapseAll")}else{var U=[];document.querySelectorAll("#tree-container .tree-item.folder").forEach(function(e){e.classList.contains("pinned-item")||e.classList.contains("tag-folder")||e.classList.contains("collapsed")&&e.dataset.id&&U.push(e.dataset.id)}),_collapseSnapshot=U,collapseAllLocal(),postMsg({name:"collapseAll",prevCollapsed:U}),J&&(J.dataset.mode="expand",J.textContent="▼",J.title=T("expandAll"))}break;case"btn-refresh":postMsg({name:"refreshView"});break;case"btn-sync":R.disabled||(R.disabled=!0,R.classList.add("syncing"),R.textContent="🔄 "+T("syncing"),postMsg({name:"sync"}))}}}}}}}),document.addEventListener("contextmenu",function(e){var t=document.getElementById("ctx-menu");if(t&&t.remove(),e.target.closest(".trash-section-header"))return e.preventDefault(),void document.body.insertAdjacentHTML("beforeend",'<div id="ctx-menu" class="context-menu" style="left:'+e.pageX+"px;top:"+e.pageY+'px;"><div class="ctx-item ctx-danger" data-action="emptyTrash" data-type="trashSection" data-id="trash">'+T("ctxEmptyTrash")+"</div></div>");var a=e.target.closest(".tree-item");if(a){e.preventDefault();var n=a.dataset.type,s=a.dataset.id,d="",o=a.querySelector(".label");o&&(d=o.textContent);var i='<div id="ctx-menu" class="context-menu" style="left:'+e.pageX+"px;top:"+e.pageY+'px;">';if("1"===a.dataset.trash){var r="folder"===n?"trashFolder":"trashNote";i+='<div class="ctx-item" data-action="restoreItem" data-id="'+s+'" data-type="'+r+'">'+T("ctxRestoreNote")+"</div>",i+='<div class="ctx-sep"></div>',i+='<div class="ctx-item ctx-danger" data-action="permanentDeleteItem" data-id="'+s+'" data-type="'+r+'">'+T("ctxPermanentDelete")+"</div>"}else if("folder"===n){var c=isPinned(s);i+='<div class="ctx-item" data-action="'+(c?"unpinFolder":"pinFolder")+'" data-id="'+s+'" data-type="folder">'+T(c?"ctxUnpin":"ctxPin")+"</div>",i+='<div class="ctx-sep"></div>',i+='<div class="ctx-item" data-action="newNote" data-id="'+s+'" data-type="folder">'+T("ctxNewNoteHere")+"</div>",i+='<div class="ctx-item" data-action="newTodo" data-id="'+s+'" data-type="folder">'+T("ctxNewTodoHere")+"</div>",i+='<div class="ctx-item" data-action="newSubNotebook" data-id="'+s+'" data-type="folder">'+T("ctxNewSubNotebook")+"</div>",i+='<div class="ctx-sep"></div>',i+='<div class="ctx-item" data-action="renameFolder" data-id="'+s+'" data-type="folder" data-title="'+d.replace(/"/g,""")+'">'+T("ctxRenameFolder")+"</div>",i+='<div class="ctx-item" data-action="exportFolder" data-id="'+s+'" data-type="folder">'+T("ctxExportFolder")+"</div>",i+='<div class="ctx-sep"></div>',i+='<div class="ctx-item ctx-danger" data-action="deleteFolder" data-id="'+s+'" data-type="folder">'+T("ctxDeleteFolder")+"</div>"}else if("note"===n){var l=isPinned(s);i+='<div class="ctx-item" data-action="'+(l?"unpinNote":"pinNote")+'" data-id="'+s+'" data-type="note">'+T(l?"ctxUnpin":"ctxPin")+"</div>",i+='<div class="ctx-sep"></div>',i+='<div class="ctx-item" data-action="openNote" data-id="'+s+'" data-type="note">'+T("ctxOpenNote")+"</div>",i+='<div class="ctx-item" data-action="openInNewWindow" data-id="'+s+'" data-type="note">'+T("ctxOpenInNewWindow")+"</div>",i+='<div class="ctx-sep"></div>',i+='<div class="ctx-item" data-action="setTags" data-id="'+s+'" data-type="note">'+T("ctxSetTags")+"</div>",i+='<div class="ctx-item" data-action="switchNoteType" data-id="'+s+'" data-type="note">'+T("ctxSwitchNoteType")+"</div>","1"===a.dataset.todo&&(i+='<div class="ctx-item" data-action="toggleTodo" data-id="'+s+'" data-type="note">'+T("ctxToggleTodo")+"</div>"),i+='<div class="ctx-item" data-action="moveToFolderDialog" data-id="'+s+'" data-type="note">'+T("ctxMoveToFolder")+"</div>",i+='<div class="ctx-item" data-action="duplicateNote" data-id="'+s+'" data-type="note">'+T("ctxDuplicateNote")+"</div>",i+='<div class="ctx-sep"></div>',i+='<div class="ctx-item" data-action="copyLink" data-id="'+s+'" data-type="note">'+T("ctxCopyLink")+"</div>",i+='<div class="ctx-item" data-action="copyExternalLink" data-id="'+s+'" data-type="note">'+T("ctxCopyExternalLink")+"</div>",i+='<div class="ctx-sep"></div>',i+='<div class="ctx-item" data-action="publishNote" data-id="'+s+'" data-type="note">'+T("ctxPublishNote")+"</div>",i+='<div class="ctx-item ctx-drill">'+T("ctxExport")+'<span class="ctx-sub-arrow">▸</span></div>',i+='<div class="ctx-export-template" style="display:none" data-title="'+T("ctxExport")+'"><div class="ctx-item" data-action="exportPdf" data-id="'+s+'" data-type="note">PDF</div><div class="ctx-item" data-action="exportNote" data-format="md" data-id="'+s+'" data-type="note">Markdown</div><div class="ctx-item" data-action="exportNote" data-format="md_frontmatter" data-id="'+s+'" data-type="note">Markdown + Front Matter</div><div class="ctx-item" data-action="exportNote" data-format="jex" data-id="'+s+'" data-type="note">JEX</div><div class="ctx-item" data-action="exportNote" data-format="html" data-id="'+s+'" data-type="note">HTML</div></div>',i+='<div class="ctx-sep"></div>',i+='<div class="ctx-item" data-action="renameNote" data-id="'+s+'" data-type="note" data-title="'+d.replace(/"/g,""")+'">'+T("ctxRenameNote")+"</div>",i+='<div class="ctx-item" data-action="noteInfo" data-id="'+s+'" data-type="note">'+T("ctxNoteInfo")+"</div>",i+='<div class="ctx-sep"></div>',i+='<div class="ctx-item ctx-danger" data-action="deleteNote" data-id="'+s+'" data-type="note">'+T("ctxDeleteNote")+"</div>",a.dataset.tagId&&(i+='<div class="ctx-sep"></div>',i+='<div class="ctx-item" data-action="untagNote" data-id="'+s+'" data-type="note" data-tag-id="'+a.dataset.tagId+'">'+T("ctxUntagNote")+"</div>")}else if("tag"===n){var p=a.dataset.tagId;i+='<div class="ctx-item" data-action="renameTag" data-id="'+p+'" data-type="tag">'+T("ctxRenameTag")+"</div>",i+='<div class="ctx-sep"></div>',i+='<div class="ctx-item ctx-danger" data-action="deleteTag" data-id="'+p+'" data-type="tag">'+T("ctxDeleteTag")+"</div>"}i+="</div>",document.body.insertAdjacentHTML("beforeend",i);var g=document.getElementById("ctx-menu"),v=g.getBoundingClientRect();v.right>window.innerWidth&&(g.style.left=window.innerWidth-v.width-4+"px"),v.bottom>window.innerHeight&&(g.style.top=window.innerHeight-v.height-4+"px")}}),document.addEventListener("mousedown",function(e){if(!e.target.closest("#ctx-menu")){var t=document.getElementById("ctx-menu");t&&t.remove()}}),webviewApi.onMessage(function(e){if(e&&e.message){var t=e.message;if("syncState"===t.name){var a=document.getElementById("btn-sync");if(!a)return;"syncing"===t.state?(a.disabled=!0,a.classList.remove("sync-done","sync-error"),a.classList.add("syncing"),a.textContent="🔄 "+T("syncing")):"done"===t.state?(a.classList.remove("syncing","sync-error"),a.classList.add("sync-done"),a.textContent=T("syncDone"),setTimeout(function(){var e=document.getElementById("btn-sync");e&&(e.disabled=!1,e.classList.remove("sync-done"),e.textContent="🔄 "+T("sync"))},2e3)):"error"===t.state&&(a.classList.remove("syncing","sync-done"),a.classList.add("sync-error"),a.textContent=T("syncFailed"),setTimeout(function(){var e=document.getElementById("btn-sync");e&&(e.disabled=!1,e.classList.remove("sync-error"),e.textContent="🔄 "+T("sync"))},4e3))}else if("searchResults"===t.name){if(void 0!==t.searchId&&t.searchId!==_searchId)return;t.notes||t.tags||t.folders?renderSearchResults(t.notes||[],t.tags||[],t.folders||[],t.query):_searchMode&&exitSearchMode()}else if("tagFolderNotes"===t.name){var n=document.querySelector('.tag-children[data-tag-id="'+t.tagId+'"]');if(n){n.dataset.loaded="1";for(var s="",d=0;d<t.notes.length;d++){var o=t.notes[d],i=o.is_todo?o.todo_completed?"☑":"☐":"📝";s+='<div class="tree-item note tag-note" data-id="'+o.id+'" data-type="note" data-tag-id="'+t.tagId+'" data-todo="'+(o.is_todo?1:0)+'"><span class="icon note-icon">'+i+'</span><span class="label">'+escapeHtml(o.title)+"</span></div>"}t.notes.length||(s='<div class="tag-empty">—</div>'),n.innerHTML=s}}else if("trashNotes"===t.name){var r=document.getElementById("trash-children");if(r){r.dataset.loaded="1";for(var c="",l=t.folders||[],p=0;p<l.length;p++){var g=l[p],v=g.depth||0;c+='<div class="tree-item folder trash-note" style="padding-left:'+(34+16*v)+'px" data-id="'+g.id+'" data-type="folder" data-trash="1" data-depth="'+v+'"><span class="toggle">'+(g.hasNotes?"▶":"")+'</span><span class="icon">📁</span><span class="label">'+escapeHtml(g.title)+"</span></div>",g.hasNotes&&(c+='<div class="trash-folder-children collapsed" data-folder-id="'+g.id+'" data-depth="'+v+'"></div>')}for(var m=t.notes||[],u=0;u<m.length;u++){var f=m[u],h=f.is_todo?f.todo_completed?"☑":"☐":"📝";c+='<div class="tree-item note trash-note" style="padding-left:34px" data-id="'+f.id+'" data-type="note" data-trash="1"><span class="icon note-icon">'+h+'</span><span class="label">'+escapeHtml(f.title)+"</span></div>"}c||(c='<div class="tag-empty">—</div>'),r.innerHTML=c}}else if("trashFolderNotes"===t.name){var y=document.querySelector('.trash-folder-children[data-folder-id="'+t.folderId+'"]');if(y){y.dataset.loaded="1";for(var x=34+16*(parseInt(y.dataset.depth||"0",10)+1),L="",S=0;S<t.notes.length;S++){var I=t.notes[S],b=I.is_todo?I.todo_completed?"☑":"☐":"📝";L+='<div class="tree-item note trash-note" style="padding-left:'+x+'px" data-id="'+I.id+'" data-type="note" data-trash="1"><span class="icon note-icon">'+b+'</span><span class="label">'+escapeHtml(I.title)+"</span></div>"}t.notes.length||(L='<div class="tag-empty" style="padding-left:'+x+'px">—</div>'),y.innerHTML=L}}else if("tagNotes"===t.name)expandTagNotes(t.tagId,t.notes);else if("scrollToFolder"===t.name)setTimeout(function(){var e=document.querySelector('.tree-item.folder:not(.pinned-item)[data-id="'+t.folderId+'"]');e&&(expandAncestorsLocal(e),e.scrollIntoView({block:"center",behavior:"smooth"}),e.classList.add("locate-flash"),setTimeout(function(){e.classList.remove("locate-flash")},1500))},80);else if("exitSearch"===t.name){var E=document.getElementById("search-input");E&&(E.value=""),_searchMode&&exitSearchMode()}else if("exitSearchAndLocate"===t.name){var w=document.getElementById("search-input");w&&(w.value=""),_searchMode=!1,showSearchContainer(!1),setTimeout(function(){var e=document.querySelector('.tree-item.folder[data-id="'+t.folderId+'"]');e&&(expandAncestorsLocal(e),e.scrollIntoView({block:"center",behavior:"smooth"}),e.classList.add("locate-flash"),setTimeout(function(){e.classList.remove("locate-flash")},1500))},80)}else if("copyText"===t.name)if(navigator.clipboard&&navigator.clipboard.writeText)navigator.clipboard.writeText(t.text);else{var M=document.createElement("textarea");M.value=t.text,document.body.appendChild(M),M.select(),document.execCommand("copy"),M.remove()}else if("selectNote"===t.name){document.querySelectorAll(".tree-item.note.selected").forEach(function(e){e.classList.remove("selected")});var N=document.querySelector('.tree-item.note[data-id="'+t.id+'"]');N&&(N.classList.add("selected"),N.scrollIntoView({block:"nearest",behavior:"instant"}))}else"updateNote"===t.name&&document.querySelectorAll('.tree-item.note[data-id="'+t.id+'"]').forEach(function(e){var a=e.querySelector(".label");a&&(a.textContent=t.title);var n=e.querySelector(".search-result-title");n&&(n.textContent=t.title);var s=e.querySelector(".note-icon");s&&(s.textContent=t.icon)})}}),document.addEventListener("mousedown",function(e){var t=e.target.closest(".tree-item");t&&0===e.button&&t.setAttribute("draggable","true")}),document.addEventListener("dragstart",function(e){var t=e.target.closest(".tree-item");if(t)if(t.closest(".trash-children"))e.preventDefault();else{var a=t.classList.contains("pinned-item");if(e.dataTransfer.setData("text/plain",JSON.stringify({id:t.dataset.id,type:t.dataset.type,pinned:a})),e.dataTransfer.effectAllowed="move",t.classList.add("dragging"),!a){var n=document.getElementById("tree-container");n&&n.classList.add("dragging-active")}}});var _dragScrollDir=0,_dragScrollRaf=null;function dragScrollStep(){var e=document.getElementById("tree-container");e&&_dragScrollDir?(e.scrollTop+=_dragScrollDir,_dragScrollRaf=requestAnimationFrame(dragScrollStep)):_dragScrollRaf=null}function updateDragScroll(e){var t=document.getElementById("tree-container");if(t){var a=t.getBoundingClientRect(),n=a.bottom,s=document.getElementById("drop-zone-empty");if(s&&t.classList.contains("dragging-active")){var d=s.getBoundingClientRect();d.height>0&&d.top>a.top&&(n=d.top)}var o=0;e<a.top+40?o=-Math.ceil((a.top+40-e)/4):e>n?o=0:e>n-40&&(o=Math.ceil((e-(n-40))/4)),_dragScrollDir=o,o&&!_dragScrollRaf&&(_dragScrollRaf=requestAnimationFrame(dragScrollStep))}else _dragScrollDir=0}function clearDropIndicators(){document.querySelectorAll(".drop-target").forEach(function(e){e.classList.remove("drop-target")}),document.querySelectorAll(".drop-above").forEach(function(e){e.classList.remove("drop-above")}),document.querySelectorAll(".drop-below").forEach(function(e){e.classList.remove("drop-below")})}function endDrag(){_dragScrollDir=0,clearDropIndicators();var e=document.getElementById("tree-container");e&&e.classList.remove("dragging-active")}document.addEventListener("dragend",function(e){var t=e.target.closest(".tree-item");t&&(t.classList.remove("dragging"),t.removeAttribute("draggable")),endDrag()}),document.addEventListener("dragover",function(e){document.querySelector(".tree-item.dragging")&&updateDragScroll(e.clientY);var t=e.target;if(t&&3===t.nodeType&&(t=t.parentElement),t){var a=t.closest(".tree-item");if(document.getElementById("tree-container"),t.closest("#drop-zone-empty"))document.querySelector(".tree-item.dragging.pinned-item")||(e.preventDefault(),e.dataTransfer.dropEffect="move");else{if(t.closest(".pinned-section-header"))return e.preventDefault(),e.dataTransfer.dropEffect="move",void clearDropIndicators();if(t.closest(".pinned-section-body")){if(document.querySelector(".tree-item.dragging.pinned-item")&&a&&a.classList.contains("pinned-item")){e.preventDefault(),e.dataTransfer.dropEffect="move",clearDropIndicators();var n=a.getBoundingClientRect();e.clientY-n.top<.5*n.height?a.classList.add("drop-above"):a.classList.add("drop-below")}}else{var s=t.closest(".tag-folder");if(s)document.querySelector(".tree-item.note.dragging")&&(e.preventDefault(),e.dataTransfer.dropEffect="move",clearDropIndicators(),s.classList.add("drop-target"));else if(!(t.closest(".tags-section-body")||t.closest(".tags-section-header")||t.closest(".trash-children")||t.closest(".trash-section-header"))&&a){var d=document.querySelector(".tree-item.dragging");if(!d||!d.classList.contains("pinned-item")){e.preventDefault(),e.dataTransfer.dropEffect="move",clearDropIndicators();var o=a.dataset.type,i=a.getBoundingClientRect(),r=e.clientY-i.top,c=i.height;"folder"===o?r<.25*c?a.classList.add("drop-above"):r>.75*c?a.classList.add("drop-below"):a.classList.add("drop-target"):"manual"===currentSortMode()?r<.5*c?a.classList.add("drop-above"):a.classList.add("drop-below"):a.classList.add("drop-target")}}}}}}),document.addEventListener("dragleave",function(e){var t=e.target.closest(".tree-item");t&&(t.classList.remove("drop-target"),t.classList.remove("drop-above"),t.classList.remove("drop-below"));var a=document.getElementById("tree-container");a&&e.target===a&&a.classList.remove("drop-empty")}),document.addEventListener("drop",function(e){e.preventDefault();var t=e.target;t&&3===t.nodeType&&(t=t.parentElement);var a,n=t?t.closest(".tree-item"):null;document.getElementById("tree-container");try{a=JSON.parse(e.dataTransfer.getData("text/plain"))}catch(e){return void endDrag()}var s=a.id,d=a.type,o=a.pinned;if(t&&t.closest("#drop-zone-empty")&&!o)return postMsg({name:"dragToEmpty",dragId:s,dragType:d}),void endDrag();if(t&&t.closest(".pinned-section-header")&&!o)return"note"===d?postMsg({name:"contextMenu",action:"pinNote",id:s,itemType:"note"}):"folder"===d&&postMsg({name:"contextMenu",action:"pinFolder",id:s,itemType:"folder"}),void endDrag();if(t&&t.closest(".pinned-section-body")&&o){var i=n&&n.classList.contains("pinned-item")?n:null;if(i&&i.dataset.id!==s){var r=i.getBoundingClientRect(),c=e.clientY-r.top<.5*r.height?"before":"after";postMsg({name:"reorderPinned",dragId:s,dragType:d,targetId:i.dataset.id,position:c})}endDrag()}else{var l=t?t.closest(".tag-folder"):null;if(l)return"note"===d&&postMsg({name:"tagNoteAdd",tagId:l.dataset.tagId,noteId:s}),void endDrag();if(t&&(t.closest(".tags-section-body")||t.closest(".tags-section-header")||t.closest(".trash-children")||t.closest(".trash-section-header")))endDrag();else if(o)endDrag();else if(n){var p=n.dataset.id,g=n.dataset.type;if(s!==p){var v=n.getBoundingClientRect(),m=e.clientY-v.top,u=v.height;postMsg("folder"===g?m>=.25*u&&m<=.75*u?{name:"dragDrop",dragId:s,dragType:d,targetId:p,position:"into"}:{name:"dragDrop",dragId:s,dragType:d,targetId:p,position:m<.25*u?"above":"below"}:"note"===d?{name:"dragDrop",dragId:s,dragType:d,targetId:p,position:m<.5*u?"above":"below"}:{name:"dragDrop",dragId:s,dragType:d,targetId:p,position:"into"}),endDrag()}else endDrag()}else endDrag()}});var _searchTimer=null,_searchMode=!1,_searchId=0;function escapeRegex(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function escapeHtml(e){return String(null==e?"":e).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}function highlightText(e,t){var a=escapeHtml(e);if(!t)return a;var n=new RegExp("("+escapeRegex(t)+")","gi");return a.replace(n,'<mark class="search-highlight">$1</mark>')}function showSearchContainer(e){var t=document.getElementById("tree-container"),a=document.getElementById("search-results");t&&(t.style.display=e?"none":""),a&&(a.style.display=e?"":"none")}function renderNoteItem(e,t){var a="📝";e.is_todo&&(a=e.todo_completed?"☑":"☐");var n='<div class="search-result-item tree-item note" data-id="'+e.id+'" data-type="note" data-todo="'+(e.is_todo?1:0)+'">';return n+='<span class="icon note-icon">'+a+"</span>",n+='<div class="search-result-content">',n+='<div class="search-result-title">'+highlightText(e.title,t)+"</div>",e.folderName&&(n+='<div class="search-result-folder">📂 '+escapeHtml(e.folderName)+"</div>"),e.snippet&&(n+='<div class="search-result-snippet">'+highlightText(e.snippet,t)+"</div>"),n+"</div></div>"}function renderSearchResults(e,t,a,n){var s=document.getElementById("search-results");if(s){showSearchContainer(!0);var d=e.length+t.length+a.length;if(0!==d){var o='<div class="search-status">'+T("searchResultCount").replace("{count}",d)+"</div>";if(a.length>0){o+=m("📁",T("searchSectionFolders"),a.length,"folders"),o+='<div class="search-section-body" id="search-section-folders">';for(var i=0;i<a.length;i++){var r=a[i],c=r.iconEmoji||"📁";o+='<div class="search-result-item search-folder-item" data-folder-id="'+r.id+'">',o+='<span class="icon">'+c+"</span>",o+='<div class="search-result-content">',o+='<div class="search-result-title">'+highlightText(r.title,n)+"</div>",o+="</div></div>"}o+="</div>"}if(e.length>0){o+=m("📝",T("searchSectionNotes"),e.length,"notes"),o+='<div class="search-section-body" id="search-section-notes">';for(var l=0;l<e.length;l++)o+=renderNoteItem(e[l],n);o+="</div>"}if(t.length>0){o+=m("🏷️",T("searchSectionTags"),t.length,"tags"),o+='<div class="search-section-body" id="search-section-tags">';for(var p=0;p<t.length;p++){var g=t[p],v=T("searchTagNoteCount").replace("{count}",g.noteCount);o+='<div class="search-result-item search-tag-item" data-tag-id="'+g.id+'">',o+='<span class="icon">🏷️</span>',o+='<div class="search-result-content">',o+='<div class="search-result-title">'+highlightText(g.title,n)+"</div>",o+='<div class="search-result-folder">'+v+"</div>",o+="</div>",o+='<span class="tag-expand-arrow">▶</span>',o+="</div>",o+='<div class="tag-notes-container" id="tag-notes-'+g.id+'"></div>'}o+="</div>"}s.innerHTML=o,_searchMode=!0}else s.innerHTML='<div class="search-status">'+T("searchNoResult")+"</div>"}function m(e,t,a,n){return'<div class="search-section-header" data-section="'+n+'"><span class="section-toggle">▼</span> '+e+" "+t+" ("+a+")</div>"}}function expandTagNotes(e,t){var a=document.getElementById("tag-notes-"+e);if(a){var n;if(a.children.length>0)return a.innerHTML="",void((n=document.querySelector('.search-tag-item[data-tag-id="'+e+'"] .tag-expand-arrow'))&&n.classList.remove("expanded"));for(var s="",d=0;d<t.length;d++)s+=renderNoteItem(t[d],"");0===t.length&&(s='<div class="search-status" style="padding-left:30px;">'+T("searchNoResult")+"</div>"),a.innerHTML=s,(n=document.querySelector('.search-tag-item[data-tag-id="'+e+'"] .tag-expand-arrow'))&&n.classList.add("expanded")}}function exitSearchMode(){_searchMode=!1,showSearchContainer(!1)}document.addEventListener("input",function(e){if("search-input"===e.target.id){var t=e.target.value.trim();_searchTimer&&clearTimeout(_searchTimer);var a=++_searchId;if(t){_searchMode=!0;var n=document.getElementById("search-results");n&&(n.innerHTML='<div class="search-status">'+T("searching")+"</div>"),showSearchContainer(!0),_searchTimer=setTimeout(function(){postMsg({name:"search",query:t,searchId:a})},400)}else _searchMode&&exitSearchMode()}}),document.addEventListener("keydown",function(e){if("Escape"===e.key){var t=document.getElementById("search-input");t&&t.value&&(t.value="",_searchMode&&exitSearchMode())}});
|
|
1
|
+
var _savedScrollTop=0,_isFirstRender=!0;function postMsg(e){webviewApi.postMessage(e)}function currentSortMode(){var e=document.getElementById("notes-in-list-root");return e&&e.dataset.sort||""}postMsg({name:"panelReady"}),document.addEventListener("scroll",function(e){e.target&&"tree-container"===e.target.id&&(_savedScrollTop=e.target.scrollTop)},!0);var _observer=new MutationObserver(function(){var e=document.getElementById("tree-container");if(e)if(_isFirstRender){_isFirstRender=!1;var t=e.querySelector(".tree-item.note.selected");t&&setTimeout(function(){t.scrollIntoView({block:"nearest",behavior:"instant"})},30)}else e.scrollTop=_savedScrollTop});function loadI18n(){var e=document.getElementById("notes-in-list-root");if(e&&e.dataset.i18n)try{window._i18n=JSON.parse(e.dataset.i18n)}catch(e){}}function T(e){return window._i18n||loadI18n(),window._i18n&&window._i18n[e]||e}function getPinnedData(){var e=document.getElementById("notes-in-list-root");if(e&&e.dataset.pinned)try{return JSON.parse(e.dataset.pinned)}catch(e){}return[]}function isPinned(e){for(var t=getPinnedData(),a=0;a<t.length;a++)if(t[a].id===e)return!0;return!1}function showInlineInput(e,t,a){var n=document.getElementById("inline-input-overlay");n&&n.remove();var d=document.createElement("div");d.id="inline-input-overlay",d.className="inline-input-overlay",d.innerHTML='<div class="inline-input-dialog"><div class="inline-input-label">'+e+'</div><input class="inline-input-field" type="text" value="'+(t||"").replace(/"/g,""")+'" /><div class="inline-input-buttons"><button class="inline-input-ok">OK</button><button class="inline-input-cancel">'+(T("cancel")||"Cancel")+"</button></div></div>",document.body.appendChild(d);var s=d.querySelector(".inline-input-field");function o(){var e=s.value;d.remove(),a(e)}function i(){d.remove(),a(null)}s.focus(),s.select(),d.querySelector(".inline-input-ok").addEventListener("click",o),d.querySelector(".inline-input-cancel").addEventListener("click",i),s.addEventListener("keydown",function(e){"Enter"===e.key&&o(),"Escape"===e.key&&i()}),d.addEventListener("click",function(e){e.target===d&&i()})}function animateExpand(e){e&&(e.classList.remove("anim-expand"),e.offsetWidth,e.classList.add("anim-expand"))}function toggleFolderLocal(e,t){var a=e.classList.toggle("collapsed"),n=document.querySelector('.children[data-folder-id="'+t+'"]');n&&n.classList.toggle("collapsed",a),a||animateExpand(n);var d=e.querySelector(".toggle");d&&(d.textContent=a?"▶":"▼",d.classList.toggle("expanded",!a))}function collapseAllLocal(){var e=document.getElementById("tree-container");e&&(e.querySelectorAll(".tree-item.folder").forEach(function(e){if(!e.classList.contains("pinned-item")){e.classList.add("collapsed");var t=e.querySelector(".toggle");t&&(t.textContent="▶",t.classList.remove("expanded"))}}),e.querySelectorAll(".children").forEach(function(e){e.classList.add("collapsed")}))}function expandAllLocal(){var e=document.getElementById("tree-container");if(!e)return[];var t=[];return e.querySelectorAll(".tree-item.folder").forEach(function(e){if(!e.classList.contains("pinned-item")&&!e.classList.contains("tag-folder")){var a=e.dataset.id,n=document.querySelector('.children[data-folder-id="'+a+'"]'),d=n&&n.querySelector(".tree-item.folder"),s=e.querySelector(".toggle");d?(e.classList.remove("collapsed"),n&&n.classList.remove("collapsed"),s&&(s.textContent="▼",s.classList.add("expanded"))):(e.classList.add("collapsed"),n&&n.classList.add("collapsed"),s&&(s.textContent="▶",s.classList.remove("expanded")),a&&t.push(a))}}),t}function applyCollapsedSet(e){for(var t={},a=0;a<e.length;a++)t[e[a]]=!0;var n=[],d=document.getElementById("tree-container");return d?(d.querySelectorAll(".tree-item.folder").forEach(function(e){if(!e.classList.contains("pinned-item")&&!e.classList.contains("tag-folder")){var a=e.dataset.id,d=document.querySelector('.children[data-folder-id="'+a+'"]'),s=e.querySelector(".toggle"),o=!!t[a];e.classList.toggle("collapsed",o),d&&d.classList.toggle("collapsed",o),s&&(s.textContent=o?"▶":"▼",s.classList.toggle("expanded",!o)),o&&a&&n.push(a)}}),n):n}_observer.observe(document.body,{childList:!0,subtree:!0});var _collapseSnapshot=null;function expandAncestorsLocal(e){for(var t=e.closest(".children");t;){t.classList.remove("collapsed");var a=document.querySelector('.tree-item.folder:not(.pinned-item)[data-id="'+t.dataset.folderId+'"]');if(a){a.classList.remove("collapsed");var n=a.querySelector(".toggle");n&&(n.textContent="▼",n.classList.add("expanded"))}t=t.parentElement?t.parentElement.closest(".children"):null}}var _hoverTimer=null,_hoverNoteId="";function hidePreview(){_hoverTimer&&(clearTimeout(_hoverTimer),_hoverTimer=null),_hoverNoteId="";var e=document.getElementById("note-preview");e&&e.remove()}function hoverPreviewEnabled(){var e=document.getElementById("notes-in-list-root");return!e||"0"!==e.dataset.hoverPreview}function showPreview(e){if(e.id===_hoverNoteId&&!document.getElementById("ctx-menu")){var t=document.querySelector('.tree-item.note[data-id="'+e.id+'"]');if(t&&t.matches(":hover")){var a=document.getElementById("note-preview");a&&a.remove();var n=document.createElement("div");n.id="note-preview";var d=document.createElement("div");d.className="note-preview-title",d.textContent=e.title,n.appendChild(d);var s=document.createElement("div");s.className="note-preview-meta";for(var o=[T("pvType")+": "+(e.isTodo?T("pvTodo"):T("pvNote"))+" · "+T("pvSize")+": "+(e.size||0)+" "+T("pvChars"),T("pvCreated")+": "+m(e.created),T("pvUpdated")+": "+m(e.updated)],i=0;i<o.length;i++){var r=document.createElement("div");r.textContent=o[i],s.appendChild(r)}n.appendChild(s);var l=document.createElement("div");l.className="note-preview-body",l.textContent=e.snippet||"",e.snippet&&n.appendChild(l),document.body.appendChild(n);var c=t.getBoundingClientRect(),v=n.getBoundingClientRect(),p=c.bottom+4;p+v.height>window.innerHeight-8&&(p=Math.max(8,c.top-v.height-4)),n.style.top=p+"px",n.style.left=Math.max(8,Math.min(c.left+20,window.innerWidth-v.width-8))+"px"}}function m(e){if(!e)return"";var t=new Date(e);return t.getFullYear()+"-"+("0"+(t.getMonth()+1)).slice(-2)+"-"+("0"+t.getDate()).slice(-2)+" "+("0"+t.getHours()).slice(-2)+":"+("0"+t.getMinutes()).slice(-2)}}document.addEventListener("mouseover",function(e){if(hoverPreviewEnabled())if(document.getElementById("ctx-menu"))hidePreview();else{var t=e.target.closest?e.target.closest(".tree-item.note"):null;if(t){var a=t.dataset.id;a&&a!==_hoverNoteId&&(hidePreview(),_hoverNoteId=a,_hoverTimer=setTimeout(function(){_hoverNoteId!==a||document.querySelector(".tree-item.dragging")||postMsg({name:"notePreview",id:a})},450))}else hidePreview()}}),document.addEventListener("scroll",function(){hidePreview()},!0),document.addEventListener("mousedown",function(){hidePreview()}),document.addEventListener("dragstart",function(){hidePreview()}),window.addEventListener("blur",function(){var e=document.getElementById("ctx-menu");e&&e.remove(),hidePreview()}),document.addEventListener("click",function(e){var t=e.target.closest(".ctx-item");if(t){if(t.dataset.msg){postMsg({name:t.dataset.msg});var a=document.getElementById("ctx-menu");return void(a&&a.remove())}if(t.classList.contains("ctx-drill")){var n=document.getElementById("ctx-menu"),d=n?n.querySelector(".ctx-export-template"):null;return void(n&&d&&(window._ctxMainHtml=n.innerHTML,n.innerHTML='<div class="ctx-item ctx-back">◂ '+(d.dataset.title||"")+'</div><div class="ctx-sep"></div>'+d.innerHTML))}if(t.classList.contains("ctx-back")){var s=document.getElementById("ctx-menu");return void(s&&window._ctxMainHtml&&(s.innerHTML=window._ctxMainHtml))}if(!t.dataset.action)return;postMsg({name:"contextMenu",action:t.dataset.action,id:t.dataset.id,itemType:t.dataset.type,tagId:t.dataset.tagId,format:t.dataset.format});var o=document.getElementById("ctx-menu");o&&o.remove()}else{var i=document.getElementById("ctx-menu");i&&i.remove();var r=e.target.closest(".search-tag-item");if(r)r.dataset.tagId&&postMsg({name:"loadTagNotes",tagId:r.dataset.tagId});else{var l=e.target.closest(".search-folder-item");if(l)l.dataset.folderId&&postMsg({name:"locateFolder",folderId:l.dataset.folderId});else{var c=e.target.closest(".pinned-section-header");if(c){var v=c.classList.toggle("collapsed"),p=document.getElementById("pinned-body");p&&p.classList.toggle("collapsed",v),v||animateExpand(p);var m=c.querySelector(".toggle");return m&&(m.textContent=v?"▶":"▼"),void postMsg({name:"togglePinnedCollapse"})}var g=e.target.closest(".tags-section-header");if(g){var u=g.classList.toggle("collapsed"),f=document.getElementById("tags-body");f&&f.classList.toggle("collapsed",u),u||animateExpand(f);var h=g.querySelector(".toggle");return h&&(h.textContent=u?"▶":"▼"),void postMsg({name:"toggleTagsSection"})}var y=e.target.closest(".smart-section-header");if(y){var x=y.classList.toggle("collapsed"),L=document.getElementById("smart-body");L&&L.classList.toggle("collapsed",x),x||animateExpand(L);var I=y.querySelector(".toggle");return I&&(I.textContent=x?"▶":"▼"),void postMsg({name:"toggleSmartSection"})}var E=e.target.closest(".smart-folder");if(E){var S=E.dataset.smartId,b=document.querySelector('.smart-children[data-smart-id="'+S+'"]');if(!b)return;var w=b.classList.toggle("collapsed");E.classList.toggle("collapsed",w),w||animateExpand(b);var M=E.querySelector(".toggle");return M&&(M.textContent=w?"▶":"▼"),void(w||postMsg({name:"smartFolderNotes",smartId:S,query:E.dataset.query}))}var N=e.target.closest(".trash-section-header");if(N){var _=N.classList.toggle("collapsed"),q=document.getElementById("trash-children");q&&q.classList.toggle("collapsed",_),_||animateExpand(q);var C=N.querySelector(".toggle");return C&&(C.textContent=_?"▶":"▼"),postMsg({name:"toggleTrashSection"}),void(_||!q||q.dataset.loaded||postMsg({name:"trashNotes"}))}var B=e.target.closest(".tag-folder");if(B){var D=B.dataset.tagId,A=document.querySelector('.tag-children[data-tag-id="'+D+'"]');if(!A)return;var k=A.classList.toggle("collapsed");B.classList.toggle("collapsed",k),k||animateExpand(A);var H=B.querySelector(".toggle");return H&&(H.textContent=k?"▶":"▼"),void(k||A.dataset.loaded||postMsg({name:"tagFolderNotes",tagId:D}))}var F=e.target.closest(".search-section-header");if(F){var R=document.getElementById("search-section-"+F.dataset.section);if(R){var P=F.querySelector(".section-toggle");R.classList.contains("collapsed")?(R.classList.remove("collapsed"),P&&(P.textContent="▼")):(R.classList.add("collapsed"),P&&(P.textContent="▶"))}}else{var O=e.target.closest(".tree-item");if(O){if("1"===O.dataset.trash){if("folder"===O.dataset.type){var Y=document.querySelector('.trash-folder-children[data-folder-id="'+O.dataset.id+'"]');if(Y){var J=Y.classList.toggle("collapsed");J||animateExpand(Y);var W=O.querySelector(".toggle");W&&(W.textContent=J?"▶":"▼"),J||Y.dataset.loaded||postMsg({name:"trashFolderNotes",folderId:O.dataset.id})}}else"note"===O.dataset.type&&postMsg({name:"openNote",id:O.dataset.id});return}var j=O.dataset.type,z=O.dataset.id,V=O.classList.contains("pinned-item");"note"===j?(document.querySelectorAll(".tree-item.note.selected").forEach(function(e){e.classList.remove("selected")}),O.classList.add("selected"),postMsg({name:"openNote",id:z})):"folder"===j&&(V?postMsg({name:"locatePinnedFolder",folderId:z}):(toggleFolderLocal(O,z),postMsg({name:"toggleFolder",id:z})))}else{var U=e.target.closest("button");if(U)switch(U.id){case"btn-new":var X=document.getElementById("ctx-menu");if(X){X.remove();break}var $=document.getElementById("btn-new");if(!$)break;var K=$.getBoundingClientRect();document.body.insertAdjacentHTML("beforeend",'<div id="ctx-menu" class="context-menu" style="left:'+K.left+"px;top:"+(K.bottom+2)+'px;"><div class="ctx-item" data-msg="newNotebook"><span class="ctx-icon">📁</span>'+T("newNotebook")+'</div><div class="ctx-item" data-msg="newNote"><span class="ctx-icon">📝</span>'+T("newNote")+'</div><div class="ctx-item" data-msg="newTodo"><span class="ctx-icon">☐</span>'+T("newTodo")+"</div></div>");break;case"btn-sort":postMsg({name:"cycleSort"});break;case"btn-collapse-all":var G=document.getElementById("btn-collapse-all");if(G&&"expand"===G.dataset.mode){var Q,Z=document.getElementById("notes-in-list-root"),ee=Z&&Z.dataset.expandMode||"restore";if("all"===ee)Q=applyCollapsedSet([]);else if("restore"===ee){var te=_collapseSnapshot;if(!te&&Z)try{te=JSON.parse(Z.dataset.collapseSnapshot||"null")}catch(e){te=null}Q=Array.isArray(te)?applyCollapsedSet(te):expandAllLocal()}else Q=expandAllLocal();postMsg({name:"expandAll",collapsedIds:Q}),G.dataset.mode="collapse",G.textContent="▲",G.title=T("collapseAll")}else{var ae=[];document.querySelectorAll("#tree-container .tree-item.folder").forEach(function(e){e.classList.contains("pinned-item")||e.classList.contains("tag-folder")||e.classList.contains("collapsed")&&e.dataset.id&&ae.push(e.dataset.id)}),_collapseSnapshot=ae,collapseAllLocal(),postMsg({name:"collapseAll",prevCollapsed:ae}),G&&(G.dataset.mode="expand",G.textContent="▼",G.title=T("expandAll"))}break;case"btn-refresh":postMsg({name:"refreshView"});break;case"btn-sync":U.disabled||(U.disabled=!0,U.classList.add("syncing"),U.textContent="🔄 "+T("syncing"),postMsg({name:"sync"}))}}}}}}}),document.addEventListener("contextmenu",function(e){hidePreview();var t=document.getElementById("ctx-menu");if(t&&t.remove(),e.target.closest(".trash-section-header"))return e.preventDefault(),void document.body.insertAdjacentHTML("beforeend",'<div id="ctx-menu" class="context-menu" style="left:'+e.pageX+"px;top:"+e.pageY+'px;"><div class="ctx-item ctx-danger" data-action="emptyTrash" data-type="trashSection" data-id="trash">'+T("ctxEmptyTrash")+"</div></div>");var a=e.target.closest(".tree-item");if(a){e.preventDefault();var n=a.dataset.type,d=a.dataset.id,s="",o=a.querySelector(".label");o&&(s=o.textContent);var i='<div id="ctx-menu" class="context-menu" style="left:'+e.pageX+"px;top:"+e.pageY+'px;">';if("1"===a.dataset.trash){var r="folder"===n?"trashFolder":"trashNote";i+='<div class="ctx-item" data-action="restoreItem" data-id="'+d+'" data-type="'+r+'">'+T("ctxRestoreNote")+"</div>",i+='<div class="ctx-sep"></div>',i+='<div class="ctx-item ctx-danger" data-action="permanentDeleteItem" data-id="'+d+'" data-type="'+r+'">'+T("ctxPermanentDelete")+"</div>"}else if("folder"===n){var l=isPinned(d);i+='<div class="ctx-item" data-action="'+(l?"unpinFolder":"pinFolder")+'" data-id="'+d+'" data-type="folder">'+T(l?"ctxUnpin":"ctxPin")+"</div>",i+='<div class="ctx-sep"></div>',i+='<div class="ctx-item" data-action="newNote" data-id="'+d+'" data-type="folder">'+T("ctxNewNoteHere")+"</div>",i+='<div class="ctx-item" data-action="newTodo" data-id="'+d+'" data-type="folder">'+T("ctxNewTodoHere")+"</div>",i+='<div class="ctx-item" data-action="newSubNotebook" data-id="'+d+'" data-type="folder">'+T("ctxNewSubNotebook")+"</div>",i+='<div class="ctx-sep"></div>',i+='<div class="ctx-item" data-action="renameFolder" data-id="'+d+'" data-type="folder" data-title="'+s.replace(/"/g,""")+'">'+T("ctxRenameFolder")+"</div>",i+='<div class="ctx-item" data-action="exportFolder" data-id="'+d+'" data-type="folder">'+T("ctxExportFolder")+"</div>",i+='<div class="ctx-sep"></div>',i+='<div class="ctx-item ctx-danger" data-action="deleteFolder" data-id="'+d+'" data-type="folder">'+T("ctxDeleteFolder")+"</div>"}else if("note"===n){var c=isPinned(d);i+='<div class="ctx-item" data-action="'+(c?"unpinNote":"pinNote")+'" data-id="'+d+'" data-type="note">'+T(c?"ctxUnpin":"ctxPin")+"</div>",i+='<div class="ctx-sep"></div>',i+='<div class="ctx-item" data-action="openNote" data-id="'+d+'" data-type="note">'+T("ctxOpenNote")+"</div>",i+='<div class="ctx-item" data-action="openInNewWindow" data-id="'+d+'" data-type="note">'+T("ctxOpenInNewWindow")+"</div>",i+='<div class="ctx-sep"></div>',i+='<div class="ctx-item" data-action="setTags" data-id="'+d+'" data-type="note">'+T("ctxSetTags")+"</div>",i+='<div class="ctx-item" data-action="switchNoteType" data-id="'+d+'" data-type="note">'+T("ctxSwitchNoteType")+"</div>","1"===a.dataset.todo&&(i+='<div class="ctx-item" data-action="toggleTodo" data-id="'+d+'" data-type="note">'+T("ctxToggleTodo")+"</div>"),i+='<div class="ctx-item" data-action="moveToFolderDialog" data-id="'+d+'" data-type="note">'+T("ctxMoveToFolder")+"</div>",i+='<div class="ctx-item" data-action="duplicateNote" data-id="'+d+'" data-type="note">'+T("ctxDuplicateNote")+"</div>",i+='<div class="ctx-sep"></div>',i+='<div class="ctx-item" data-action="copyLink" data-id="'+d+'" data-type="note">'+T("ctxCopyLink")+"</div>",i+='<div class="ctx-item" data-action="copyExternalLink" data-id="'+d+'" data-type="note">'+T("ctxCopyExternalLink")+"</div>",i+='<div class="ctx-sep"></div>',i+='<div class="ctx-item" data-action="publishNote" data-id="'+d+'" data-type="note">'+T("ctxPublishNote")+"</div>",i+='<div class="ctx-item ctx-drill">'+T("ctxExport")+'<span class="ctx-sub-arrow">▸</span></div>',i+='<div class="ctx-export-template" style="display:none" data-title="'+T("ctxExport")+'"><div class="ctx-item" data-action="exportPdf" data-id="'+d+'" data-type="note">PDF</div><div class="ctx-item" data-action="exportNote" data-format="md" data-id="'+d+'" data-type="note">Markdown</div><div class="ctx-item" data-action="exportNote" data-format="md_frontmatter" data-id="'+d+'" data-type="note">Markdown + Front Matter</div><div class="ctx-item" data-action="exportNote" data-format="jex" data-id="'+d+'" data-type="note">JEX</div><div class="ctx-item" data-action="exportNote" data-format="html" data-id="'+d+'" data-type="note">HTML</div></div>',i+='<div class="ctx-sep"></div>',i+='<div class="ctx-item" data-action="renameNote" data-id="'+d+'" data-type="note" data-title="'+s.replace(/"/g,""")+'">'+T("ctxRenameNote")+"</div>",i+='<div class="ctx-item" data-action="noteInfo" data-id="'+d+'" data-type="note">'+T("ctxNoteInfo")+"</div>",i+='<div class="ctx-sep"></div>',i+='<div class="ctx-item ctx-danger" data-action="deleteNote" data-id="'+d+'" data-type="note">'+T("ctxDeleteNote")+"</div>",a.dataset.tagId&&(i+='<div class="ctx-sep"></div>',i+='<div class="ctx-item" data-action="untagNote" data-id="'+d+'" data-type="note" data-tag-id="'+a.dataset.tagId+'">'+T("ctxUntagNote")+"</div>")}else if("tag"===n){var v=a.dataset.tagId;i+='<div class="ctx-item" data-action="renameTag" data-id="'+v+'" data-type="tag">'+T("ctxRenameTag")+"</div>",i+='<div class="ctx-sep"></div>',i+='<div class="ctx-item ctx-danger" data-action="deleteTag" data-id="'+v+'" data-type="tag">'+T("ctxDeleteTag")+"</div>"}i+="</div>",document.body.insertAdjacentHTML("beforeend",i);var p=document.getElementById("ctx-menu"),m=p.getBoundingClientRect();m.right>window.innerWidth&&(p.style.left=window.innerWidth-m.width-4+"px"),m.bottom>window.innerHeight&&(p.style.top=window.innerHeight-m.height-4+"px")}}),document.addEventListener("mousedown",function(e){if(!e.target.closest("#ctx-menu")){var t=document.getElementById("ctx-menu");t&&t.remove()}}),webviewApi.onMessage(function(e){if(e&&e.message){var t=e.message;if("syncState"===t.name){var a=document.getElementById("btn-sync");if(!a)return;"syncing"===t.state?(a.disabled=!0,a.classList.remove("sync-done","sync-error"),a.classList.add("syncing"),a.textContent="🔄 "+T("syncing")):"done"===t.state?(a.classList.remove("syncing","sync-error"),a.classList.add("sync-done"),a.textContent=T("syncDone"),setTimeout(function(){var e=document.getElementById("btn-sync");e&&(e.disabled=!1,e.classList.remove("sync-done"),e.textContent="🔄 "+T("sync"))},2e3)):"error"===t.state&&(a.classList.remove("syncing","sync-done"),a.classList.add("sync-error"),a.textContent=T("syncFailed"),setTimeout(function(){var e=document.getElementById("btn-sync");e&&(e.disabled=!1,e.classList.remove("sync-error"),e.textContent="🔄 "+T("sync"))},4e3))}else if("searchResults"===t.name){if(void 0!==t.searchId&&t.searchId!==_searchId)return;t.notes||t.tags||t.folders?renderSearchResults(t.notes||[],t.tags||[],t.folders||[],t.query):_searchMode&&exitSearchMode()}else if("tagFolderNotes"===t.name){var n=document.querySelector('.tag-children[data-tag-id="'+t.tagId+'"]');if(n){n.dataset.loaded="1";for(var d="",s=0;s<t.notes.length;s++){var o=t.notes[s],i=o.is_todo?o.todo_completed?"☑":"☐":"📝";d+='<div class="tree-item note tag-note" data-id="'+o.id+'" data-type="note" data-tag-id="'+t.tagId+'" data-todo="'+(o.is_todo?1:0)+'"><span class="icon note-icon">'+i+'</span><span class="label">'+escapeHtml(o.title)+"</span></div>"}t.notes.length||(d='<div class="tag-empty">—</div>'),n.innerHTML=d}}else if("trashNotes"===t.name){var r=document.getElementById("trash-children");if(r){r.dataset.loaded="1";for(var l="",c=t.folders||[],v=0;v<c.length;v++){var p=c[v],m=p.depth||0;l+='<div class="tree-item folder trash-note" style="padding-left:'+(34+16*m)+'px" data-id="'+p.id+'" data-type="folder" data-trash="1" data-depth="'+m+'"><span class="toggle">'+(p.hasNotes?"▶":"")+'</span><span class="icon">📁</span><span class="label">'+escapeHtml(p.title)+"</span></div>",p.hasNotes&&(l+='<div class="trash-folder-children collapsed" data-folder-id="'+p.id+'" data-depth="'+m+'"></div>')}for(var g=t.notes||[],u=0;u<g.length;u++){var f=g[u],h=f.is_todo?f.todo_completed?"☑":"☐":"📝";l+='<div class="tree-item note trash-note" style="padding-left:34px" data-id="'+f.id+'" data-type="note" data-trash="1"><span class="icon note-icon">'+h+'</span><span class="label">'+escapeHtml(f.title)+"</span></div>"}l||(l='<div class="tag-empty">—</div>'),r.innerHTML=l}}else if("smartFolderNotes"===t.name){var y=document.querySelector('.smart-children[data-smart-id="'+t.smartId+'"]');if(y){for(var x="",L=0;L<t.notes.length;L++){var I=t.notes[L],E=I.is_todo?I.todo_completed?"☑":"☐":"📝";x+='<div class="tree-item note smart-note" style="padding-left:44px" data-id="'+I.id+'" data-type="note" data-todo="'+(I.is_todo?1:0)+'"><span class="icon note-icon">'+E+'</span><span class="label">'+escapeHtml(I.title)+"</span></div>"}t.notes.length||(x='<div class="tag-empty">—</div>'),y.innerHTML=x}}else if("notePreview"===t.name)showPreview(t);else if("trashFolderNotes"===t.name){var S=document.querySelector('.trash-folder-children[data-folder-id="'+t.folderId+'"]');if(S){S.dataset.loaded="1";for(var b=34+16*(parseInt(S.dataset.depth||"0",10)+1),w="",M=0;M<t.notes.length;M++){var N=t.notes[M],_=N.is_todo?N.todo_completed?"☑":"☐":"📝";w+='<div class="tree-item note trash-note" style="padding-left:'+b+'px" data-id="'+N.id+'" data-type="note" data-trash="1"><span class="icon note-icon">'+_+'</span><span class="label">'+escapeHtml(N.title)+"</span></div>"}t.notes.length||(w='<div class="tag-empty" style="padding-left:'+b+'px">—</div>'),S.innerHTML=w}}else if("tagNotes"===t.name)expandTagNotes(t.tagId,t.notes);else if("scrollToFolder"===t.name)setTimeout(function(){var e=document.querySelector('.tree-item.folder:not(.pinned-item)[data-id="'+t.folderId+'"]');e&&(expandAncestorsLocal(e),e.scrollIntoView({block:"center",behavior:"smooth"}),e.classList.add("locate-flash"),setTimeout(function(){e.classList.remove("locate-flash")},1500))},80);else if("exitSearch"===t.name){var q=document.getElementById("search-input");q&&(q.value=""),_searchMode&&exitSearchMode()}else if("exitSearchAndLocate"===t.name){var C=document.getElementById("search-input");C&&(C.value=""),_searchMode=!1,showSearchContainer(!1),setTimeout(function(){var e=document.querySelector('.tree-item.folder[data-id="'+t.folderId+'"]');e&&(expandAncestorsLocal(e),e.scrollIntoView({block:"center",behavior:"smooth"}),e.classList.add("locate-flash"),setTimeout(function(){e.classList.remove("locate-flash")},1500))},80)}else if("copyText"===t.name)if(navigator.clipboard&&navigator.clipboard.writeText)navigator.clipboard.writeText(t.text);else{var B=document.createElement("textarea");B.value=t.text,document.body.appendChild(B),B.select(),document.execCommand("copy"),B.remove()}else if("selectNote"===t.name){document.querySelectorAll(".tree-item.note.selected").forEach(function(e){e.classList.remove("selected")});var D=document.querySelector('.tree-item.note[data-id="'+t.id+'"]');D&&(D.classList.add("selected"),D.scrollIntoView({block:"nearest",behavior:"instant"}))}else"updateNote"===t.name&&document.querySelectorAll('.tree-item.note[data-id="'+t.id+'"]').forEach(function(e){var a=e.querySelector(".label");a&&(a.textContent=t.title);var n=e.querySelector(".search-result-title");n&&(n.textContent=t.title);var d=e.querySelector(".note-icon");d&&(d.textContent=t.icon)})}}),document.addEventListener("mousedown",function(e){var t=e.target.closest(".tree-item");t&&0===e.button&&t.setAttribute("draggable","true")}),document.addEventListener("dragstart",function(e){var t=e.target.closest(".tree-item");if(t)if(t.closest(".trash-children")||t.closest(".smart-section-body")||t.classList.contains("tag-folder"))e.preventDefault();else{var a=t.classList.contains("pinned-item");if(e.dataTransfer.setData("text/plain",JSON.stringify({id:t.dataset.id,type:t.dataset.type,pinned:a})),e.dataTransfer.effectAllowed="move",t.classList.add("dragging"),!a){var n=document.getElementById("tree-container");n&&n.classList.add("dragging-active")}}});var _dragScrollDir=0,_dragScrollRaf=null;function dragScrollStep(){var e=document.getElementById("tree-container");e&&_dragScrollDir?(e.scrollTop+=_dragScrollDir,_dragScrollRaf=requestAnimationFrame(dragScrollStep)):_dragScrollRaf=null}function updateDragScroll(e){var t=document.getElementById("tree-container");if(t){var a=t.getBoundingClientRect(),n=a.bottom,d=document.getElementById("drop-zone-empty");if(d&&t.classList.contains("dragging-active")){var s=d.getBoundingClientRect();s.height>0&&s.top>a.top&&(n=s.top)}var o=0;e<a.top+40?o=-Math.ceil((a.top+40-e)/4):e>n?o=0:e>n-40&&(o=Math.ceil((e-(n-40))/4)),_dragScrollDir=o,o&&!_dragScrollRaf&&(_dragScrollRaf=requestAnimationFrame(dragScrollStep))}else _dragScrollDir=0}function clearDropIndicators(){document.querySelectorAll(".drop-target").forEach(function(e){e.classList.remove("drop-target")}),document.querySelectorAll(".drop-above").forEach(function(e){e.classList.remove("drop-above")}),document.querySelectorAll(".drop-below").forEach(function(e){e.classList.remove("drop-below")})}function endDrag(){_dragScrollDir=0,clearDropIndicators();var e=document.getElementById("tree-container");e&&e.classList.remove("dragging-active")}document.addEventListener("dragend",function(e){var t=e.target.closest(".tree-item");t&&(t.classList.remove("dragging"),t.removeAttribute("draggable")),endDrag()}),document.addEventListener("dragover",function(e){document.querySelector(".tree-item.dragging")&&updateDragScroll(e.clientY);var t=e.target;if(t&&3===t.nodeType&&(t=t.parentElement),t){var a=t.closest(".tree-item");if(document.getElementById("tree-container"),t.closest("#drop-zone-empty"))document.querySelector(".tree-item.dragging.pinned-item")||(e.preventDefault(),e.dataTransfer.dropEffect="move");else{if(t.closest(".pinned-section-header"))return e.preventDefault(),e.dataTransfer.dropEffect="move",void clearDropIndicators();if(t.closest(".pinned-section-body")){if(document.querySelector(".tree-item.dragging.pinned-item")&&a&&a.classList.contains("pinned-item")){e.preventDefault(),e.dataTransfer.dropEffect="move",clearDropIndicators();var n=a.getBoundingClientRect();e.clientY-n.top<.5*n.height?a.classList.add("drop-above"):a.classList.add("drop-below")}}else{var d=t.closest(".tag-folder");if(d)document.querySelector(".tree-item.note.dragging")&&(e.preventDefault(),e.dataTransfer.dropEffect="move",clearDropIndicators(),d.classList.add("drop-target"));else if(!(t.closest(".tags-section-body")||t.closest(".tags-section-header")||t.closest(".trash-children")||t.closest(".trash-section-header")||t.closest(".smart-section-body")||t.closest(".smart-section-header"))&&a){var s=document.querySelector(".tree-item.dragging");if(!s||!s.classList.contains("pinned-item")){e.preventDefault(),e.dataTransfer.dropEffect="move",clearDropIndicators();var o=a.dataset.type,i=a.getBoundingClientRect(),r=e.clientY-i.top,l=i.height;"folder"===o?r<.25*l?a.classList.add("drop-above"):r>.75*l?a.classList.add("drop-below"):a.classList.add("drop-target"):"manual"===currentSortMode()?r<.5*l?a.classList.add("drop-above"):a.classList.add("drop-below"):a.classList.add("drop-target")}}}}}}),document.addEventListener("dragleave",function(e){var t=e.target.closest(".tree-item");t&&(t.classList.remove("drop-target"),t.classList.remove("drop-above"),t.classList.remove("drop-below"));var a=document.getElementById("tree-container");a&&e.target===a&&a.classList.remove("drop-empty")}),document.addEventListener("drop",function(e){e.preventDefault();var t=e.target;t&&3===t.nodeType&&(t=t.parentElement);var a,n=t?t.closest(".tree-item"):null;document.getElementById("tree-container");try{a=JSON.parse(e.dataTransfer.getData("text/plain"))}catch(e){return void endDrag()}var d=a.id,s=a.type,o=a.pinned;if(t&&t.closest("#drop-zone-empty")&&!o)return postMsg({name:"dragToEmpty",dragId:d,dragType:s}),void endDrag();if(t&&t.closest(".pinned-section-header")&&!o)return"note"===s?postMsg({name:"contextMenu",action:"pinNote",id:d,itemType:"note"}):"folder"===s&&postMsg({name:"contextMenu",action:"pinFolder",id:d,itemType:"folder"}),void endDrag();if(t&&t.closest(".pinned-section-body")&&o){var i=n&&n.classList.contains("pinned-item")?n:null;if(i&&i.dataset.id!==d){var r=i.getBoundingClientRect(),l=e.clientY-r.top<.5*r.height?"before":"after";postMsg({name:"reorderPinned",dragId:d,dragType:s,targetId:i.dataset.id,position:l})}endDrag()}else{var c=t?t.closest(".tag-folder"):null;if(c)return"note"===s&&postMsg({name:"tagNoteAdd",tagId:c.dataset.tagId,noteId:d}),void endDrag();if(t&&(t.closest(".tags-section-body")||t.closest(".tags-section-header")||t.closest(".trash-children")||t.closest(".trash-section-header")||t.closest(".smart-section-body")||t.closest(".smart-section-header")))endDrag();else if(o)endDrag();else if(n){var v=n.dataset.id,p=n.dataset.type;if(d!==v){var m=n.getBoundingClientRect(),g=e.clientY-m.top,u=m.height;postMsg("folder"===p?g>=.25*u&&g<=.75*u?{name:"dragDrop",dragId:d,dragType:s,targetId:v,position:"into"}:{name:"dragDrop",dragId:d,dragType:s,targetId:v,position:g<.25*u?"above":"below"}:"note"===s?{name:"dragDrop",dragId:d,dragType:s,targetId:v,position:g<.5*u?"above":"below"}:{name:"dragDrop",dragId:d,dragType:s,targetId:v,position:"into"}),endDrag()}else endDrag()}else endDrag()}});var _searchTimer=null,_searchMode=!1,_searchId=0;function escapeRegex(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function escapeHtml(e){return String(null==e?"":e).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}function highlightText(e,t){var a=escapeHtml(e);if(!t)return a;var n=new RegExp("("+escapeRegex(t)+")","gi");return a.replace(n,'<mark class="search-highlight">$1</mark>')}function showSearchContainer(e){var t=document.getElementById("tree-container"),a=document.getElementById("search-results");t&&(t.style.display=e?"none":""),a&&(a.style.display=e?"":"none")}function renderNoteItem(e,t){var a="📝";e.is_todo&&(a=e.todo_completed?"☑":"☐");var n='<div class="search-result-item tree-item note" data-id="'+e.id+'" data-type="note" data-todo="'+(e.is_todo?1:0)+'">';return n+='<span class="icon note-icon">'+a+"</span>",n+='<div class="search-result-content">',n+='<div class="search-result-title">'+highlightText(e.title,t)+"</div>",e.folderName&&(n+='<div class="search-result-folder">📂 '+escapeHtml(e.folderName)+"</div>"),e.snippet&&(n+='<div class="search-result-snippet">'+highlightText(e.snippet,t)+"</div>"),n+"</div></div>"}function renderSearchResults(e,t,a,n){var d=document.getElementById("search-results");if(d){showSearchContainer(!0);var s=e.length+t.length+a.length;if(0!==s){var o='<div class="search-status">'+T("searchResultCount").replace("{count}",s)+"</div>";if(a.length>0){o+=g("📁",T("searchSectionFolders"),a.length,"folders"),o+='<div class="search-section-body" id="search-section-folders">';for(var i=0;i<a.length;i++){var r=a[i],l=r.iconEmoji||"📁";o+='<div class="search-result-item search-folder-item" data-folder-id="'+r.id+'">',o+='<span class="icon">'+l+"</span>",o+='<div class="search-result-content">',o+='<div class="search-result-title">'+highlightText(r.title,n)+"</div>",o+="</div></div>"}o+="</div>"}if(e.length>0){o+=g("📝",T("searchSectionNotes"),e.length,"notes"),o+='<div class="search-section-body" id="search-section-notes">';for(var c=0;c<e.length;c++)o+=renderNoteItem(e[c],n);o+="</div>"}if(t.length>0){o+=g("🏷️",T("searchSectionTags"),t.length,"tags"),o+='<div class="search-section-body" id="search-section-tags">';for(var v=0;v<t.length;v++){var p=t[v],m=T("searchTagNoteCount").replace("{count}",p.noteCount);o+='<div class="search-result-item search-tag-item" data-tag-id="'+p.id+'">',o+='<span class="icon">🏷️</span>',o+='<div class="search-result-content">',o+='<div class="search-result-title">'+highlightText(p.title,n)+"</div>",o+='<div class="search-result-folder">'+m+"</div>",o+="</div>",o+='<span class="tag-expand-arrow">▶</span>',o+="</div>",o+='<div class="tag-notes-container" id="tag-notes-'+p.id+'"></div>'}o+="</div>"}d.innerHTML=o,_searchMode=!0}else d.innerHTML='<div class="search-status">'+T("searchNoResult")+"</div>"}function g(e,t,a,n){return'<div class="search-section-header" data-section="'+n+'"><span class="section-toggle">▼</span> '+e+" "+t+" ("+a+")</div>"}}function expandTagNotes(e,t){var a=document.getElementById("tag-notes-"+e);if(a){var n;if(a.children.length>0)return a.innerHTML="",void((n=document.querySelector('.search-tag-item[data-tag-id="'+e+'"] .tag-expand-arrow'))&&n.classList.remove("expanded"));for(var d="",s=0;s<t.length;s++)d+=renderNoteItem(t[s],"");0===t.length&&(d='<div class="search-status" style="padding-left:30px;">'+T("searchNoResult")+"</div>"),a.innerHTML=d,(n=document.querySelector('.search-tag-item[data-tag-id="'+e+'"] .tag-expand-arrow'))&&n.classList.add("expanded")}}function exitSearchMode(){_searchMode=!1,showSearchContainer(!1)}document.addEventListener("input",function(e){if("search-input"===e.target.id){var t=e.target.value.trim();_searchTimer&&clearTimeout(_searchTimer);var a=++_searchId;if(t){_searchMode=!0;var n=document.getElementById("search-results");n&&(n.innerHTML='<div class="search-status">'+T("searching")+"</div>"),showSearchContainer(!0),_searchTimer=setTimeout(function(){postMsg({name:"search",query:t,searchId:a})},400)}else _searchMode&&exitSearchMode()}}),document.addEventListener("keydown",function(e){if("Escape"===e.key){var t=document.getElementById("search-input");t&&t.value&&(t.value="",_searchMode&&exitSearchMode())}});
|