From a0489f733d66ef52bfbb7d8eea46df3db7bac994 Mon Sep 17 00:00:00 2001
From: windingwind <33902321+windingwind@users.noreply.github.com>
Date: Fri, 23 Aug 2024 21:20:53 +0800
Subject: [PATCH] add: recent notes in note picker
---
.../content/styles/linkCreator/notePicker.css | 8 ++
src/elements/linkCreator/inboundCreator.ts | 1 +
src/elements/linkCreator/notePicker.ts | 133 +++++++++++++++++-
src/elements/linkCreator/outboundCreator.ts | 1 +
4 files changed, 136 insertions(+), 7 deletions(-)
diff --git a/addon/chrome/content/styles/linkCreator/notePicker.css b/addon/chrome/content/styles/linkCreator/notePicker.css
index 99c19d7..fa51ac0 100644
--- a/addon/chrome/content/styles/linkCreator/notePicker.css
+++ b/addon/chrome/content/styles/linkCreator/notePicker.css
@@ -33,4 +33,12 @@ bn-note-picker {
min-width: 200px;
max-height: 50%;
}
+
+ .bn-note-list-container {
+ width: 100%;
+ }
+
+ #bn-select-recent-notes-content {
+ border-left: var(--material-border-quarternary);
+ }
}
diff --git a/src/elements/linkCreator/inboundCreator.ts b/src/elements/linkCreator/inboundCreator.ts
index 320c56b..d46df2c 100644
--- a/src/elements/linkCreator/inboundCreator.ts
+++ b/src/elements/linkCreator/inboundCreator.ts
@@ -67,6 +67,7 @@ export class InboundCreator extends PluginCEBase {
async accept(io: any) {
if (!this.targetNote) return;
const content = await this.getContentToInsert();
+ this.notePicker.saveRecentNotes();
io.targetNoteID = this.targetNote.id;
io.content = content;
diff --git a/src/elements/linkCreator/notePicker.ts b/src/elements/linkCreator/notePicker.ts
index 3d12439..b010754 100644
--- a/src/elements/linkCreator/notePicker.ts
+++ b/src/elements/linkCreator/notePicker.ts
@@ -2,6 +2,7 @@ import { config } from "../../../package.json";
import { VirtualizedTableHelper } from "zotero-plugin-toolkit/dist/helpers/virtualizedTable";
import { PluginCEBase } from "../base";
import {
+ getPref,
getPrefJSON,
registerPrefObserver,
setPref,
@@ -19,12 +20,15 @@ export class NotePicker extends PluginCEBase {
itemsView!: _ZoteroTypes.ItemTree;
collectionsView!: _ZoteroTypes.CollectionTree;
openedNotesView!: VirtualizedTableHelper;
+ recentNotesView!: VirtualizedTableHelper;
_collectionsList!: XUL.Box;
openedNotes: Zotero.Item[] = [];
- activeSelectionType: "library" | "tabs" | "none" = "none";
+ recentNotes: Zotero.Item[] = [];
+
+ activeSelectionType: "library" | "tabs" | "recent" | "none" = "none";
uid = Zotero.Utilities.randomString(8);
@@ -62,14 +66,20 @@ export class NotePicker extends PluginCEBase {
-
+
-
+
+
+
+
@@ -118,6 +128,10 @@ export class NotePicker extends PluginCEBase {
await this.loadLibraryNotes();
this.loadQuickSearch();
await this.loadOpenedNotes();
+
+ this.recentNotes = this.getRecentNotes();
+
+ await this.loadRecentNotes();
}
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() {
if (this.itemsView) {
const searchVal = (
@@ -316,6 +402,33 @@ export class NotePicker extends PluginCEBase {
this.dispatchSelectionChange(selection);
}
+ onRecentNoteSelected(selection: { selected: Set }) {
+ 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 }) {
this.dispatchEvent(
new CustomEvent("selectionchange", {
@@ -331,10 +444,16 @@ export class NotePicker extends PluginCEBase {
return [];
} else if (this.activeSelectionType == "library") {
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(
- (selection || this.openedNotesView.treeInstance.selection).selected,
- ).map((index) => this.openedNotes[index]);
+ return [];
}
_persistState() {
diff --git a/src/elements/linkCreator/outboundCreator.ts b/src/elements/linkCreator/outboundCreator.ts
index 5d38625..e19b61b 100644
--- a/src/elements/linkCreator/outboundCreator.ts
+++ b/src/elements/linkCreator/outboundCreator.ts
@@ -70,6 +70,7 @@ export class OutboundCreator extends PluginCEBase {
async accept(io: any) {
if (!this.targetNote) return;
const content = await this.getContentToInsert();
+ this.notePicker.saveRecentNotes();
io.targetNoteID = this.currentNote!.id;
io.content = content;