joplin-plugin-explorer 1.2.1 → 1.2.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/README.md +1 -1
- 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 +3 -3
- package/publish/webview/panel.js +1 -1
package/README.md
CHANGED
|
@@ -19,7 +19,7 @@ A unified sidebar plugin for [Joplin](https://joplinapp.org/) that displays note
|
|
|
19
19
|
- **Auto Expand** — Automatically expands to the currently selected note on startup
|
|
20
20
|
- **Collapse All** — One-click collapse all notebooks
|
|
21
21
|
- **Scroll Position** — Preserved when navigating between notes
|
|
22
|
-
- **i18n** — Supports Simplified Chinese, Traditional Chinese,
|
|
22
|
+
- **i18n** — Supports English, Simplified Chinese, Traditional Chinese, Japanese, and Russian (follows Joplin's locale setting)
|
|
23
23
|
|
|
24
24
|
## Install
|
|
25
25
|
|
package/package.json
CHANGED
package/publish/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(()=>{"use strict";const e={zh_CN:{newNotebook:"新建笔记本",newNote:"新建笔记",newTodo:"新建待办",sort:"排序",collapseAll:"全部折叠",expandAll:"全部展开",search:"搜索笔记内容...",searchResultCount:"找到 {count} 条结果",searchNoResult:"没有找到匹配的笔记",searching:"搜索中...",sync:"同步",syncing:"同步中...",syncDone:"✔ 同步完成",loading:"加载中...",sortUpdatedDesc:"↓ 修改时间",sortUpdatedAsc:"↑ 修改时间",sortTitleAsc:"↑ 标题",sortTitleDesc:"↓ 标题",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:"收藏夹",ctxPin:"📌 收藏",ctxUnpin:"取消收藏",cancel:"取消"},zh_TW:{newNotebook:"新建筆記本",newNote:"新建筆記",newTodo:"新建待辦",sort:"排序",collapseAll:"全部摺疊",expandAll:"全部展開",search:"搜尋筆記內容...",searchResultCount:"找到 {count} 條結果",searchNoResult:"沒有找到匹配的筆記",searching:"搜尋中...",sync:"同步",syncing:"同步中...",syncDone:"✔ 同步完成",loading:"載入中...",sortUpdatedDesc:"↓ 修改時間",sortUpdatedAsc:"↑ 修改時間",sortTitleAsc:"↑ 標題",sortTitleDesc:"↓ 標題",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:"收藏夾",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",loading:"Loading...",sortUpdatedDesc:"↓ Updated",sortUpdatedAsc:"↑ Updated",sortTitleAsc:"↑ Title",sortTitleDesc:"↓ Title",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",ctxPin:"📌 Pin",ctxUnpin:"Unpin",cancel:"Cancel"},ja_JP:{newNotebook:"新規ノートブック",newNote:"新規ノート",newTodo:"新規タスク",sort:"並べ替え",collapseAll:"すべて折りたたむ",expandAll:"すべて展開",search:"ノート内容を検索...",searchResultCount:"{count} 件の結果",searchNoResult:"一致するノートが見つかりません",searching:"検索中...",sync:"同期",syncing:"同期中...",syncDone:"✔ 同期完了",loading:"読み込み中...",sortUpdatedDesc:"↓ 更新日時",sortUpdatedAsc:"↑ 更新日時",sortTitleAsc:"↑ タイトル",sortTitleDesc:"↓ タイトル",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:"ピン留め",ctxPin:"📌 ピン留め",ctxUnpin:"ピン解除",cancel:"キャンセル"}};function t(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}async function o(){let e=[],t=1,o=!0;for(;o;){const i=await joplin.data.get(["folders"],{fields:["id","title","parent_id","icon"],page:t,limit:100});e=e.concat(i.items),o=i.has_more,t++}return e}async function i(e){let t=[],o=1,i=!0;for(;i;){const n=await joplin.data.get(["folders",e,"notes"],{fields:["id","title","parent_id","is_todo","todo_completed","updated_time","user_updated_time"],page:o,limit:100,order_by:"user_updated_time",order_dir:"DESC"});t=t.concat(n.items),i=n.has_more,o++}return t}function n(e){let t=e.icon;if(t&&"string"==typeof t)try{t=JSON.parse(t)}catch(e){t=null}return t&&t.emoji?t.emoji:"📂"}function a(e,o,i,s=0){let l="";for(const d of e){const e=18*s;if("folder"===d.type){const r=d.total_count||d.note_count||0,c=i[d.id],p=c?"▶":"▼",w=c?"toggle":"toggle expanded";l+='<div class="tree-item folder" style="padding-left:'+e+'px" data-id="'+d.id+'" data-type="folder">',l+='<span class="'+w+'">'+p+"</span>",l+='<span class="icon folder-icon">'+n(d)+"</span>",l+='<span class="label">'+t(d.title)+"</span>",l+='<span class="count">'+r+"</span>",l+="</div>",l+='<div class="children'+(c?" collapsed":"")+'" data-folder-id="'+d.id+'">',d.children&&(l+=a(d.children,o,i,s+1)),l+="</div>"}else{const i=d.id===o?" selected":"";let n="📝";d.is_todo&&(n=d.todo_completed?"☑":"☐"),l+='<div class="tree-item note'+i+'" style="padding-left:'+e+'px" data-id="'+d.id+'" data-type="note">',l+='<span class="icon note-icon">'+n+"</span>",l+='<span class="label">'+t(d.title)+"</span>",l+="</div>"}}return l}function s(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;default:o.sort((e,t)=>(t.user_updated_time||0)-(e.user_updated_time||0))}return o}joplin.plugins.register({onStart:async function(){const l=(r=await joplin.settings.globalValue("locale")||"en_US",e[r]||e[r.split("_")[0]]||e.en_US),d=await joplin.views.panels.create("notesInListPanel");var r;await joplin.views.panels.addScript(d,"webview/panel.css"),await joplin.views.panels.addScript(d,"webview/panel.js"),await joplin.views.panels.setHtml(d,'<div id="notes-in-list-root"><p style="padding:12px;">'+l.loading+"</p></div>"),await joplin.views.panels.show(d,!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)"}})}catch(e){console.error("Joplin Explorer: failed to register settings",e)}const c=await joplin.views.dialogs.create("explorerInputDialog"),p=await joplin.views.dialogs.create("explorerConfirmDialog"),w=await joplin.views.dialogs.create("explorerInfoDialog");async function f(e){return await joplin.views.dialogs.setHtml(p,'<div style="padding:10px;min-width:280px;"><div style="font-size:13px;">'+t(e)+"</div></div>"),await joplin.views.dialogs.setButtons(p,[{id:"ok",title:"OK"},{id:"cancel",title:l.cancel||"Cancel"}]),"ok"===(await joplin.views.dialogs.open(p)).id}async function m(e,o){await joplin.views.dialogs.setHtml(c,'<div style="padding:10px;min-width:300px;"><div style="margin-bottom:8px;font-size:13px;">'+t(e)+'</div><form name="inputForm"><input name="value" type="text" value="'+t(o||"")+'" style="width:100%;box-sizing:border-box;padding:6px 8px;font-size:13px;" /></form></div>'),await joplin.views.dialogs.setButtons(c,[{id:"ok",title:"OK"},{id:"cancel",title:l.cancel||"Cancel"}]);const i=await joplin.views.dialogs.open(c);return"ok"===i.id&&i.formData&&i.formData.inputForm&&i.formData.inputForm.value||null}let u="",g={},N="updated_desc",h=[],x=[],y=[],_=!1,b=!0;async function j(){try{await joplin.settings.setValue("pinnedItems",JSON.stringify(y))}catch(e){console.error("Joplin Explorer: failed to save pinned items",e)}}function v(e){let t=e;for(;t;){delete g[t];let e=null;for(const o of h)if(o.id===t){e=o;break}t=e?e.parent_id:null}}async function k(){try{const e=await o();if(h=e,b){for(const t of e)g[t.id]=!0;const t=await joplin.workspace.selectedNote();if(t){u=t.id;let o=t.parent_id;for(;o;){delete g[o];let t=null;for(const i of e)if(i.id===o){t=i;break}o=t?t.parent_id:null}}b=!1}const r={},c=10;for(let t=0;t<e.length;t+=c){const o=e.slice(t,t+c),n=await Promise.all(o.map(e=>i(e.id)));for(let e=0;e<o.length;e++)r[o[e].id]=s(n[e],N)}const p=[];for(const e of Object.keys(r))for(const t of r[e])p.push(t);x=p;const w=function(e,t){const o={};for(const t of e)o[t.id]={type:"folder",id:t.id,title:t.title,parent_id:t.parent_id,icon:t.icon,note_count:0,children:[]};for(const e of Object.keys(t)){const i=o[e];if(i){const o=t[e];i.note_count=o.length;for(const e of o)i.children.push({type:"note",id:e.id,title:e.title||"(untitled)",is_todo:e.is_todo,todo_completed:e.todo_completed})}}const i=[];for(const t of e){const e=o[t.id];t.parent_id&&o[t.parent_id]?o[t.parent_id].children.unshift(e):i.push(e)}function n(e){let t=0;if(!e.children)return 0;for(const o of e.children)"note"===o.type?t++:"folder"===o.type&&(n(o),t+=o.total_count||0);return e.total_count=t,t}for(const e of i)n(e);return i}(e,r),f=a(w,u,g);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){y=[];for(const e of t.folders)y.push({id:e,type:"folder"});for(const e of t.notes)y.push({id:e,type:"note"});await j()}else Array.isArray(t)&&(y=t)}catch(e){y=[]}}();const m=new Set(e.map(e=>e.id)),v=new Set(p.map(e=>e.id)),k=y.length;y=y.filter(e=>"folder"===e.type?m.has(e.id):v.has(e.id)),y.length!==k&&await j();let T="";const D=y.length;if(D>0){T+='<div class="pinned-section-header" id="pinned-header"><span class="toggle">'+(_?"▶":"▼")+'</span><span class="icon">📌</span><span class="label">'+l.pinned+" ("+D+")</span></div>",T+='<div class="pinned-section-body'+(_?" collapsed":"")+'" id="pinned-body">';for(const o of y)if("folder"===o.type){let i=null;for(const t of e)if(t.id===o.id){i=t;break}if(i){const e=n(i);T+='<div class="tree-item folder pinned-item" data-id="'+i.id+'" data-type="folder">',T+='<span class="icon folder-icon">'+e+"</span>",T+='<span class="label">'+t(i.title)+"</span>",T+="</div>"}}else{let e=null;for(const t of p)if(t.id===o.id){e=t;break}if(e){const o=e.id===u?" selected":"";let i="📝";e.is_todo&&(i=e.todo_completed?"☑":"☐"),T+='<div class="tree-item note pinned-item'+o+'" data-id="'+e.id+'" data-type="note">',T+='<span class="icon note-icon">'+i+"</span>",T+='<span class="label">'+t(e.title)+"</span>",T+="</div>"}}T+="</div>"}const S=t(JSON.stringify(y)),I={updated_desc:l.sortUpdatedDesc,updated_asc:l.sortUpdatedAsc,title_asc:l.sortTitleAsc,title_desc:l.sortTitleDesc},F='<div id="notes-in-list-root" data-i18n="'+t(JSON.stringify(l))+'" data-pinned="'+S+'"> <div class="toolbar"> <button id="btn-new-notebook" title="'+l.newNotebook+'">📁+</button> <button id="btn-new-note" title="'+l.newNote+'">📝+</button> <button id="btn-new-todo" title="'+l.newTodo+'">☐+</button> <button id="btn-sort" title="'+l.sort+'">'+I[N]+'</button> <button id="btn-collapse-all" title="'+l.collapseAll+'">▲</button> </div> <div class="search-bar"> <input id="search-input" type="text" placeholder="🔍 '+l.search+'" /> </div> <div id="tree-container">'+T+f+' <div id="drop-zone-empty" class="drop-zone-empty">+ '+l.dropCreateNotebook+'</div> </div> <div id="search-results" style="display:none;"></div> <div class="bottom-bar"> <button id="btn-sync" title="'+l.sync+'">🔄 '+l.sync+"</button> </div></div>";await joplin.views.panels.setHtml(d,F)}catch(e){console.error("Notes In List: refresh error",e),await joplin.views.panels.setHtml(d,'<div style="padding:12px;color:red;">Error: '+t(String(e))+"</div>")}}await joplin.views.panels.onMessage(d,async e=>{if("openNote"===e.name)u=e.id,await joplin.commands.execute("openNote",e.id);else if("refresh"===e.name)await k();else if("toggleFolder"===e.name)g[e.id]?delete g[e.id]:g[e.id]=!0,await k();else if("collapseAll"===e.name){const e=await o();for(const t of e)g[t.id]=!0;await k()}else if("expandAll"===e.name)g={},await k();else if("newNotebook"===e.name)await joplin.commands.execute("newFolder"),await k();else if("newNote"===e.name){await joplin.commands.execute("newNote");const e=await joplin.workspace.selectedNote();e&&(u=e.id,v(e.parent_id)),await k()}else if("newTodo"===e.name){await joplin.commands.execute("newTodo");const e=await joplin.workspace.selectedNote();e&&(u=e.id,v(e.parent_id)),await k()}else if("search"===e.name){const t=e.query;if(!t||!t.trim())return void await joplin.views.panels.postMessage(d,{name:"searchResults",results:null,query:"",searchId:e.searchId});try{const o=t.toLowerCase(),i={};for(const e of h)i[e.id]=e.title;let n=[],a=1,s=!0;for(;s&&n.length<100;){const e=await joplin.data.get(["search"],{query:t,fields:["id","title","body","parent_id","is_todo","todo_completed"],page:a,limit:20});n=n.concat(e.items),s=e.has_more,a++}const l=new Set(n.map(e=>e.id)),r=[];for(const e of x)!l.has(e.id)&&(e.title||"").toLowerCase().indexOf(o)>=0&&r.push(e);for(let e=0;e<r.length&&e<50;e++)try{const t=await joplin.data.get(["notes",r[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 n=e.body||"",a=n.toLowerCase().indexOf(o);if(a>=0){const e=Math.max(0,a-40),i=Math.min(n.length,a+o.length+80);t=(e>0?"...":"")+n.substring(e,i).replace(/\n/g," ")+(i<n.length?"...":"")}else t=n.substring(0,120).replace(/\n/g," ")+(n.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=[],w=1,f=!0;for(;f;){const e=await joplin.data.get(["tags"],{fields:["id","title"],page:w,limit:100});p=p.concat(e.items),f=e.has_more,w++}const m=[];for(const e of p)if((e.title||"").toLowerCase().indexOf(o)>=0){let t=0;try{const o=await joplin.data.get(["tags",e.id,"notes"],{fields:["id"],limit:1});if(t=o.items.length+(o.has_more?"+":0),o.has_more){let i=o.items.length,n=2,a=!0;for(;a;){const t=await joplin.data.get(["tags",e.id,"notes"],{fields:["id"],page:n,limit:100});i+=t.items.length,a=t.has_more,n++}t=i}}catch(e){}m.push({id:e.id,title:e.title,noteCount:t})}const u=[];for(const e of h)(e.title||"").toLowerCase().indexOf(o)>=0&&u.push({id:e.id,title:e.title,parent_id:e.parent_id,icon:e.icon});await joplin.views.panels.postMessage(d,{name:"searchResults",notes:c,tags:m,folders:u,query:t,searchId:e.searchId})}catch(e){console.error("Joplin Explorer: search error",e)}}else if("loadTagNotes"===e.name)try{const t=e.tagId;let o=[],i=1,n=!0;for(;n&&o.length<100;){const e=await joplin.data.get(["tags",t,"notes"],{fields:["id","title","parent_id","is_todo","todo_completed"],page:i,limit:50});o=o.concat(e.items),n=e.has_more,i++}const a={};for(const e of h)a[e.id]=e.title;const s=o.map(e=>({id:e.id,title:e.title||"(untitled)",is_todo:e.is_todo,todo_completed:e.todo_completed,snippet:"",folderName:a[e.parent_id]||""}));await joplin.views.panels.postMessage(d,{name:"tagNotes",tagId:t,notes:s})}catch(e){console.error("Joplin Explorer: loadTagNotes error",e)}else if("locateFolder"===e.name)try{v(e.folderId),await k(),await joplin.views.panels.postMessage(d,{name:"exitSearchAndLocate",folderId:e.folderId})}catch(e){console.error("Joplin Explorer: locateFolder error",e)}else if("locatePinnedFolder"===e.name)try{v(e.folderId),await k(),await joplin.views.panels.postMessage(d,{name:"scrollToFolder",folderId:e.folderId})}catch(e){console.error("Joplin Explorer: locatePinnedFolder error",e)}else if("reorderPinned"===e.name)try{const t=e.dragId,o=e.targetId,i=e.position,n=y.findIndex(e=>e.id===t);if(n<0)return;const a=y[n];y.splice(n,1);let s=y.findIndex(e=>e.id===o);s<0?y.push(a):("after"===i&&s++,y.splice(s,0,a)),await j(),await k()}catch(e){console.error("Joplin Explorer: reorderPinned error",e)}else if("togglePinnedCollapse"===e.name)_=!_,await k();else if("cycleSort"===e.name){const e=["updated_desc","updated_asc","title_asc","title_desc"],t=e.indexOf(N);N=e[(t+1)%e.length],await k()}else if("sync"===e.name){await joplin.views.panels.postMessage(d,{name:"syncState",state:"syncing"});try{await joplin.commands.execute("synchronize")}catch(e){console.error("Joplin Explorer: sync error",e)}await new Promise(e=>setTimeout(e,3e3)),await joplin.views.panels.postMessage(d,{name:"syncState",state:"done"}),await k()}else if("contextMenu"===e.name){const o=e.action,i=e.id,n=e.itemType;try{if("folder"===n)switch(o){case"newNote":{const e=await joplin.data.post(["notes"],null,{title:l.newNote,parent_id:i});await joplin.commands.execute("openNote",e.id),u=e.id,v(i);break}case"newTodo":{const e=await joplin.data.post(["notes"],null,{title:l.newTodo,parent_id:i,is_todo:1});await joplin.commands.execute("openNote",e.id),u=e.id,v(i);break}case"newSubNotebook":{const e=await m(l.newNotebook,"");e&&e.trim()&&await joplin.data.post(["folders"],null,{title:e.trim(),parent_id:i});break}case"deleteFolder":{const e=await joplin.data.get(["folders",i],{fields:["title"]});await f(l.confirmDeleteFolder+"\n\n"+e.title)&&await joplin.data.delete(["folders",i]);break}case"renameFolder":{const e=await joplin.data.get(["folders",i],{fields:["title"]}),t=await m(l.promptRename,e.title);t&&t.trim()&&await joplin.data.put(["folders",i],null,{title:t.trim()});break}case"exportFolder":try{await joplin.commands.execute("exportFolders",[i])}catch(e){}break;case"pinFolder":y.some(e=>e.id===i)||(y.push({id:i,type:"folder"}),await j());break;case"unpinFolder":y=y.filter(e=>e.id!==i),await j()}else if("note"===n)switch(o){case"openNote":await joplin.commands.execute("openNote",i),u=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"]}),t="["+e.title+"](:/"+e.id+")";try{await joplin.clipboard.writeText(t)}catch(e){await joplin.views.panels.postMessage(d,{name:"copyText",text:t})}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),u=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"renameNote":{const e=await joplin.data.get(["notes",i],{fields:["title"]}),t=await m(l.promptRename,e.title);t&&t.trim()&&await joplin.data.put(["notes",i],null,{title:t.trim()});break}case"moveNote":if(e.targetFolderName){let t=null;for(const o of h)if(o.title===e.targetFolderName){t=o;break}t&&await joplin.data.put(["notes",i],null,{parent_id:t.id})}break;case"noteInfo":{const e=await joplin.data.get(["notes",i],{fields:["id","title","created_time","updated_time","is_todo","parent_id","body"]});let o="";for(const t of h)if(t.id===e.parent_id){o=t.title;break}const n=(e.body||"").length,a="ID: "+e.id+"\n"+(l.ctxRenameNote||"Title")+": "+e.title+"\n"+(l.newNotebook||"Notebook")+": "+o+"\n"+(l.sortUpdatedDesc?l.sortUpdatedDesc.replace(/[↓↑\u2193\u2191]\s*/,""):"Created")+": "+new Date(e.created_time).toLocaleString()+"\n"+(l.sortUpdatedAsc?l.sortUpdatedAsc.replace(/[↓↑\u2193\u2191]\s*/,""):"Updated")+": "+new Date(e.updated_time).toLocaleString()+"\nType: "+(e.is_todo?"To-do":"Note")+"\nSize: "+n+" chars";await async function(e,o){await joplin.views.dialogs.setHtml(w,'<div style="padding:10px;min-width:320px;"><div style="font-size:14px;font-weight:bold;margin-bottom:10px;">'+t(e)+'</div><div style="font-size:12px;line-height:1.8;white-space:pre-wrap;">'+t(o)+"</div></div>"),await joplin.views.dialogs.setButtons(w,[{id:"ok",title:"OK"}]),await joplin.views.dialogs.open(w)}(e.title,a);break}case"deleteNote":{const e=await joplin.data.get(["notes",i],{fields:["title"]});await f(l.confirmDeleteNote+"\n\n"+e.title)&&await joplin.data.delete(["notes",i]);break}case"pinNote":y.some(e=>e.id===i)||(y.push({id:i,type:"note"}),await j());break;case"unpinNote":y=y.filter(e=>e.id!==i),await j()}await k()}catch(e){console.error("Notes In List: context menu error",e)}}else if("dragDrop"===e.name)try{const t=e.dragId,o=e.dragType,i=e.targetId,n=e.position;if("note"===o){if("into"===n){let e=i,o=!1;for(const e of h)if(e.id===i){o=!0;break}o||(e=(await joplin.data.get(["notes",i],{fields:["parent_id"]})).parent_id),await joplin.data.put(["notes",t],null,{parent_id:e})}}else if("folder"===o)if("into"===n)t!==i&&await joplin.data.put(["folders",t],null,{parent_id:i});else{let e=null;for(const t of h)if(t.id===i){e=t;break}e&&await joplin.data.put(["folders",t],null,{parent_id:e.parent_id||""})}await k()}catch(e){console.error("Notes In List: drag drop error",e)}else if("dragToEmpty"===e.name)try{const t=e.dragId,o=e.dragType,i=await m(l.promptNewNotebookName,"");if(!i||!i.trim())return;const n=await joplin.data.post(["folders"],null,{title:i.trim()});"note"===o?await joplin.data.put(["notes",t],null,{parent_id:n.id}):"folder"===o&&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)}}),await joplin.workspace.onNoteSelectionChange(async()=>{const e=await joplin.workspace.selectedNote();e&&e.id!==u&&(u=e.id,await joplin.views.panels.postMessage(d,{name:"selectNote",id:e.id}))}),await k()}})})();
|
|
1
|
+
(()=>{"use strict";const e={zh_CN:{newNotebook:"新建笔记本",newNote:"新建笔记",newTodo:"新建待办",sort:"排序",collapseAll:"全部折叠",expandAll:"全部展开",search:"搜索笔记内容...",searchResultCount:"找到 {count} 条结果",searchNoResult:"没有找到匹配的笔记",searching:"搜索中...",sync:"同步",syncing:"同步中...",syncDone:"✔ 同步完成",loading:"加载中...",sortUpdatedDesc:"↓ 修改时间",sortUpdatedAsc:"↑ 修改时间",sortTitleAsc:"↑ 标题",sortTitleDesc:"↓ 标题",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:"收藏夹",ctxPin:"📌 收藏",ctxUnpin:"取消收藏",cancel:"取消"},zh_TW:{newNotebook:"新建筆記本",newNote:"新建筆記",newTodo:"新建待辦",sort:"排序",collapseAll:"全部摺疊",expandAll:"全部展開",search:"搜尋筆記內容...",searchResultCount:"找到 {count} 條結果",searchNoResult:"沒有找到匹配的筆記",searching:"搜尋中...",sync:"同步",syncing:"同步中...",syncDone:"✔ 同步完成",loading:"載入中...",sortUpdatedDesc:"↓ 修改時間",sortUpdatedAsc:"↑ 修改時間",sortTitleAsc:"↑ 標題",sortTitleDesc:"↓ 標題",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:"收藏夾",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",loading:"Loading...",sortUpdatedDesc:"↓ Updated",sortUpdatedAsc:"↑ Updated",sortTitleAsc:"↑ Title",sortTitleDesc:"↓ Title",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",ctxPin:"📌 Pin",ctxUnpin:"Unpin",cancel:"Cancel"},ru:{newNotebook:"Новый блокнот",newNote:"Новая заметка",newTodo:"Новая задача",sort:"Сортировка",collapseAll:"Свернуть все",expandAll:"Развернуть все",search:"Искать в содержимом заметок...",searchResultCount:"Найдено результатов: {count}",searchNoResult:"Заметки не найдены",searching:"Поиск...",sync:"Синхронизировать",syncing:"Синхронизация...",syncDone:"✔ Синхронизация завершена",loading:"Загрузка...",sortUpdatedDesc:"↓ Обновлено",sortUpdatedAsc:"↑ Обновлено",sortTitleAsc:"↑ Название",sortTitleDesc:"↓ Название",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:"Закрепленные",ctxPin:"📌 Закрепить",ctxUnpin:"Открепить",cancel:"Отмена"},ja_JP:{newNotebook:"新規ノートブック",newNote:"新規ノート",newTodo:"新規タスク",sort:"並べ替え",collapseAll:"すべて折りたたむ",expandAll:"すべて展開",search:"ノート内容を検索...",searchResultCount:"{count} 件の結果",searchNoResult:"一致するノートが見つかりません",searching:"検索中...",sync:"同期",syncing:"同期中...",syncDone:"✔ 同期完了",loading:"読み込み中...",sortUpdatedDesc:"↓ 更新日時",sortUpdatedAsc:"↑ 更新日時",sortTitleAsc:"↑ タイトル",sortTitleDesc:"↓ タイトル",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:"ピン留め",ctxPin:"📌 ピン留め",ctxUnpin:"ピン解除",cancel:"キャンセル"}};function t(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}async function o(){let e=[],t=1,o=!0;for(;o;){const n=await joplin.data.get(["folders"],{fields:["id","title","parent_id","icon"],page:t,limit:100});e=e.concat(n.items),o=n.has_more,t++}return e}async function n(e){let t=[],o=1,n=!0;for(;n;){const i=await joplin.data.get(["folders",e,"notes"],{fields:["id","title","parent_id","is_todo","todo_completed","updated_time","user_updated_time"],page:o,limit:100,order_by:"user_updated_time",order_dir:"DESC"});t=t.concat(i.items),n=i.has_more,o++}return t}function i(e){let t=e.icon;if(t&&"string"==typeof t)try{t=JSON.parse(t)}catch(e){t=null}return t&&t.emoji?t.emoji:"📂"}function a(e,o,n,s=0){let l="";for(const d of e){const e=18*s;if("folder"===d.type){const r=d.total_count||d.note_count||0,c=n[d.id],p=c?"▶":"▼",w=c?"toggle":"toggle expanded";l+='<div class="tree-item folder" style="padding-left:'+e+'px" data-id="'+d.id+'" data-type="folder">',l+='<span class="'+w+'">'+p+"</span>",l+='<span class="icon folder-icon">'+i(d)+"</span>",l+='<span class="label">'+t(d.title)+"</span>",l+='<span class="count">'+r+"</span>",l+="</div>",l+='<div class="children'+(c?" collapsed":"")+'" data-folder-id="'+d.id+'">',d.children&&(l+=a(d.children,o,n,s+1)),l+="</div>"}else{const n=d.id===o?" selected":"";let i="📝";d.is_todo&&(i=d.todo_completed?"☑":"☐"),l+='<div class="tree-item note'+n+'" style="padding-left:'+e+'px" data-id="'+d.id+'" data-type="note">',l+='<span class="icon note-icon">'+i+"</span>",l+='<span class="label">'+t(d.title)+"</span>",l+="</div>"}}return l}function s(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;default:o.sort((e,t)=>(t.user_updated_time||0)-(e.user_updated_time||0))}return o}joplin.plugins.register({onStart:async function(){const l=(r=await joplin.settings.globalValue("locale")||"en_US",e[r]||e[r.split("_")[0]]||e.en_US),d=await joplin.views.panels.create("notesInListPanel");var r;await joplin.views.panels.addScript(d,"webview/panel.css"),await joplin.views.panels.addScript(d,"webview/panel.js"),await joplin.views.panels.setHtml(d,'<div id="notes-in-list-root"><p style="padding:12px;">'+l.loading+"</p></div>"),await joplin.views.panels.show(d,!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)"}})}catch(e){console.error("Joplin Explorer: failed to register settings",e)}const c=await joplin.views.dialogs.create("explorerInputDialog"),p=await joplin.views.dialogs.create("explorerConfirmDialog"),w=await joplin.views.dialogs.create("explorerInfoDialog");async function f(e){return await joplin.views.dialogs.setHtml(p,'<div style="padding:10px;min-width:280px;"><div style="font-size:13px;">'+t(e)+"</div></div>"),await joplin.views.dialogs.setButtons(p,[{id:"ok",title:"OK"},{id:"cancel",title:l.cancel||"Cancel"}]),"ok"===(await joplin.views.dialogs.open(p)).id}async function m(e,o){await joplin.views.dialogs.setHtml(c,'<div style="padding:10px;min-width:300px;"><div style="margin-bottom:8px;font-size:13px;">'+t(e)+'</div><form name="inputForm"><input name="value" type="text" value="'+t(o||"")+'" style="width:100%;box-sizing:border-box;padding:6px 8px;font-size:13px;" /></form></div>'),await joplin.views.dialogs.setButtons(c,[{id:"ok",title:"OK"},{id:"cancel",title:l.cancel||"Cancel"}]);const n=await joplin.views.dialogs.open(c);return"ok"===n.id&&n.formData&&n.formData.inputForm&&n.formData.inputForm.value||null}let u="",N={},g="updated_desc",x=[],h=[],y=[],b=!1,_=!0;async function v(){try{await joplin.settings.setValue("pinnedItems",JSON.stringify(y))}catch(e){console.error("Joplin Explorer: failed to save pinned items",e)}}function j(e){let t=e;for(;t;){delete N[t];let e=null;for(const o of x)if(o.id===t){e=o;break}t=e?e.parent_id:null}}async function k(){try{const e=await o();if(x=e,_){for(const t of e)N[t.id]=!0;const t=await joplin.workspace.selectedNote();if(t){u=t.id;let o=t.parent_id;for(;o;){delete N[o];let t=null;for(const n of e)if(n.id===o){t=n;break}o=t?t.parent_id:null}}_=!1}const r={},c=10;for(let t=0;t<e.length;t+=c){const o=e.slice(t,t+c),i=await Promise.all(o.map(e=>n(e.id)));for(let e=0;e<o.length;e++)r[o[e].id]=s(i[e],g)}const p=[];for(const e of Object.keys(r))for(const t of r[e])p.push(t);h=p;const w=function(e,t){const o={};for(const t of e)o[t.id]={type:"folder",id:t.id,title:t.title,parent_id:t.parent_id,icon:t.icon,note_count:0,children:[]};for(const e of Object.keys(t)){const n=o[e];if(n){const o=t[e];n.note_count=o.length;for(const e of o)n.children.push({type:"note",id:e.id,title:e.title||"(untitled)",is_todo:e.is_todo,todo_completed:e.todo_completed})}}const n=[];for(const t of e){const e=o[t.id];t.parent_id&&o[t.parent_id]?o[t.parent_id].children.unshift(e):n.push(e)}function i(e){let t=0;if(!e.children)return 0;for(const o of e.children)"note"===o.type?t++:"folder"===o.type&&(i(o),t+=o.total_count||0);return e.total_count=t,t}for(const e of n)i(e);return n}(e,r),f=a(w,u,N);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){y=[];for(const e of t.folders)y.push({id:e,type:"folder"});for(const e of t.notes)y.push({id:e,type:"note"});await v()}else Array.isArray(t)&&(y=t)}catch(e){y=[]}}();const m=new Set(e.map(e=>e.id)),j=new Set(p.map(e=>e.id)),k=y.length;y=y.filter(e=>"folder"===e.type?m.has(e.id):j.has(e.id)),y.length!==k&&await v();let T="";const D=y.length;if(D>0){T+='<div class="pinned-section-header" id="pinned-header"><span class="toggle">'+(b?"▶":"▼")+'</span><span class="icon">📌</span><span class="label">'+l.pinned+" ("+D+")</span></div>",T+='<div class="pinned-section-body'+(b?" collapsed":"")+'" id="pinned-body">';for(const o of y)if("folder"===o.type){let n=null;for(const t of e)if(t.id===o.id){n=t;break}if(n){const e=i(n);T+='<div class="tree-item folder pinned-item" data-id="'+n.id+'" data-type="folder">',T+='<span class="icon folder-icon">'+e+"</span>",T+='<span class="label">'+t(n.title)+"</span>",T+="</div>"}}else{let e=null;for(const t of p)if(t.id===o.id){e=t;break}if(e){const o=e.id===u?" selected":"";let n="📝";e.is_todo&&(n=e.todo_completed?"☑":"☐"),T+='<div class="tree-item note pinned-item'+o+'" data-id="'+e.id+'" data-type="note">',T+='<span class="icon note-icon">'+n+"</span>",T+='<span class="label">'+t(e.title)+"</span>",T+="</div>"}}T+="</div>"}const S=t(JSON.stringify(y)),F={updated_desc:l.sortUpdatedDesc,updated_asc:l.sortUpdatedAsc,title_asc:l.sortTitleAsc,title_desc:l.sortTitleDesc},I='<div id="notes-in-list-root" data-i18n="'+t(JSON.stringify(l))+'" data-pinned="'+S+'"> <div class="toolbar"> <button id="btn-new-notebook" title="'+l.newNotebook+'">📁+</button> <button id="btn-new-note" title="'+l.newNote+'">📝+</button> <button id="btn-new-todo" title="'+l.newTodo+'">☐+</button> <button id="btn-sort" title="'+l.sort+'">'+F[g]+'</button> <button id="btn-collapse-all" title="'+l.collapseAll+'">▲</button> </div> <div class="search-bar"> <input id="search-input" type="text" placeholder="🔍 '+l.search+'" /> </div> <div id="tree-container">'+T+f+' <div id="drop-zone-empty" class="drop-zone-empty">+ '+l.dropCreateNotebook+'</div> </div> <div id="search-results" style="display:none;"></div> <div class="bottom-bar"> <button id="btn-sync" title="'+l.sync+'">🔄 '+l.sync+"</button> </div></div>";await joplin.views.panels.setHtml(d,I)}catch(e){console.error("Notes In List: refresh error",e),await joplin.views.panels.setHtml(d,'<div style="padding:12px;color:red;">Error: '+t(String(e))+"</div>")}}await joplin.views.panels.onMessage(d,async e=>{if("openNote"===e.name)u=e.id,await joplin.commands.execute("openNote",e.id);else if("refresh"===e.name)await k();else if("toggleFolder"===e.name)N[e.id]?delete N[e.id]:N[e.id]=!0,await k();else if("collapseAll"===e.name){const e=await o();for(const t of e)N[t.id]=!0;await k()}else if("expandAll"===e.name)N={},await k();else if("newNotebook"===e.name)await joplin.commands.execute("newFolder"),await k();else if("newNote"===e.name){await joplin.commands.execute("newNote");const e=await joplin.workspace.selectedNote();e&&(u=e.id,j(e.parent_id)),await k()}else if("newTodo"===e.name){await joplin.commands.execute("newTodo");const e=await joplin.workspace.selectedNote();e&&(u=e.id,j(e.parent_id)),await k()}else if("search"===e.name){const t=e.query;if(!t||!t.trim())return void await joplin.views.panels.postMessage(d,{name:"searchResults",results:null,query:"",searchId:e.searchId});try{const o=t.toLowerCase(),n={};for(const e of x)n[e.id]=e.title;let i=[],a=1,s=!0;for(;s&&i.length<100;){const e=await joplin.data.get(["search"],{query:t,fields:["id","title","body","parent_id","is_todo","todo_completed"],page:a,limit:20});i=i.concat(e.items),s=e.has_more,a++}const l=new Set(i.map(e=>e.id)),r=[];for(const e of h)!l.has(e.id)&&(e.title||"").toLowerCase().indexOf(o)>=0&&r.push(e);for(let e=0;e<r.length&&e<50;e++)try{const t=await joplin.data.get(["notes",r[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 i=e.body||"",a=i.toLowerCase().indexOf(o);if(a>=0){const e=Math.max(0,a-40),n=Math.min(i.length,a+o.length+80);t=(e>0?"...":"")+i.substring(e,n).replace(/\n/g," ")+(n<i.length?"...":"")}else t=i.substring(0,120).replace(/\n/g," ")+(i.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=[],w=1,f=!0;for(;f;){const e=await joplin.data.get(["tags"],{fields:["id","title"],page:w,limit:100});p=p.concat(e.items),f=e.has_more,w++}const m=[];for(const e of p)if((e.title||"").toLowerCase().indexOf(o)>=0){let t=0;try{const o=await joplin.data.get(["tags",e.id,"notes"],{fields:["id"],limit:1});if(t=o.items.length+(o.has_more?"+":0),o.has_more){let n=o.items.length,i=2,a=!0;for(;a;){const t=await joplin.data.get(["tags",e.id,"notes"],{fields:["id"],page:i,limit:100});n+=t.items.length,a=t.has_more,i++}t=n}}catch(e){}m.push({id:e.id,title:e.title,noteCount:t})}const u=[];for(const e of x)(e.title||"").toLowerCase().indexOf(o)>=0&&u.push({id:e.id,title:e.title,parent_id:e.parent_id,icon:e.icon});await joplin.views.panels.postMessage(d,{name:"searchResults",notes:c,tags:m,folders:u,query:t,searchId:e.searchId})}catch(e){console.error("Joplin Explorer: search error",e)}}else if("loadTagNotes"===e.name)try{const t=e.tagId;let o=[],n=1,i=!0;for(;i&&o.length<100;){const e=await joplin.data.get(["tags",t,"notes"],{fields:["id","title","parent_id","is_todo","todo_completed"],page:n,limit:50});o=o.concat(e.items),i=e.has_more,n++}const a={};for(const e of x)a[e.id]=e.title;const s=o.map(e=>({id:e.id,title:e.title||"(untitled)",is_todo:e.is_todo,todo_completed:e.todo_completed,snippet:"",folderName:a[e.parent_id]||""}));await joplin.views.panels.postMessage(d,{name:"tagNotes",tagId:t,notes:s})}catch(e){console.error("Joplin Explorer: loadTagNotes error",e)}else if("locateFolder"===e.name)try{j(e.folderId),await k(),await joplin.views.panels.postMessage(d,{name:"exitSearchAndLocate",folderId:e.folderId})}catch(e){console.error("Joplin Explorer: locateFolder error",e)}else if("locatePinnedFolder"===e.name)try{j(e.folderId),await k(),await joplin.views.panels.postMessage(d,{name:"scrollToFolder",folderId:e.folderId})}catch(e){console.error("Joplin Explorer: locatePinnedFolder error",e)}else if("reorderPinned"===e.name)try{const t=e.dragId,o=e.targetId,n=e.position,i=y.findIndex(e=>e.id===t);if(i<0)return;const a=y[i];y.splice(i,1);let s=y.findIndex(e=>e.id===o);s<0?y.push(a):("after"===n&&s++,y.splice(s,0,a)),await v(),await k()}catch(e){console.error("Joplin Explorer: reorderPinned error",e)}else if("togglePinnedCollapse"===e.name)b=!b,await k();else if("cycleSort"===e.name){const e=["updated_desc","updated_asc","title_asc","title_desc"],t=e.indexOf(g);g=e[(t+1)%e.length],await k()}else if("sync"===e.name){await joplin.views.panels.postMessage(d,{name:"syncState",state:"syncing"});try{await joplin.commands.execute("synchronize")}catch(e){console.error("Joplin Explorer: sync error",e)}await new Promise(e=>setTimeout(e,3e3)),await joplin.views.panels.postMessage(d,{name:"syncState",state:"done"}),await k()}else if("contextMenu"===e.name){const o=e.action,n=e.id,i=e.itemType;try{if("folder"===i)switch(o){case"newNote":{const e=await joplin.data.post(["notes"],null,{title:l.newNote,parent_id:n});await joplin.commands.execute("openNote",e.id),u=e.id,j(n);break}case"newTodo":{const e=await joplin.data.post(["notes"],null,{title:l.newTodo,parent_id:n,is_todo:1});await joplin.commands.execute("openNote",e.id),u=e.id,j(n);break}case"newSubNotebook":{const e=await m(l.newNotebook,"");e&&e.trim()&&await joplin.data.post(["folders"],null,{title:e.trim(),parent_id:n});break}case"deleteFolder":{const e=await joplin.data.get(["folders",n],{fields:["title"]});await f(l.confirmDeleteFolder+"\n\n"+e.title)&&await joplin.data.delete(["folders",n]);break}case"renameFolder":{const e=await joplin.data.get(["folders",n],{fields:["title"]}),t=await m(l.promptRename,e.title);t&&t.trim()&&await joplin.data.put(["folders",n],null,{title:t.trim()});break}case"exportFolder":try{await joplin.commands.execute("exportFolders",[n])}catch(e){}break;case"pinFolder":y.some(e=>e.id===n)||(y.push({id:n,type:"folder"}),await v());break;case"unpinFolder":y=y.filter(e=>e.id!==n),await v()}else if("note"===i)switch(o){case"openNote":await joplin.commands.execute("openNote",n),u=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"]}),t="["+e.title+"](:/"+e.id+")";try{await joplin.clipboard.writeText(t)}catch(e){await joplin.views.panels.postMessage(d,{name:"copyText",text:t})}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),u=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"renameNote":{const e=await joplin.data.get(["notes",n],{fields:["title"]}),t=await m(l.promptRename,e.title);t&&t.trim()&&await joplin.data.put(["notes",n],null,{title:t.trim()});break}case"moveNote":if(e.targetFolderName){let t=null;for(const o of x)if(o.title===e.targetFolderName){t=o;break}t&&await joplin.data.put(["notes",n],null,{parent_id:t.id})}break;case"noteInfo":{const e=await joplin.data.get(["notes",n],{fields:["id","title","created_time","updated_time","is_todo","parent_id","body"]});let o="";for(const t of x)if(t.id===e.parent_id){o=t.title;break}const i=(e.body||"").length,a="ID: "+e.id+"\n"+(l.ctxRenameNote||"Title")+": "+e.title+"\n"+(l.newNotebook||"Notebook")+": "+o+"\n"+(l.sortUpdatedDesc?l.sortUpdatedDesc.replace(/[↓↑\u2193\u2191]\s*/,""):"Created")+": "+new Date(e.created_time).toLocaleString()+"\n"+(l.sortUpdatedAsc?l.sortUpdatedAsc.replace(/[↓↑\u2193\u2191]\s*/,""):"Updated")+": "+new Date(e.updated_time).toLocaleString()+"\nType: "+(e.is_todo?"To-do":"Note")+"\nSize: "+i+" chars";await async function(e,o){await joplin.views.dialogs.setHtml(w,'<div style="padding:10px;min-width:320px;"><div style="font-size:14px;font-weight:bold;margin-bottom:10px;">'+t(e)+'</div><div style="font-size:12px;line-height:1.8;white-space:pre-wrap;">'+t(o)+"</div></div>"),await joplin.views.dialogs.setButtons(w,[{id:"ok",title:"OK"}]),await joplin.views.dialogs.open(w)}(e.title,a);break}case"deleteNote":{const e=await joplin.data.get(["notes",n],{fields:["title"]});await f(l.confirmDeleteNote+"\n\n"+e.title)&&await joplin.data.delete(["notes",n]);break}case"pinNote":y.some(e=>e.id===n)||(y.push({id:n,type:"note"}),await v());break;case"unpinNote":y=y.filter(e=>e.id!==n),await v()}await k()}catch(e){console.error("Notes In List: context menu error",e)}}else if("dragDrop"===e.name)try{const t=e.dragId,o=e.dragType,n=e.targetId,i=e.position;if("note"===o){if("into"===i){let e=n,o=!1;for(const e of x)if(e.id===n){o=!0;break}o||(e=(await joplin.data.get(["notes",n],{fields:["parent_id"]})).parent_id),await joplin.data.put(["notes",t],null,{parent_id:e})}}else if("folder"===o)if("into"===i)t!==n&&await joplin.data.put(["folders",t],null,{parent_id:n});else{let e=null;for(const t of x)if(t.id===n){e=t;break}e&&await joplin.data.put(["folders",t],null,{parent_id:e.parent_id||""})}await k()}catch(e){console.error("Notes In List: drag drop error",e)}else if("dragToEmpty"===e.name)try{const t=e.dragId,o=e.dragType,n=await m(l.promptNewNotebookName,"");if(!n||!n.trim())return;const i=await joplin.data.post(["folders"],null,{title:n.trim()});"note"===o?await joplin.data.put(["notes",t],null,{parent_id:i.id}):"folder"===o&&t!==i.id&&await joplin.data.put(["folders",t],null,{parent_id:i.id}),await k()}catch(e){console.error("Notes In List: drag to empty error",e)}}),await joplin.workspace.onNoteSelectionChange(async()=>{const e=await joplin.workspace.selectedNote();e&&e.id!==u&&(u=e.id,await joplin.views.panels.postMessage(d,{name:"selectNote",id:e.id}))}),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.2.
|
|
5
|
+
"version": "1.2.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
|
|
@@ -311,10 +311,10 @@ html, body {
|
|
|
311
311
|
background: rgba(74, 156, 245, 0.08);
|
|
312
312
|
}
|
|
313
313
|
|
|
314
|
-
/* Pinned section accepts drops during drag */
|
|
314
|
+
/* Pinned section accepts drops during drag — outline doesn't affect layout */
|
|
315
315
|
#tree-container.dragging-active .pinned-section-header {
|
|
316
|
-
|
|
317
|
-
|
|
316
|
+
outline: 2px dashed var(--joplin-color2, #4a9cf5);
|
|
317
|
+
outline-offset: -2px;
|
|
318
318
|
}
|
|
319
319
|
|
|
320
320
|
/* Drag & Drop */
|
package/publish/webview/panel.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var _savedScrollTop=0,_isFirstRender=!0;function postMsg(e){webviewApi.postMessage(e)}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 i=document.createElement("div");i.id="inline-input-overlay",i.className="inline-input-overlay",i.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(i);var s=i.querySelector(".inline-input-field");function d(){var e=s.value;i.remove(),a(e)}function o(){i.remove(),a(null)}s.focus(),s.select(),i.querySelector(".inline-input-ok").addEventListener("click",d),i.querySelector(".inline-input-cancel").addEventListener("click",o),s.addEventListener("keydown",function(e){"Enter"===e.key&&d(),"Escape"===e.key&&o()}),i.addEventListener("click",function(e){e.target===i&&o()})}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(){clearDropIndicators();var e=document.getElementById("tree-container");e&&e.classList.remove("dragging-active")}_observer.observe(document.body,{childList:!0,subtree:!0}),document.addEventListener("click",function(e){var t=document.getElementById("ctx-menu");t&&t.remove();var a=e.target.closest(".search-tag-item");if(a){var n=a.dataset.tagId;n&&postMsg({name:"loadTagNotes",tagId:n})}else{var i=e.target.closest(".search-folder-item");if(i){var s=i.dataset.folderId;s&&postMsg({name:"locateFolder",folderId:s})}else{var d=e.target.closest(".tree-item");if(d){var o=d.dataset.type,r=d.dataset.id,c=d.classList.contains("pinned-item");"note"===o&&(document.querySelectorAll(".tree-item.note.selected").forEach(function(e){e.classList.remove("selected")}),d.classList.add("selected"),postMsg({name:"openNote",id:r})),"folder"===o&&postMsg(c?{name:"locatePinnedFolder",folderId:r}:{name:"toggleFolder",id:r})}}}}),document.addEventListener("contextmenu",function(e){var t=document.getElementById("ctx-menu");t&&t.remove();var a=e.target.closest(".tree-item");if(a){e.preventDefault();var n=a.dataset.type,i=a.dataset.id,s="",d=a.querySelector(".label");d&&(s=d.textContent);var o='<div id="ctx-menu" class="context-menu" style="left:'+e.pageX+"px;top:"+e.pageY+'px;">';if("folder"===n){var r=isPinned(i);o+='<div class="ctx-item" data-action="'+(r?"unpinFolder":"pinFolder")+'" data-id="'+i+'" data-type="folder">'+T(r?"ctxUnpin":"ctxPin")+"</div>",o+='<div class="ctx-sep"></div>',o+='<div class="ctx-item" data-action="newNote" data-id="'+i+'" data-type="folder">'+T("ctxNewNoteHere")+"</div>",o+='<div class="ctx-item" data-action="newTodo" data-id="'+i+'" data-type="folder">'+T("ctxNewTodoHere")+"</div>",o+='<div class="ctx-item" data-action="newSubNotebook" data-id="'+i+'" data-type="folder">'+T("ctxNewSubNotebook")+"</div>",o+='<div class="ctx-sep"></div>',o+='<div class="ctx-item" data-action="renameFolder" data-id="'+i+'" data-type="folder" data-title="'+s.replace(/"/g,""")+'">'+T("ctxRenameFolder")+"</div>",o+='<div class="ctx-item" data-action="exportFolder" data-id="'+i+'" data-type="folder">'+T("ctxExportFolder")+"</div>",o+='<div class="ctx-sep"></div>',o+='<div class="ctx-item ctx-danger" data-action="deleteFolder" data-id="'+i+'" data-type="folder">'+T("ctxDeleteFolder")+"</div>"}else if("note"===n){var c=isPinned(i);o+='<div class="ctx-item" data-action="'+(c?"unpinNote":"pinNote")+'" data-id="'+i+'" data-type="note">'+T(c?"ctxUnpin":"ctxPin")+"</div>",o+='<div class="ctx-sep"></div>',o+='<div class="ctx-item" data-action="openNote" data-id="'+i+'" data-type="note">'+T("ctxOpenNote")+"</div>",o+='<div class="ctx-item" data-action="openInNewWindow" data-id="'+i+'" data-type="note">'+T("ctxOpenInNewWindow")+"</div>",o+='<div class="ctx-sep"></div>',o+='<div class="ctx-item" data-action="copyLink" data-id="'+i+'" data-type="note">'+T("ctxCopyLink")+"</div>",o+='<div class="ctx-item" data-action="duplicateNote" data-id="'+i+'" data-type="note">'+T("ctxDuplicateNote")+"</div>",o+='<div class="ctx-item" data-action="switchNoteType" data-id="'+i+'" data-type="note">'+T("ctxSwitchNoteType")+"</div>",o+='<div class="ctx-item" data-action="toggleTodo" data-id="'+i+'" data-type="note">'+T("ctxToggleTodo")+"</div>",o+='<div class="ctx-sep"></div>',o+='<div class="ctx-item" data-action="renameNote" data-id="'+i+'" data-type="note" data-title="'+s.replace(/"/g,""")+'">'+T("ctxRenameNote")+"</div>",o+='<div class="ctx-item" data-action="noteInfo" data-id="'+i+'" data-type="note">'+T("ctxNoteInfo")+"</div>",o+='<div class="ctx-sep"></div>',o+='<div class="ctx-item ctx-danger" data-action="deleteNote" data-id="'+i+'" data-type="note">'+T("ctxDeleteNote")+"</div>"}o+="</div>",document.body.insertAdjacentHTML("beforeend",o);var l=document.getElementById("ctx-menu"),v=l.getBoundingClientRect();v.right>window.innerWidth&&(l.style.left=window.innerWidth-v.width-4+"px"),v.bottom>window.innerHeight&&(l.style.top=window.innerHeight-v.height-4+"px")}}),document.addEventListener("click",function(e){var t=e.target.closest(".ctx-item");if(t){postMsg({name:"contextMenu",action:t.dataset.action,id:t.dataset.id,itemType:t.dataset.type});var a=document.getElementById("ctx-menu");a&&a.remove()}}),document.addEventListener("mousedown",function(e){if(!e.target.closest("#ctx-menu")){var t=document.getElementById("ctx-menu");t&&t.remove()}}),document.addEventListener("click",function(e){e.target.closest(".pinned-section-header")&&postMsg({name:"togglePinnedCollapse"})}),document.addEventListener("click",function(e){var t=e.target.closest(".search-section-header");if(t){var a=t.dataset.section,n=document.getElementById("search-section-"+a);if(n){var i=t.querySelector(".section-toggle");n.classList.contains("collapsed")?(n.classList.remove("collapsed"),i&&(i.textContent="▼")):(n.classList.add("collapsed"),i&&(i.textContent="▶"))}}}),document.addEventListener("click",function(e){var t=e.target.closest("button");if(t)switch(t.id){case"btn-new-notebook":postMsg({name:"newNotebook"});break;case"btn-new-note":postMsg({name:"newNote"});break;case"btn-new-todo":postMsg({name:"newTodo"});break;case"btn-sort":postMsg({name:"cycleSort"});break;case"btn-collapse-all":postMsg({name:"collapseAll"});break;case"btn-sync":var a=document.getElementById("btn-sync");a&&!a.disabled&&(a.disabled=!0,a.classList.add("syncing"),a.textContent="🔄 "+T("syncing"),postMsg({name:"sync"}))}}),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;"done"===t.state&&(a.classList.remove("syncing"),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))}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("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&&(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 n=document.getElementById("search-input");n&&(n.value=""),_searchMode&&exitSearchMode()}else if("exitSearchAndLocate"===t.name){var i=document.getElementById("search-input");i&&(i.value=""),_searchMode=!1,showSearchContainer(!1),setTimeout(function(){var e=document.querySelector('.tree-item.folder[data-id="'+t.folderId+'"]');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 s=document.createElement("textarea");s.value=t.text,document.body.appendChild(s),s.select(),document.execCommand("copy"),s.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"}))}}}),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){var a=t.classList.contains("pinned-item");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");var n=document.getElementById("tree-container");n&&n.classList.add("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){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"))return e.preventDefault(),void(e.dataTransfer.dropEffect="move");if(t.closest(".pinned-section-header")||t.closest(".pinned-section-body")){if(e.preventDefault(),e.dataTransfer.dropEffect="move",clearDropIndicators(),a&&a.classList.contains("pinned-item")){var n=a.getBoundingClientRect();e.clientY-n.top<.5*n.height?a.classList.add("drop-above"):a.classList.add("drop-below")}}else if(a){var i=document.querySelector(".tree-item.dragging");if(!i||!i.classList.contains("pinned-item")){e.preventDefault(),e.dataTransfer.dropEffect="move",clearDropIndicators();var s=a.dataset.type,d=a.getBoundingClientRect(),o=e.clientY-d.top,r=d.height;"folder"===s?o<.25*r?a.classList.add("drop-above"):o>.75*r?a.classList.add("drop-below"):a.classList.add("drop-target"):o<.5*r?a.classList.add("drop-above"):a.classList.add("drop-below")}}}}),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 i=a.id,s=a.type,d=a.pinned;if(t&&t.closest("#drop-zone-empty"))return postMsg({name:"dragToEmpty",dragId:i,dragType:s}),void endDrag();if(t&&(t.closest(".pinned-section-header")||t.closest(".pinned-section-body"))){if(d){var o=n&&n.classList.contains("pinned-item")?n:null;if(o&&o.dataset.id!==i){var r=o.getBoundingClientRect(),c=e.clientY-r.top<.5*r.height?"before":"after";postMsg({name:"reorderPinned",dragId:i,dragType:s,targetId:o.dataset.id,position:c})}}else"note"===s?postMsg({name:"contextMenu",action:"pinNote",id:i,itemType:"note"}):"folder"===s&&postMsg({name:"contextMenu",action:"pinFolder",id:i,itemType:"folder"});endDrag()}else if(d)endDrag();else if(n){var l=n.dataset.id,v=n.dataset.type;if(i!==l){var u=n.getBoundingClientRect(),m=e.clientY-u.top,p=u.height;postMsg("folder"===v?m>=.25*p&&m<=.75*p?{name:"dragDrop",dragId:i,dragType:s,targetId:l,position:"into"}:{name:"dragDrop",dragId:i,dragType:s,targetId:l,position:m<.25*p?"above":"below"}:{name:"dragDrop",dragId:i,dragType:s,targetId:l,position:"into"}),endDrag()}else endDrag()}else endDrag()});var _searchTimer=null,_searchMode=!1,_searchId=0;function escapeRegex(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function highlightText(e,t){if(!t)return e;var a=e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">"),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">';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">📂 '+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 i=document.getElementById("search-results");if(i){showSearchContainer(!0);var s=e.length+t.length+a.length;if(0!==s){var d='<div class="search-status">'+T("searchResultCount").replace("{count}",s)+"</div>";if(a.length>0){d+=p("📁",T("searchSectionFolders"),a.length,"folders"),d+='<div class="search-section-body" id="search-section-folders">';for(var o=0;o<a.length;o++){var r=a[o],c=r.icon&&r.icon.emoji?r.icon.emoji:"📁";d+='<div class="search-result-item search-folder-item" data-folder-id="'+r.id+'">',d+='<span class="icon">'+c+"</span>",d+='<div class="search-result-content">',d+='<div class="search-result-title">'+highlightText(r.title,n)+"</div>",d+="</div></div>"}d+="</div>"}if(e.length>0){d+=p("📝",T("searchSectionNotes"),e.length,"notes"),d+='<div class="search-section-body" id="search-section-notes">';for(var l=0;l<e.length;l++)d+=renderNoteItem(e[l],n);d+="</div>"}if(t.length>0){d+=p("🏷️",T("searchSectionTags"),t.length,"tags"),d+='<div class="search-section-body" id="search-section-tags">';for(var v=0;v<t.length;v++){var u=t[v],m=T("searchTagNoteCount").replace("{count}",u.noteCount);d+='<div class="search-result-item search-tag-item" data-tag-id="'+u.id+'">',d+='<span class="icon">🏷️</span>',d+='<div class="search-result-content">',d+='<div class="search-result-title">'+highlightText(u.title,n)+"</div>",d+='<div class="search-result-folder">'+m+"</div>",d+="</div>",d+='<span class="tag-expand-arrow">▶</span>',d+="</div>",d+='<div class="tag-notes-container" id="tag-notes-'+u.id+'"></div>'}d+="</div>"}i.innerHTML=d,_searchMode=!0}else i.innerHTML='<div class="search-status">'+T("searchNoResult")+"</div>"}function p(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 i="",s=0;s<t.length;s++)i+=renderNoteItem(t[s],"");0===t.length&&(i='<div class="search-status" style="padding-left:30px;">'+T("searchNoResult")+"</div>"),a.innerHTML=i,(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)}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 i=document.createElement("div");i.id="inline-input-overlay",i.className="inline-input-overlay",i.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(i);var d=i.querySelector(".inline-input-field");function o(){var e=d.value;i.remove(),a(e)}function s(){i.remove(),a(null)}d.focus(),d.select(),i.querySelector(".inline-input-ok").addEventListener("click",o),i.querySelector(".inline-input-cancel").addEventListener("click",s),d.addEventListener("keydown",function(e){"Enter"===e.key&&o(),"Escape"===e.key&&s()}),i.addEventListener("click",function(e){e.target===i&&s()})}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(){clearDropIndicators();var e=document.getElementById("tree-container");e&&e.classList.remove("dragging-active")}_observer.observe(document.body,{childList:!0,subtree:!0}),document.addEventListener("click",function(e){var t=document.getElementById("ctx-menu");t&&t.remove();var a=e.target.closest(".search-tag-item");if(a){var n=a.dataset.tagId;n&&postMsg({name:"loadTagNotes",tagId:n})}else{var i=e.target.closest(".search-folder-item");if(i){var d=i.dataset.folderId;d&&postMsg({name:"locateFolder",folderId:d})}else{var o=e.target.closest(".tree-item");if(o){var s=o.dataset.type,r=o.dataset.id,c=o.classList.contains("pinned-item");"note"===s&&(document.querySelectorAll(".tree-item.note.selected").forEach(function(e){e.classList.remove("selected")}),o.classList.add("selected"),postMsg({name:"openNote",id:r})),"folder"===s&&postMsg(c?{name:"locatePinnedFolder",folderId:r}:{name:"toggleFolder",id:r})}}}}),document.addEventListener("contextmenu",function(e){var t=document.getElementById("ctx-menu");t&&t.remove();var a=e.target.closest(".tree-item");if(a){e.preventDefault();var n=a.dataset.type,i=a.dataset.id,d="",o=a.querySelector(".label");o&&(d=o.textContent);var s='<div id="ctx-menu" class="context-menu" style="left:'+e.pageX+"px;top:"+e.pageY+'px;">';if("folder"===n){var r=isPinned(i);s+='<div class="ctx-item" data-action="'+(r?"unpinFolder":"pinFolder")+'" data-id="'+i+'" data-type="folder">'+T(r?"ctxUnpin":"ctxPin")+"</div>",s+='<div class="ctx-sep"></div>',s+='<div class="ctx-item" data-action="newNote" data-id="'+i+'" data-type="folder">'+T("ctxNewNoteHere")+"</div>",s+='<div class="ctx-item" data-action="newTodo" data-id="'+i+'" data-type="folder">'+T("ctxNewTodoHere")+"</div>",s+='<div class="ctx-item" data-action="newSubNotebook" data-id="'+i+'" data-type="folder">'+T("ctxNewSubNotebook")+"</div>",s+='<div class="ctx-sep"></div>',s+='<div class="ctx-item" data-action="renameFolder" data-id="'+i+'" data-type="folder" data-title="'+d.replace(/"/g,""")+'">'+T("ctxRenameFolder")+"</div>",s+='<div class="ctx-item" data-action="exportFolder" data-id="'+i+'" data-type="folder">'+T("ctxExportFolder")+"</div>",s+='<div class="ctx-sep"></div>',s+='<div class="ctx-item ctx-danger" data-action="deleteFolder" data-id="'+i+'" data-type="folder">'+T("ctxDeleteFolder")+"</div>"}else if("note"===n){var c=isPinned(i);s+='<div class="ctx-item" data-action="'+(c?"unpinNote":"pinNote")+'" data-id="'+i+'" data-type="note">'+T(c?"ctxUnpin":"ctxPin")+"</div>",s+='<div class="ctx-sep"></div>',s+='<div class="ctx-item" data-action="openNote" data-id="'+i+'" data-type="note">'+T("ctxOpenNote")+"</div>",s+='<div class="ctx-item" data-action="openInNewWindow" data-id="'+i+'" data-type="note">'+T("ctxOpenInNewWindow")+"</div>",s+='<div class="ctx-sep"></div>',s+='<div class="ctx-item" data-action="copyLink" data-id="'+i+'" data-type="note">'+T("ctxCopyLink")+"</div>",s+='<div class="ctx-item" data-action="duplicateNote" data-id="'+i+'" data-type="note">'+T("ctxDuplicateNote")+"</div>",s+='<div class="ctx-item" data-action="switchNoteType" data-id="'+i+'" data-type="note">'+T("ctxSwitchNoteType")+"</div>",s+='<div class="ctx-item" data-action="toggleTodo" data-id="'+i+'" data-type="note">'+T("ctxToggleTodo")+"</div>",s+='<div class="ctx-sep"></div>',s+='<div class="ctx-item" data-action="renameNote" data-id="'+i+'" data-type="note" data-title="'+d.replace(/"/g,""")+'">'+T("ctxRenameNote")+"</div>",s+='<div class="ctx-item" data-action="noteInfo" data-id="'+i+'" data-type="note">'+T("ctxNoteInfo")+"</div>",s+='<div class="ctx-sep"></div>',s+='<div class="ctx-item ctx-danger" data-action="deleteNote" data-id="'+i+'" data-type="note">'+T("ctxDeleteNote")+"</div>"}s+="</div>",document.body.insertAdjacentHTML("beforeend",s);var l=document.getElementById("ctx-menu"),v=l.getBoundingClientRect();v.right>window.innerWidth&&(l.style.left=window.innerWidth-v.width-4+"px"),v.bottom>window.innerHeight&&(l.style.top=window.innerHeight-v.height-4+"px")}}),document.addEventListener("click",function(e){var t=e.target.closest(".ctx-item");if(t){postMsg({name:"contextMenu",action:t.dataset.action,id:t.dataset.id,itemType:t.dataset.type});var a=document.getElementById("ctx-menu");a&&a.remove()}}),document.addEventListener("mousedown",function(e){if(!e.target.closest("#ctx-menu")){var t=document.getElementById("ctx-menu");t&&t.remove()}}),document.addEventListener("click",function(e){e.target.closest(".pinned-section-header")&&postMsg({name:"togglePinnedCollapse"})}),document.addEventListener("click",function(e){var t=e.target.closest(".search-section-header");if(t){var a=t.dataset.section,n=document.getElementById("search-section-"+a);if(n){var i=t.querySelector(".section-toggle");n.classList.contains("collapsed")?(n.classList.remove("collapsed"),i&&(i.textContent="▼")):(n.classList.add("collapsed"),i&&(i.textContent="▶"))}}}),document.addEventListener("click",function(e){var t=e.target.closest("button");if(t)switch(t.id){case"btn-new-notebook":postMsg({name:"newNotebook"});break;case"btn-new-note":postMsg({name:"newNote"});break;case"btn-new-todo":postMsg({name:"newTodo"});break;case"btn-sort":postMsg({name:"cycleSort"});break;case"btn-collapse-all":postMsg({name:"collapseAll"});break;case"btn-sync":var a=document.getElementById("btn-sync");a&&!a.disabled&&(a.disabled=!0,a.classList.add("syncing"),a.textContent="🔄 "+T("syncing"),postMsg({name:"sync"}))}}),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;"done"===t.state&&(a.classList.remove("syncing"),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))}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("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&&(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 n=document.getElementById("search-input");n&&(n.value=""),_searchMode&&exitSearchMode()}else if("exitSearchAndLocate"===t.name){var i=document.getElementById("search-input");i&&(i.value=""),_searchMode=!1,showSearchContainer(!1),setTimeout(function(){var e=document.querySelector('.tree-item.folder[data-id="'+t.folderId+'"]');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 d=document.createElement("textarea");d.value=t.text,document.body.appendChild(d),d.select(),document.execCommand("copy"),d.remove()}else if("selectNote"===t.name){document.querySelectorAll(".tree-item.note.selected").forEach(function(e){e.classList.remove("selected")});var o=document.querySelector('.tree-item.note[data-id="'+t.id+'"]');o&&(o.classList.add("selected"),o.scrollIntoView({block:"nearest",behavior:"instant"}))}}}),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){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")}}}),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){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 if(a){var i=document.querySelector(".tree-item.dragging");if(!i||!i.classList.contains("pinned-item")){e.preventDefault(),e.dataTransfer.dropEffect="move",clearDropIndicators();var d=a.dataset.type,o=a.getBoundingClientRect(),s=e.clientY-o.top,r=o.height;"folder"===d?s<.25*r?a.classList.add("drop-above"):s>.75*r?a.classList.add("drop-below"):a.classList.add("drop-target"):s<.5*r?a.classList.add("drop-above"):a.classList.add("drop-below")}}}}}),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 i=a.id,d=a.type,o=a.pinned;if(t&&t.closest("#drop-zone-empty")&&!o)return postMsg({name:"dragToEmpty",dragId:i,dragType:d}),void endDrag();if(t&&t.closest(".pinned-section-header")&&!o)return"note"===d?postMsg({name:"contextMenu",action:"pinNote",id:i,itemType:"note"}):"folder"===d&&postMsg({name:"contextMenu",action:"pinFolder",id:i,itemType:"folder"}),void endDrag();if(t&&t.closest(".pinned-section-body")&&o){var s=n&&n.classList.contains("pinned-item")?n:null;if(s&&s.dataset.id!==i){var r=s.getBoundingClientRect(),c=e.clientY-r.top<.5*r.height?"before":"after";postMsg({name:"reorderPinned",dragId:i,dragType:d,targetId:s.dataset.id,position:c})}endDrag()}else if(o)endDrag();else if(n){var l=n.dataset.id,v=n.dataset.type;if(i!==l){var u=n.getBoundingClientRect(),m=e.clientY-u.top,p=u.height;postMsg("folder"===v?m>=.25*p&&m<=.75*p?{name:"dragDrop",dragId:i,dragType:d,targetId:l,position:"into"}:{name:"dragDrop",dragId:i,dragType:d,targetId:l,position:m<.25*p?"above":"below"}:{name:"dragDrop",dragId:i,dragType:d,targetId:l,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">';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 i=document.getElementById("search-results");if(i){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+=p("📁",T("searchSectionFolders"),a.length,"folders"),o+='<div class="search-section-body" id="search-section-folders">';for(var s=0;s<a.length;s++){var r=a[s],c=r.icon&&r.icon.emoji?r.icon.emoji:"📁";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+=p("📝",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+=p("🏷️",T("searchSectionTags"),t.length,"tags"),o+='<div class="search-section-body" id="search-section-tags">';for(var v=0;v<t.length;v++){var u=t[v],m=T("searchTagNoteCount").replace("{count}",u.noteCount);o+='<div class="search-result-item search-tag-item" data-tag-id="'+u.id+'">',o+='<span class="icon">🏷️</span>',o+='<div class="search-result-content">',o+='<div class="search-result-title">'+highlightText(u.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-'+u.id+'"></div>'}o+="</div>"}i.innerHTML=o,_searchMode=!0}else i.innerHTML='<div class="search-status">'+T("searchNoResult")+"</div>"}function p(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 i="",d=0;d<t.length;d++)i+=renderNoteItem(t[d],"");0===t.length&&(i='<div class="search-status" style="padding-left:30px;">'+T("searchNoResult")+"</div>"),a.innerHTML=i,(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())}});
|