joplin-plugin-explorer 1.1.2 → 1.1.4
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 +106 -16
- package/publish/manifest.json +1 -1
- package/publish/plugin.jpl +0 -0
- package/publish/webview/panel.css +2 -2
- package/publish/webview/panel.js +2 -25
package/package.json
CHANGED
package/publish/index.js
CHANGED
|
@@ -254,12 +254,77 @@ joplin.plugins.register({
|
|
|
254
254
|
await joplin.views.panels.setHtml(panel, '<div id="notes-in-list-root"><p style="padding:12px;">' + t.loading + '</p></div>');
|
|
255
255
|
await joplin.views.panels.show(panel, true);
|
|
256
256
|
|
|
257
|
+
// Native dialogs
|
|
258
|
+
var inputDialog = await joplin.views.dialogs.create('explorerInputDialog');
|
|
259
|
+
var confirmDialog = await joplin.views.dialogs.create('explorerConfirmDialog');
|
|
260
|
+
var infoDialog = await joplin.views.dialogs.create('explorerInfoDialog');
|
|
261
|
+
|
|
262
|
+
async function showNativeConfirm(message) {
|
|
263
|
+
await joplin.views.dialogs.setHtml(confirmDialog,
|
|
264
|
+
'<div style="padding:10px;min-width:280px;">'
|
|
265
|
+
+ '<div style="font-size:13px;">' + escapeHtml(message) + '</div>'
|
|
266
|
+
+ '</div>'
|
|
267
|
+
);
|
|
268
|
+
await joplin.views.dialogs.setButtons(confirmDialog, [
|
|
269
|
+
{ id: 'ok', title: 'OK' },
|
|
270
|
+
{ id: 'cancel', title: t.cancel || 'Cancel' },
|
|
271
|
+
]);
|
|
272
|
+
var result = await joplin.views.dialogs.open(confirmDialog);
|
|
273
|
+
return result.id === 'ok';
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
async function showNativeInfo(title, body) {
|
|
277
|
+
await joplin.views.dialogs.setHtml(infoDialog,
|
|
278
|
+
'<div style="padding:10px;min-width:320px;">'
|
|
279
|
+
+ '<div style="font-size:14px;font-weight:bold;margin-bottom:10px;">' + escapeHtml(title) + '</div>'
|
|
280
|
+
+ '<div style="font-size:12px;line-height:1.8;white-space:pre-wrap;">' + escapeHtml(body) + '</div>'
|
|
281
|
+
+ '</div>'
|
|
282
|
+
);
|
|
283
|
+
await joplin.views.dialogs.setButtons(infoDialog, [
|
|
284
|
+
{ id: 'ok', title: 'OK' },
|
|
285
|
+
]);
|
|
286
|
+
await joplin.views.dialogs.open(infoDialog);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
async function showNativeInput(label, defaultValue) {
|
|
290
|
+
await joplin.views.dialogs.setHtml(inputDialog,
|
|
291
|
+
'<div style="padding:10px;min-width:300px;">'
|
|
292
|
+
+ '<div style="margin-bottom:8px;font-size:13px;">' + escapeHtml(label) + '</div>'
|
|
293
|
+
+ '<form name="inputForm">'
|
|
294
|
+
+ '<input name="value" type="text" value="' + escapeHtml(defaultValue || '') + '" '
|
|
295
|
+
+ 'style="width:100%;box-sizing:border-box;padding:6px 8px;font-size:13px;" />'
|
|
296
|
+
+ '</form>'
|
|
297
|
+
+ '</div>'
|
|
298
|
+
);
|
|
299
|
+
await joplin.views.dialogs.setButtons(inputDialog, [
|
|
300
|
+
{ id: 'ok', title: 'OK' },
|
|
301
|
+
{ id: 'cancel', title: t.cancel || 'Cancel' },
|
|
302
|
+
]);
|
|
303
|
+
var result = await joplin.views.dialogs.open(inputDialog);
|
|
304
|
+
if (result.id === 'ok' && result.formData && result.formData.inputForm) {
|
|
305
|
+
return result.formData.inputForm.value || null;
|
|
306
|
+
}
|
|
307
|
+
return null;
|
|
308
|
+
}
|
|
309
|
+
|
|
257
310
|
var selectedNoteId = '';
|
|
258
311
|
var collapsedFolders = {};
|
|
259
312
|
var currentSort = 'updated_desc';
|
|
260
313
|
var allFoldersCache = [];
|
|
261
314
|
var isFirstLoad = true;
|
|
262
315
|
|
|
316
|
+
function expandToFolder(folderId) {
|
|
317
|
+
var parentId = folderId;
|
|
318
|
+
while (parentId) {
|
|
319
|
+
delete collapsedFolders[parentId];
|
|
320
|
+
var found = null;
|
|
321
|
+
for (var i = 0; i < allFoldersCache.length; i++) {
|
|
322
|
+
if (allFoldersCache[i].id === parentId) { found = allFoldersCache[i]; break; }
|
|
323
|
+
}
|
|
324
|
+
parentId = found ? found.parent_id : null;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
263
328
|
function sortNotes(notes, sortMode) {
|
|
264
329
|
var sorted = notes.slice();
|
|
265
330
|
switch (sortMode) {
|
|
@@ -367,9 +432,13 @@ joplin.plugins.register({
|
|
|
367
432
|
await refreshPanel();
|
|
368
433
|
} else if (msg.name === 'newNote') {
|
|
369
434
|
await joplin.commands.execute('newNote');
|
|
435
|
+
var nn = await joplin.workspace.selectedNote();
|
|
436
|
+
if (nn) { selectedNoteId = nn.id; expandToFolder(nn.parent_id); }
|
|
370
437
|
await refreshPanel();
|
|
371
438
|
} else if (msg.name === 'newTodo') {
|
|
372
439
|
await joplin.commands.execute('newTodo');
|
|
440
|
+
var nt = await joplin.workspace.selectedNote();
|
|
441
|
+
if (nt) { selectedNoteId = nt.id; expandToFolder(nt.parent_id); }
|
|
373
442
|
await refreshPanel();
|
|
374
443
|
} else if (msg.name === 'search') {
|
|
375
444
|
var query = msg.query;
|
|
@@ -454,20 +523,32 @@ joplin.plugins.register({
|
|
|
454
523
|
var newNote = await joplin.data.post(['notes'], null, { title: t.newNote, parent_id: id });
|
|
455
524
|
await joplin.commands.execute('openNote', newNote.id);
|
|
456
525
|
selectedNoteId = newNote.id;
|
|
526
|
+
expandToFolder(id);
|
|
457
527
|
break;
|
|
458
528
|
case 'newTodo':
|
|
459
529
|
var newTodo = await joplin.data.post(['notes'], null, { title: t.newTodo, parent_id: id, is_todo: 1 });
|
|
460
530
|
await joplin.commands.execute('openNote', newTodo.id);
|
|
461
531
|
selectedNoteId = newTodo.id;
|
|
532
|
+
expandToFolder(id);
|
|
462
533
|
break;
|
|
463
534
|
case 'newSubNotebook':
|
|
464
|
-
|
|
535
|
+
var subName = await showNativeInput(t.newNotebook, '');
|
|
536
|
+
if (subName && subName.trim()) {
|
|
537
|
+
await joplin.data.post(['folders'], null, { title: subName.trim(), parent_id: id });
|
|
538
|
+
}
|
|
465
539
|
break;
|
|
466
540
|
case 'deleteFolder':
|
|
467
|
-
await joplin.data.
|
|
541
|
+
var folderInfo = await joplin.data.get(['folders', id], { fields: ['title'] });
|
|
542
|
+
if (await showNativeConfirm(t.confirmDeleteFolder + '\n\n' + folderInfo.title)) {
|
|
543
|
+
await joplin.data.delete(['folders', id]);
|
|
544
|
+
}
|
|
468
545
|
break;
|
|
469
546
|
case 'renameFolder':
|
|
470
|
-
|
|
547
|
+
var folderData = await joplin.data.get(['folders', id], { fields: ['title'] });
|
|
548
|
+
var newFolderName = await showNativeInput(t.promptRename, folderData.title);
|
|
549
|
+
if (newFolderName && newFolderName.trim()) {
|
|
550
|
+
await joplin.data.put(['folders', id], null, { title: newFolderName.trim() });
|
|
551
|
+
}
|
|
471
552
|
break;
|
|
472
553
|
case 'exportFolder':
|
|
473
554
|
try { await joplin.commands.execute('exportFolders', [id]); } catch(e) {}
|
|
@@ -515,7 +596,11 @@ joplin.plugins.register({
|
|
|
515
596
|
}
|
|
516
597
|
break;
|
|
517
598
|
case 'renameNote':
|
|
518
|
-
|
|
599
|
+
var noteData = await joplin.data.get(['notes', id], { fields: ['title'] });
|
|
600
|
+
var newNoteName = await showNativeInput(t.promptRename, noteData.title);
|
|
601
|
+
if (newNoteName && newNoteName.trim()) {
|
|
602
|
+
await joplin.data.put(['notes', id], null, { title: newNoteName.trim() });
|
|
603
|
+
}
|
|
519
604
|
break;
|
|
520
605
|
case 'moveNote':
|
|
521
606
|
if (msg.targetFolderName) {
|
|
@@ -531,21 +616,26 @@ joplin.plugins.register({
|
|
|
531
616
|
}
|
|
532
617
|
break;
|
|
533
618
|
case 'noteInfo':
|
|
534
|
-
var info = await joplin.data.get(['notes', id], { fields: ['id', 'title', 'created_time', 'updated_time', 'is_todo', 'parent_id'] });
|
|
535
|
-
var
|
|
619
|
+
var info = await joplin.data.get(['notes', id], { fields: ['id', 'title', 'created_time', 'updated_time', 'is_todo', 'parent_id', 'body'] });
|
|
620
|
+
var pTitle = '';
|
|
536
621
|
for (var i = 0; i < allFoldersCache.length; i++) {
|
|
537
|
-
if (allFoldersCache[i].id === info.parent_id) {
|
|
622
|
+
if (allFoldersCache[i].id === info.parent_id) { pTitle = allFoldersCache[i].title; break; }
|
|
538
623
|
}
|
|
539
|
-
var
|
|
540
|
-
|
|
541
|
-
+ '\
|
|
542
|
-
+ '\
|
|
543
|
-
+ '\
|
|
544
|
-
+ '\
|
|
545
|
-
|
|
546
|
-
|
|
624
|
+
var bodyLen = (info.body || '').length;
|
|
625
|
+
var infoBody = 'ID: ' + info.id
|
|
626
|
+
+ '\n' + (t.ctxRenameNote || 'Title') + ': ' + info.title
|
|
627
|
+
+ '\n' + (t.newNotebook || 'Notebook') + ': ' + pTitle
|
|
628
|
+
+ '\n' + (t.sortUpdatedDesc ? t.sortUpdatedDesc.replace(/[↓↑\u2193\u2191]\s*/, '') : 'Created') + ': ' + new Date(info.created_time).toLocaleString()
|
|
629
|
+
+ '\n' + (t.sortUpdatedAsc ? t.sortUpdatedAsc.replace(/[↓↑\u2193\u2191]\s*/, '') : 'Updated') + ': ' + new Date(info.updated_time).toLocaleString()
|
|
630
|
+
+ '\nType: ' + (info.is_todo ? 'To-do' : 'Note')
|
|
631
|
+
+ '\n' + 'Size: ' + bodyLen + ' chars';
|
|
632
|
+
await showNativeInfo(info.title, infoBody);
|
|
633
|
+
break;
|
|
547
634
|
case 'deleteNote':
|
|
548
|
-
await joplin.data.
|
|
635
|
+
var noteForDel = await joplin.data.get(['notes', id], { fields: ['title'] });
|
|
636
|
+
if (await showNativeConfirm(t.confirmDeleteNote + '\n\n' + noteForDel.title)) {
|
|
637
|
+
await joplin.data.delete(['notes', id]);
|
|
638
|
+
}
|
|
549
639
|
break;
|
|
550
640
|
}
|
|
551
641
|
}
|
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.1.
|
|
5
|
+
"version": "1.1.4",
|
|
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
|
|
@@ -408,9 +408,9 @@ html, body {
|
|
|
408
408
|
}
|
|
409
409
|
|
|
410
410
|
.inline-input-ok {
|
|
411
|
-
background:
|
|
411
|
+
background: #1a73e8 !important;
|
|
412
412
|
color: #fff !important;
|
|
413
|
-
border-color:
|
|
413
|
+
border-color: #1a73e8 !important;
|
|
414
414
|
}
|
|
415
415
|
|
|
416
416
|
.inline-input-buttons button:hover {
|
package/publish/webview/panel.js
CHANGED
|
@@ -150,7 +150,6 @@ document.addEventListener('contextmenu', function(e) {
|
|
|
150
150
|
menuHtml += '<div class="ctx-item" data-action="toggleTodo" data-id="' + id + '" data-type="note">' + T('ctxToggleTodo') + '</div>';
|
|
151
151
|
menuHtml += '<div class="ctx-sep"></div>';
|
|
152
152
|
menuHtml += '<div class="ctx-item" data-action="renameNote" data-id="' + id + '" data-type="note" data-title="' + title.replace(/"/g, '"') + '">' + T('ctxRenameNote') + '</div>';
|
|
153
|
-
menuHtml += '<div class="ctx-item" data-action="moveNote" data-id="' + id + '" data-type="note">' + T('ctxMoveNote') + '</div>';
|
|
154
153
|
menuHtml += '<div class="ctx-item" data-action="noteInfo" data-id="' + id + '" data-type="note">' + T('ctxNoteInfo') + '</div>';
|
|
155
154
|
menuHtml += '<div class="ctx-sep"></div>';
|
|
156
155
|
menuHtml += '<div class="ctx-item ctx-danger" data-action="deleteNote" data-id="' + id + '" data-type="note">' + T('ctxDeleteNote') + '</div>';
|
|
@@ -174,30 +173,8 @@ document.addEventListener('click', function(e) {
|
|
|
174
173
|
var id = ctxItem.dataset.id;
|
|
175
174
|
var itemType = ctxItem.dataset.type;
|
|
176
175
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
showInlineInput(T('promptRename'), currentTitle, function(newTitle) {
|
|
180
|
-
if (newTitle !== null && newTitle.trim() !== '') {
|
|
181
|
-
postMsg({ name: 'contextMenu', action: action, id: id, itemType: itemType, newTitle: newTitle.trim() });
|
|
182
|
-
}
|
|
183
|
-
});
|
|
184
|
-
} else if (action === 'deleteFolder') {
|
|
185
|
-
if (confirm(T('confirmDeleteFolder'))) {
|
|
186
|
-
postMsg({ name: 'contextMenu', action: action, id: id, itemType: itemType });
|
|
187
|
-
}
|
|
188
|
-
} else if (action === 'deleteNote') {
|
|
189
|
-
if (confirm(T('confirmDeleteNote'))) {
|
|
190
|
-
postMsg({ name: 'contextMenu', action: action, id: id, itemType: itemType });
|
|
191
|
-
}
|
|
192
|
-
} else if (action === 'moveNote') {
|
|
193
|
-
showInlineInput(T('promptMoveNote'), '', function(folderName) {
|
|
194
|
-
if (folderName !== null && folderName.trim() !== '') {
|
|
195
|
-
postMsg({ name: 'contextMenu', action: action, id: id, itemType: itemType, targetFolderName: folderName.trim() });
|
|
196
|
-
}
|
|
197
|
-
});
|
|
198
|
-
} else {
|
|
199
|
-
postMsg({ name: 'contextMenu', action: action, id: id, itemType: itemType });
|
|
200
|
-
}
|
|
176
|
+
// All dialogs handled by backend using native Joplin dialogs
|
|
177
|
+
postMsg({ name: 'contextMenu', action: action, id: id, itemType: itemType });
|
|
201
178
|
|
|
202
179
|
var menu = document.getElementById('ctx-menu');
|
|
203
180
|
if (menu) menu.remove();
|