diff --git a/package-lock.json b/package-lock.json
index a32cc9615..842410e2a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -12,6 +12,9 @@
"@braintree/sanitize-url": "7.1.1",
"@electron/remote": "2.1.2",
"@excalidraw/excalidraw": "0.17.6",
+ "@fullcalendar/core": "6.1.15",
+ "@fullcalendar/daygrid": "6.1.15",
+ "@fullcalendar/interaction": "6.1.15",
"@highlightjs/cdn-assets": "11.11.1",
"@joplin/turndown-plugin-gfm": "1.0.61",
"@mermaid-js/layout-elk": "0.1.7",
@@ -2124,6 +2127,43 @@
"react-dom": "^17.0.2 || ^18.2.0"
}
},
+ "node_modules/@fullcalendar/core": {
+ "version": "6.1.15",
+ "resolved": "https://registry.npmjs.org/@fullcalendar/core/-/core-6.1.15.tgz",
+ "integrity": "sha512-BuX7o6ALpLb84cMw1FCB9/cSgF4JbVO894cjJZ6kP74jzbUZNjtwffwRdA+Id8rrLjT30d/7TrkW90k4zbXB5Q==",
+ "license": "MIT",
+ "dependencies": {
+ "preact": "~10.12.1"
+ }
+ },
+ "node_modules/@fullcalendar/core/node_modules/preact": {
+ "version": "10.12.1",
+ "resolved": "https://registry.npmjs.org/preact/-/preact-10.12.1.tgz",
+ "integrity": "sha512-l8386ixSsBdbreOAkqtrwqHwdvR35ID8c3rKPa8lCWuO86dBi32QWHV4vfsZK1utLLFMvw+Z5Ad4XLkZzchscg==",
+ "license": "MIT",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/preact"
+ }
+ },
+ "node_modules/@fullcalendar/daygrid": {
+ "version": "6.1.15",
+ "resolved": "https://registry.npmjs.org/@fullcalendar/daygrid/-/daygrid-6.1.15.tgz",
+ "integrity": "sha512-j8tL0HhfiVsdtOCLfzK2J0RtSkiad3BYYemwQKq512cx6btz6ZZ2RNc/hVnIxluuWFyvx5sXZwoeTJsFSFTEFA==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@fullcalendar/core": "~6.1.15"
+ }
+ },
+ "node_modules/@fullcalendar/interaction": {
+ "version": "6.1.15",
+ "resolved": "https://registry.npmjs.org/@fullcalendar/interaction/-/interaction-6.1.15.tgz",
+ "integrity": "sha512-DOTSkofizM7QItjgu7W68TvKKvN9PSEEvDJceyMbQDvlXHa7pm/WAVtAc6xSDZ9xmB1QramYoWGLHkCYbTW1rQ==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@fullcalendar/core": "~6.1.15"
+ }
+ },
"node_modules/@gar/promisify": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz",
diff --git a/package.json b/package.json
index bd65afbd8..d48cdaf6e 100644
--- a/package.json
+++ b/package.json
@@ -70,6 +70,9 @@
"@braintree/sanitize-url": "7.1.1",
"@electron/remote": "2.1.2",
"@excalidraw/excalidraw": "0.17.6",
+ "@fullcalendar/core": "6.1.15",
+ "@fullcalendar/daygrid": "6.1.15",
+ "@fullcalendar/interaction": "6.1.15",
"@highlightjs/cdn-assets": "11.11.1",
"@joplin/turndown-plugin-gfm": "1.0.61",
"@mermaid-js/layout-elk": "0.1.7",
diff --git a/src/public/app/components/note_context.ts b/src/public/app/components/note_context.ts
index 7656894c9..6179ac57f 100644
--- a/src/public/app/components/note_context.ts
+++ b/src/public/app/components/note_context.ts
@@ -290,7 +290,7 @@ class NoteContext extends Component implements EventListener<"entitiesReloaded">
return (
this.note &&
["default", "contextual-help"].includes(this.viewScope?.viewMode ?? "") &&
- this.note.hasChildren() &&
+ (this.note.hasChildren() || this.note.getLabelValue("viewType") === "calendar") &&
["book", "text", "code"].includes(this.note.type) &&
this.note.mime !== "text/x-sqlite;schema=trilium" &&
!this.note.isLabelTruthy("hideChildrenOverview")
diff --git a/src/public/app/doc_notes/en/User Guide/!!!meta.json b/src/public/app/doc_notes/en/User Guide/!!!meta.json
index f7ee2b545..b90fd4f50 100644
--- a/src/public/app/doc_notes/en/User Guide/!!!meta.json
+++ b/src/public/app/doc_notes/en/User Guide/!!!meta.json
@@ -11,7 +11,7 @@
"title": "User Guide",
"notePosition": 20,
"prefix": null,
- "isExpanded": true,
+ "isExpanded": false,
"type": "text",
"mime": "text/html",
"attributes": [
@@ -166,7 +166,7 @@
"title": "Features",
"notePosition": 40,
"prefix": null,
- "isExpanded": false,
+ "isExpanded": true,
"type": "text",
"mime": "text/html",
"attributes": [],
@@ -314,7 +314,7 @@
"title": "Note Types",
"notePosition": 70,
"prefix": null,
- "isExpanded": false,
+ "isExpanded": true,
"type": "text",
"mime": "text/html",
"attributes": [],
@@ -536,6 +536,208 @@
"dataFileName": "19_Geo map_image.png"
}
]
+ },
+ {
+ "isClone": false,
+ "noteId": "pSDzQIgLGswQ",
+ "notePath": [
+ "OkOZllzB3fqN",
+ "wmegHv51MJMd",
+ "pSDzQIgLGswQ"
+ ],
+ "title": "Book",
+ "notePosition": 30,
+ "prefix": null,
+ "isExpanded": true,
+ "type": "text",
+ "mime": "text/html",
+ "attributes": [
+ {
+ "type": "label",
+ "name": "iconClass",
+ "value": "bx bx-book-alt",
+ "isInheritable": false,
+ "position": 10
+ }
+ ],
+ "format": "html",
+ "attachments": [],
+ "dirFileName": "Book",
+ "children": [
+ {
+ "isClone": false,
+ "noteId": "fDGg7QcJg3Xm",
+ "notePath": [
+ "OkOZllzB3fqN",
+ "wmegHv51MJMd",
+ "pSDzQIgLGswQ",
+ "fDGg7QcJg3Xm"
+ ],
+ "title": "Calendar View",
+ "notePosition": 10,
+ "prefix": null,
+ "isExpanded": false,
+ "type": "text",
+ "mime": "text/html",
+ "attributes": [
+ {
+ "type": "label",
+ "name": "iconClass",
+ "value": "bx bx-calendar",
+ "isInheritable": false,
+ "position": 10
+ }
+ ],
+ "format": "html",
+ "dataFileName": "Calendar View.html",
+ "attachments": [
+ {
+ "attachmentId": "j1NIQJvjsFrc",
+ "title": "image.png",
+ "role": "image",
+ "mime": "image/png",
+ "position": 10,
+ "dataFileName": "Calendar View_image.png"
+ },
+ {
+ "attachmentId": "9FxGltAPWr9V",
+ "title": "image.png",
+ "role": "image",
+ "mime": "image/png",
+ "position": 10,
+ "dataFileName": "1_Calendar View_image.png"
+ },
+ {
+ "attachmentId": "8kfaJPGjJ1t5",
+ "title": "image.png",
+ "role": "image",
+ "mime": "image/png",
+ "position": 10,
+ "dataFileName": "2_Calendar View_image.png"
+ },
+ {
+ "attachmentId": "GaH4K6lKfcQe",
+ "title": "image.png",
+ "role": "image",
+ "mime": "image/png",
+ "position": 10,
+ "dataFileName": "3_Calendar View_image.png"
+ },
+ {
+ "attachmentId": "xr4c0Mdf7gPm",
+ "title": "image.png",
+ "role": "image",
+ "mime": "image/png",
+ "position": 10,
+ "dataFileName": "4_Calendar View_image.png"
+ },
+ {
+ "attachmentId": "K8NQktF9sCss",
+ "title": "image.png",
+ "role": "image",
+ "mime": "image/png",
+ "position": 10,
+ "dataFileName": "5_Calendar View_image.png"
+ },
+ {
+ "attachmentId": "fFaq1mWTFlJA",
+ "title": "image.png",
+ "role": "image",
+ "mime": "image/png",
+ "position": 10,
+ "dataFileName": "6_Calendar View_image.png"
+ },
+ {
+ "attachmentId": "2CExLYphNtCd",
+ "title": "image.png",
+ "role": "image",
+ "mime": "image/png",
+ "position": 10,
+ "dataFileName": "7_Calendar View_image.png"
+ },
+ {
+ "attachmentId": "UaXBPb7fINm4",
+ "title": "image.png",
+ "role": "image",
+ "mime": "image/png",
+ "position": 10,
+ "dataFileName": "8_Calendar View_image.png"
+ },
+ {
+ "attachmentId": "TIzqtnGIPlxu",
+ "title": "image.png",
+ "role": "image",
+ "mime": "image/png",
+ "position": 10,
+ "dataFileName": "9_Calendar View_image.png"
+ },
+ {
+ "attachmentId": "p7eRe4TFFdIt",
+ "title": "image.png",
+ "role": "image",
+ "mime": "image/png",
+ "position": 10,
+ "dataFileName": "10_Calendar View_image.png"
+ },
+ {
+ "attachmentId": "bnKESYv4Toa1",
+ "title": "image.png",
+ "role": "image",
+ "mime": "image/png",
+ "position": 10,
+ "dataFileName": "11_Calendar View_image.png"
+ },
+ {
+ "attachmentId": "MwECr6EjQjEE",
+ "title": "image.png",
+ "role": "image",
+ "mime": "image/png",
+ "position": 10,
+ "dataFileName": "12_Calendar View_image.png"
+ },
+ {
+ "attachmentId": "0J8MfQPq7E1H",
+ "title": "image.png",
+ "role": "image",
+ "mime": "image/png",
+ "position": 10,
+ "dataFileName": "13_Calendar View_image.png"
+ },
+ {
+ "attachmentId": "0yGXmgB3yfGg",
+ "title": "image.png",
+ "role": "image",
+ "mime": "image/png",
+ "position": 10,
+ "dataFileName": "14_Calendar View_image.png"
+ },
+ {
+ "attachmentId": "XBOyB2RH28OS",
+ "title": "image.png",
+ "role": "image",
+ "mime": "image/png",
+ "position": 10,
+ "dataFileName": "15_Calendar View_image.png"
+ },
+ {
+ "attachmentId": "BsiAqW51VJOz",
+ "title": "image.png",
+ "role": "image",
+ "mime": "image/png",
+ "position": 10,
+ "dataFileName": "16_Calendar View_image.png"
+ },
+ {
+ "attachmentId": "RTFdV19BHn28",
+ "title": "image.png",
+ "role": "image",
+ "mime": "image/png",
+ "position": 10,
+ "dataFileName": "17_Calendar View_image.png"
+ }
+ ]
+ }
+ ]
}
]
},
@@ -624,7 +826,7 @@
"title": "Examples",
"notePosition": 10,
"prefix": null,
- "isExpanded": true,
+ "isExpanded": false,
"type": "text",
"mime": "text/html",
"attributes": [],
@@ -895,7 +1097,7 @@
"title": "ETAPI",
"notePosition": 10,
"prefix": null,
- "isExpanded": true,
+ "isExpanded": false,
"type": "text",
"mime": "text/html",
"attributes": [],
@@ -945,7 +1147,7 @@
"title": "Internal API",
"notePosition": 20,
"prefix": null,
- "isExpanded": true,
+ "isExpanded": false,
"type": "text",
"mime": "text/html",
"attributes": [],
diff --git a/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Book/10_Calendar View_image.png b/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Book/10_Calendar View_image.png
new file mode 100644
index 000000000..f60aa0acc
Binary files /dev/null and b/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Book/10_Calendar View_image.png differ
diff --git a/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Book/11_Calendar View_image.png b/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Book/11_Calendar View_image.png
new file mode 100644
index 000000000..7e97245a6
Binary files /dev/null and b/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Book/11_Calendar View_image.png differ
diff --git a/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Book/12_Calendar View_image.png b/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Book/12_Calendar View_image.png
new file mode 100644
index 000000000..b594af6a6
Binary files /dev/null and b/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Book/12_Calendar View_image.png differ
diff --git a/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Book/13_Calendar View_image.png b/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Book/13_Calendar View_image.png
new file mode 100644
index 000000000..d3d64f75c
Binary files /dev/null and b/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Book/13_Calendar View_image.png differ
diff --git a/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Book/14_Calendar View_image.png b/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Book/14_Calendar View_image.png
new file mode 100644
index 000000000..d588ed568
Binary files /dev/null and b/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Book/14_Calendar View_image.png differ
diff --git a/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Book/15_Calendar View_image.png b/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Book/15_Calendar View_image.png
new file mode 100644
index 000000000..71f7d2dc3
Binary files /dev/null and b/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Book/15_Calendar View_image.png differ
diff --git a/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Book/16_Calendar View_image.png b/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Book/16_Calendar View_image.png
new file mode 100644
index 000000000..46698faac
Binary files /dev/null and b/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Book/16_Calendar View_image.png differ
diff --git a/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Book/17_Calendar View_image.png b/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Book/17_Calendar View_image.png
new file mode 100644
index 000000000..fceb0563c
Binary files /dev/null and b/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Book/17_Calendar View_image.png differ
diff --git a/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Book/1_Calendar View_image.png b/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Book/1_Calendar View_image.png
new file mode 100644
index 000000000..71d6c38f1
Binary files /dev/null and b/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Book/1_Calendar View_image.png differ
diff --git a/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Book/2_Calendar View_image.png b/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Book/2_Calendar View_image.png
new file mode 100644
index 000000000..d8d8f87c1
Binary files /dev/null and b/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Book/2_Calendar View_image.png differ
diff --git a/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Book/3_Calendar View_image.png b/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Book/3_Calendar View_image.png
new file mode 100644
index 000000000..052cddb18
Binary files /dev/null and b/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Book/3_Calendar View_image.png differ
diff --git a/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Book/4_Calendar View_image.png b/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Book/4_Calendar View_image.png
new file mode 100644
index 000000000..bec9d93e1
Binary files /dev/null and b/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Book/4_Calendar View_image.png differ
diff --git a/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Book/5_Calendar View_image.png b/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Book/5_Calendar View_image.png
new file mode 100644
index 000000000..acf382206
Binary files /dev/null and b/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Book/5_Calendar View_image.png differ
diff --git a/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Book/6_Calendar View_image.png b/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Book/6_Calendar View_image.png
new file mode 100644
index 000000000..57964953a
Binary files /dev/null and b/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Book/6_Calendar View_image.png differ
diff --git a/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Book/7_Calendar View_image.png b/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Book/7_Calendar View_image.png
new file mode 100644
index 000000000..53ac5632f
Binary files /dev/null and b/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Book/7_Calendar View_image.png differ
diff --git a/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Book/8_Calendar View_image.png b/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Book/8_Calendar View_image.png
new file mode 100644
index 000000000..aa9e445ad
Binary files /dev/null and b/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Book/8_Calendar View_image.png differ
diff --git a/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Book/9_Calendar View_image.png b/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Book/9_Calendar View_image.png
new file mode 100644
index 000000000..e050184a7
Binary files /dev/null and b/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Book/9_Calendar View_image.png differ
diff --git a/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Book/Calendar View.html b/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Book/Calendar View.html
new file mode 100644
index 000000000..d5364a1e9
--- /dev/null
+++ b/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Book/Calendar View.html
@@ -0,0 +1,192 @@
+
+
+
+
+
+
+
+ Calendar View
+
+
+
+
+
Calendar View
+
+
+
+
+
+
The Calendar view of Book notes will display each child note in a calendar
+ that has a start date and optionally an end date, as an event.
+
Unlike other Book view types, the Calendar view also allows some kind
+ of interaction, such as moving events around as well as creating new ones.
+
Creating a calendar
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+ The Calendar View works only for Book note types. To create a new note,
+ right click on the note tree on the left and select Insert note after,
+ or Insert child note and then select Book .
+
+
+
+
+ 2
+
+
+
+
+
+ Once created, the “View type” of the Book needs changed to “Calendar”,
+ by selecting the “Book Properties” tab in the ribbon.
+
+
+
+
+
Creating a new event/note
+
+ Clicking on a day will create a new child note and assign it to that particular
+ day.
+
+ You will be asked for the name of the new note. If the popup is dismissed
+ by pressing the close button or escape, then the note will not be created.
+
+
+ It's possible to drag across multiple days to set both the start and end
+ date of a particular note.
+
+
+
+
+
Interacting with events
+
+ Hovering the mouse over an event will display information about the note.
+
+
+
+ Left clicking the event will go to that note. Middle clicking will open
+ the note in a new tab and right click will offer more options including
+ opening the note in a new split or window.
+ Drag and drop an event on the calendar to move it to another day.
+ The length of an event can be changed by placing the mouse to the right
+ edge of the event and dragging the mouse around.
+
+
Configuring the calendar
+
+ The first day of the week can be either Sunday or Monday and can be adjusted
+ from the application settings.
+
+
How the calendar works
+
+ The calendar displays all the child notes of the book that have a #startDate
.
+ An #endDate
can optionally be added.
+
If editing the start date and end date from the note itself is desirable,
+ the following attributes can be added to the book note:
#viewType=calendar #label:startDate(inheritable)="promoted,alias=Start Date,single,date" #label:endDate(inheritable)="promoted,alias=End Date,single,date" #hidePromotedAttributes
+
This will result in:
+
+
+
+
Advanced use-cases
+
Using a different attribute as event title
+
By default, events are displayed on the calendar by their note title.
+ However, it is possible to configure a different attribute to be displayed
+ instead.
+
To do so, assign #calendar:title
to the child note (not the
+ calendar/book note), with the value being #name
where name
can
+ be any label. The attribute can also come through inheritance such as a
+ template attribute. If the note does not have the requested label, the
+ title of the note will be used instead.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Using a relation attribute as event title
+
Similarly to using an attribute, use #calendar:title
and set
+ it to ~name
where name
is the name of the relation
+ to use.
+
Moreover, if there are more relations of the same name, they will be displayed
+ as multiple events coming from the same note.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Note that it's even possible to have a #calendar:title
on the
+ target note (e.g. “John Smith”) which will try to render an attribute of
+ it. Note that it's not possible to use a relation here as well for safety
+ reasons (an accidental recursion of attributes could cause the application
+ to loop infinitely).
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Book/Calendar View_image.png b/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Book/Calendar View_image.png
new file mode 100644
index 000000000..d46f327a2
Binary files /dev/null and b/src/public/app/doc_notes/en/User Guide/User Guide/Note Types/Book/Calendar View_image.png differ
diff --git a/src/public/app/doc_notes/en/User Guide/navigation.html b/src/public/app/doc_notes/en/User Guide/navigation.html
index 77cf9ca53..85143e944 100644
--- a/src/public/app/doc_notes/en/User Guide/navigation.html
+++ b/src/public/app/doc_notes/en/User Guide/navigation.html
@@ -29,6 +29,12 @@
Geo map
+ Book
+
+
Shared notes
diff --git a/src/public/app/layouts/mobile_layout.ts b/src/public/app/layouts/mobile_layout.ts
index a98b3df29..51609ce32 100644
--- a/src/public/app/layouts/mobile_layout.ts
+++ b/src/public/app/layouts/mobile_layout.ts
@@ -31,6 +31,7 @@ import type AppContext from "../components/app_context.js";
import TabRowWidget from "../widgets/tab_row.js";
import JumpToNoteDialog from "../widgets/dialogs/jump_to_note.js";
import RecentChangesDialog from "../widgets/dialogs/recent_changes.js";
+import PromptDialog from "../widgets/dialogs/prompt.js";
const MOBILE_CSS = `
-
-
-`;
-
-class NoteListRenderer {
- private $noteList: JQuery;
-
- private parentNote: FNote;
- private noteIds: string[];
- private page?: number;
- private pageSize?: number;
- private viewType?: string | null;
- private showNotePath?: boolean;
- private highlightRegex?: RegExp | null;
-
- /*
- * We're using noteIds so that it's not necessary to load all notes at once when paging
- */
constructor($parent: JQuery, parentNote: FNote, noteIds: string[], showNotePath: boolean = false) {
- this.$noteList = $(TPL);
-
- // note list must be added to the DOM immediately, otherwise some functionality scripting (canvas) won't work
- $parent.empty();
-
- this.parentNote = parentNote;
- const includedNoteIds = this.getIncludedNoteIds();
-
- this.noteIds = noteIds.filter((noteId) => !includedNoteIds.has(noteId) && noteId !== "_hidden");
-
- if (this.noteIds.length === 0) {
- return;
+ this.viewType = this.#getViewType(parentNote);
+ const args: ViewModeArgs = {
+ $parent,
+ parentNote,
+ noteIds,
+ showNotePath
}
- $parent.append(this.$noteList);
-
- this.page = 1;
- this.pageSize = parseInt(parentNote.getLabelValue("pageSize") || "");
-
- if (!this.pageSize || this.pageSize < 1) {
- this.pageSize = 20;
+ if (this.viewType === "list" || this.viewType === "grid") {
+ this.viewMode = new ListOrGridView(this.viewType, args);
+ } else if (this.viewType === "calendar") {
+ this.viewMode = new CalendarView(args);
+ } else {
+ this.viewMode = null;
}
-
- this.viewType = parentNote.getLabelValue("viewType");
-
- if (!["list", "grid"].includes(this.viewType || "")) {
- // when not explicitly set, decide based on the note type
- this.viewType = parentNote.type === "search" ? "list" : "grid";
- }
-
- this.$noteList.addClass(`${this.viewType}-view`);
-
- this.showNotePath = showNotePath;
}
- /** @returns {Set} list of noteIds included (images, included notes) in the parent note and which
- * don't have to be shown in the note list. */
- getIncludedNoteIds() {
- const includedLinks = this.parentNote ? this.parentNote.getRelations().filter((rel) => rel.name === "imageLink" || rel.name === "includeNoteLink") : [];
+ #getViewType(parentNote: FNote): ViewTypeOptions {
+ const viewType = parentNote.getLabelValue("viewType");
- return new Set(includedLinks.map((rel) => rel.value));
+ if (!["list", "grid", "calendar"].includes(viewType || "")) {
+ // when not explicitly set, decide based on the note type
+ return parentNote.type === "search" ? "list" : "grid";
+ } else {
+ return viewType as ViewTypeOptions;
+ }
}
async renderList() {
- if (this.noteIds.length === 0 || !this.page || !this.pageSize) {
- this.$noteList.hide();
- return;
+ if (!this.viewMode) {
+ return null;
}
- const highlightedTokens = this.parentNote.highlightedTokens || [];
- if (highlightedTokens.length > 0) {
- await libraryLoader.requireLibrary(libraryLoader.MARKJS);
-
- const regex = highlightedTokens.map((token) => utils.escapeRegExp(token)).join("|");
-
- this.highlightRegex = new RegExp(regex, "gi");
- } else {
- this.highlightRegex = null;
- }
-
- this.$noteList.show();
-
- const $container = this.$noteList.find(".note-list-container").empty();
-
- const startIdx = (this.page - 1) * this.pageSize;
- const endIdx = startIdx + this.pageSize;
-
- const pageNoteIds = this.noteIds.slice(startIdx, Math.min(endIdx, this.noteIds.length));
- const pageNotes = await froca.getNotes(pageNoteIds);
-
- for (const note of pageNotes) {
- const $card = await this.renderNote(note, this.parentNote.isLabelTruthy("expanded"));
-
- $container.append($card);
- }
-
- this.renderPager();
-
- return this.$noteList;
+ return await this.viewMode.renderList();
}
- renderPager() {
- const $pager = this.$noteList.find(".note-list-pager").empty();
- if (!this.page || !this.pageSize) {
- return;
- }
-
- const pageCount = Math.ceil(this.noteIds.length / this.pageSize);
-
- $pager.toggle(pageCount > 1);
-
- let lastPrinted;
-
- for (let i = 1; i <= pageCount; i++) {
- if (pageCount < 20 || i <= 5 || pageCount - i <= 5 || Math.abs(this.page - i) <= 2) {
- lastPrinted = true;
-
- const startIndex = (i - 1) * this.pageSize + 1;
- const endIndex = Math.min(this.noteIds.length, i * this.pageSize);
-
- $pager.append(
- i === this.page
- ? $("").text(i).css("text-decoration", "underline").css("font-weight", "bold")
- : $('')
- .text(i)
- .attr("title", `Page of ${startIndex} - ${endIndex}`)
- .on("click", () => {
- this.page = i;
- this.renderList();
- }),
- " "
- );
- } else if (lastPrinted) {
- $pager.append("... ");
-
- lastPrinted = false;
- }
- }
-
- // no need to distinguish "note" vs "notes" since in case of one result, there's no paging at all
- $pager.append(``);
- }
-
- async renderNote(note: FNote, expand: boolean = false) {
- const $expander = $(' ');
-
- const { $renderedAttributes } = await attributeRenderer.renderNormalAttributes(note);
- const notePath =
- this.parentNote.type === "search"
- ? note.noteId // for search note parent, we want to display a non-search path
- : `${this.parentNote.noteId}/${note.noteId}`;
-
- const $card = $('')
- .attr("data-note-id", note.noteId)
- .append(
- $('