add: recent notes in note picker

This commit is contained in:
windingwind 2024-08-23 21:20:53 +08:00
parent 60a5ea8974
commit a0489f733d
4 changed files with 136 additions and 7 deletions

View File

@ -33,4 +33,12 @@ bn-note-picker {
min-width: 200px; min-width: 200px;
max-height: 50%; max-height: 50%;
} }
.bn-note-list-container {
width: 100%;
}
#bn-select-recent-notes-content {
border-left: var(--material-border-quarternary);
}
} }

View File

@ -67,6 +67,7 @@ export class InboundCreator extends PluginCEBase {
async accept(io: any) { async accept(io: any) {
if (!this.targetNote) return; if (!this.targetNote) return;
const content = await this.getContentToInsert(); const content = await this.getContentToInsert();
this.notePicker.saveRecentNotes();
io.targetNoteID = this.targetNote.id; io.targetNoteID = this.targetNote.id;
io.content = content; io.content = content;

View File

@ -2,6 +2,7 @@ import { config } from "../../../package.json";
import { VirtualizedTableHelper } from "zotero-plugin-toolkit/dist/helpers/virtualizedTable"; import { VirtualizedTableHelper } from "zotero-plugin-toolkit/dist/helpers/virtualizedTable";
import { PluginCEBase } from "../base"; import { PluginCEBase } from "../base";
import { import {
getPref,
getPrefJSON, getPrefJSON,
registerPrefObserver, registerPrefObserver,
setPref, setPref,
@ -19,12 +20,15 @@ export class NotePicker extends PluginCEBase {
itemsView!: _ZoteroTypes.ItemTree; itemsView!: _ZoteroTypes.ItemTree;
collectionsView!: _ZoteroTypes.CollectionTree; collectionsView!: _ZoteroTypes.CollectionTree;
openedNotesView!: VirtualizedTableHelper; openedNotesView!: VirtualizedTableHelper;
recentNotesView!: VirtualizedTableHelper;
_collectionsList!: XUL.Box; _collectionsList!: XUL.Box;
openedNotes: Zotero.Item[] = []; openedNotes: Zotero.Item[] = [];
activeSelectionType: "library" | "tabs" | "none" = "none"; recentNotes: Zotero.Item[] = [];
activeSelectionType: "library" | "tabs" | "recent" | "none" = "none";
uid = Zotero.Utilities.randomString(8); uid = Zotero.Utilities.randomString(8);
@ -62,14 +66,20 @@ export class NotePicker extends PluginCEBase {
<html:div id="zotero-items-tree"></html:div> <html:div id="zotero-items-tree"></html:div>
</hbox> </hbox>
</hbox> </hbox>
<vbox id="bn-select-opened-notes-container" class="container"> <hbox id="bn-select-opened-notes-container" class="container">
<vbox <vbox
id="bn-select-opened-notes-content" id="bn-select-opened-notes-content"
class="container virtualized-table-container" class="container virtualized-table-container bn-note-list-container"
> >
<html:div id="bn-select-opened-notes-tree-${this.uid}"></html:div> <html:div id="bn-select-opened-notes-tree-${this.uid}"></html:div>
</vbox> </vbox>
</vbox> <vbox
id="bn-select-recent-notes-content"
class="container virtualized-table-container bn-note-list-container"
>
<html:div id="bn-select-recent-notes-tree-${this.uid}"></html:div>
</vbox>
</hbox>
</vbox> </vbox>
</vbox> </vbox>
</vbox> </vbox>
@ -118,6 +128,10 @@ export class NotePicker extends PluginCEBase {
await this.loadLibraryNotes(); await this.loadLibraryNotes();
this.loadQuickSearch(); this.loadQuickSearch();
await this.loadOpenedNotes(); await this.loadOpenedNotes();
this.recentNotes = this.getRecentNotes();
await this.loadRecentNotes();
} }
async loadLibraryNotes() { async loadLibraryNotes() {
@ -250,6 +264,78 @@ export class NotePicker extends PluginCEBase {
// } // }
} }
async loadRecentNotes() {
const renderLock = Zotero.Promise.defer();
this.recentNotesView = new VirtualizedTableHelper(window)
.setContainerId(`bn-select-recent-notes-tree-${this.uid}`)
.setProp({
id: `bn-select-recent-notes-table-${this.uid}`,
columns: [
{
dataKey: "title",
label: "Recent Notes",
flex: 1,
},
],
showHeader: true,
multiSelect: false,
staticColumns: true,
disableFontSizeScaling: true,
})
.setProp("getRowCount", () => this.recentNotes.length || 0)
.setProp("getRowData", (index) => {
const note = this.recentNotes[index];
return {
title: note.getNoteTitle(),
};
})
.setProp("onSelectionChange", (selection) => {
this.onRecentNoteSelected(selection);
})
// For find-as-you-type
.setProp(
"getRowString",
(index) => this.recentNotes[index].getNoteTitle() || "",
)
.setProp("renderItem", (index, selection, oldElem, columns) => {
let div;
if (oldElem) {
div = oldElem;
div.innerHTML = "";
} else {
div = document.createElement("div");
div.className = "row";
}
div.classList.toggle("selected", selection.isSelected(index));
div.classList.toggle("focused", selection.focused == index);
const rowData = this.recentNotes[index];
for (const column of columns) {
const span = document.createElement("span");
// @ts-ignore
span.className = `cell ${column?.className}`;
span.textContent = rowData.getNoteTitle();
const icon = getCSSItemTypeIcon("note");
icon.classList.add("cell-icon");
span.prepend(icon);
div.append(span);
}
return div;
})
.render(-1, () => {
renderLock.resolve();
});
await renderLock.promise;
if (this.recentNotes.length > 0) {
setTimeout(() => {
this.recentNotesView.treeInstance.selection.select(0);
this.onRecentNoteSelected(this.recentNotesView.treeInstance.selection);
}, 200);
}
}
onSearch() { onSearch() {
if (this.itemsView) { if (this.itemsView) {
const searchVal = ( const searchVal = (
@ -316,6 +402,33 @@ export class NotePicker extends PluginCEBase {
this.dispatchSelectionChange(selection); this.dispatchSelectionChange(selection);
} }
onRecentNoteSelected(selection: { selected: Set<number> }) {
this.activeSelectionType = "recent";
this.dispatchSelectionChange(selection);
}
getRecentNotes() {
return ((getPref("linkCreator.recentNotes") as string) || "")
.split(",")
.map((id) => Zotero.Items.get(parseInt(id)))
.filter((item) => item && item.isNote());
}
saveRecentNotes() {
const selectedNotes = this.getSelectedNotes();
if (!selectedNotes.length) {
return;
}
const recentNotes: number[] = [...selectedNotes.map((note) => note.id)];
for (const note of this.recentNotes) {
if (!recentNotes.includes(note.id)) {
recentNotes.push(note.id);
}
}
// Save only 10 recent notes
setPref("linkCreator.recentNotes", recentNotes.slice(0, 10).join(","));
}
dispatchSelectionChange(selection?: { selected: Set<number> }) { dispatchSelectionChange(selection?: { selected: Set<number> }) {
this.dispatchEvent( this.dispatchEvent(
new CustomEvent("selectionchange", { new CustomEvent("selectionchange", {
@ -331,10 +444,16 @@ export class NotePicker extends PluginCEBase {
return []; return [];
} else if (this.activeSelectionType == "library") { } else if (this.activeSelectionType == "library") {
return this.itemsView.getSelectedItems(); return this.itemsView.getSelectedItems();
} else if (this.activeSelectionType == "tabs") {
return Array.from(
(selection || this.openedNotesView.treeInstance.selection).selected,
).map((index) => this.openedNotes[index]);
} else if (this.activeSelectionType == "recent") {
return Array.from(
(selection || this.recentNotesView.treeInstance.selection).selected,
).map((index) => this.recentNotes[index]);
} }
return Array.from( return [];
(selection || this.openedNotesView.treeInstance.selection).selected,
).map((index) => this.openedNotes[index]);
} }
_persistState() { _persistState() {

View File

@ -70,6 +70,7 @@ export class OutboundCreator extends PluginCEBase {
async accept(io: any) { async accept(io: any) {
if (!this.targetNote) return; if (!this.targetNote) return;
const content = await this.getContentToInsert(); const content = await this.getContentToInsert();
this.notePicker.saveRecentNotes();
io.targetNoteID = this.currentNote!.id; io.targetNoteID = this.currentNote!.id;
io.content = content; io.content = content;