chore(client/ts): port services/note_list_renderer

This commit is contained in:
Elian Doran 2024-12-23 11:00:10 +02:00
parent 9bdee7afff
commit 838dc521b1
No known key found for this signature in database
5 changed files with 48 additions and 26 deletions

View File

@ -89,7 +89,7 @@ class FNote {
// Managed by Froca. // Managed by Froca.
searchResultsLoaded?: boolean; searchResultsLoaded?: boolean;
highlightedTokens?: unknown; highlightedTokens?: string[];
constructor(froca: Froca, row: FNoteRow) { constructor(froca: Froca, row: FNoteRow) {
this.froca = froca; this.froca = froca;
@ -111,7 +111,7 @@ class FNote {
this.title = row.title; this.title = row.title;
this.isProtected = !!row.isProtected; this.isProtected = !!row.isProtected;
this.type = row.type; this.type = row.type;
this.mime = row.mime; this.mime = row.mime;
this.blobId = row.blobId; this.blobId = row.blobId;
@ -478,7 +478,7 @@ class FNote {
return true; return true;
} }
/** /**
* @private * @private
*/ */
__filterAttrs(attributes: FAttribute[], type?: AttributeType, name?: string): FAttribute[] { __filterAttrs(attributes: FAttribute[], type?: AttributeType, name?: string): FAttribute[] {
@ -602,7 +602,7 @@ class FNote {
* @param [name] - relation name to filter * @param [name] - relation name to filter
* @returns all note's relations (attributes with type relation), including inherited ones * @returns all note's relations (attributes with type relation), including inherited ones
*/ */
getRelations(name: string) { getRelations(name?: string) {
return this.getAttributes(RELATION, name); return this.getAttributes(RELATION, name);
} }

View File

@ -231,14 +231,14 @@ function parseNavigationStateFromUrl(url: string | undefined) {
}; };
} }
function goToLink(evt: MouseEvent) { function goToLink(evt: MouseEvent | JQuery.ClickEvent) {
const $link = $(evt.target as any).closest("a,.block-link"); const $link = $(evt.target as any).closest("a,.block-link");
const hrefLink = $link.attr('href') || $link.attr('data-href'); const hrefLink = $link.attr('href') || $link.attr('data-href');
return goToLinkExt(evt, hrefLink, $link); return goToLinkExt(evt, hrefLink, $link);
} }
function goToLinkExt(evt: MouseEvent, hrefLink: string | undefined, $link: JQuery<HTMLElement>) { function goToLinkExt(evt: MouseEvent | JQuery.ClickEvent, hrefLink: string | undefined, $link: JQuery<HTMLElement>) {
if (hrefLink?.startsWith("data:")) { if (hrefLink?.startsWith("data:")) {
return true; return true;
} }

View File

@ -5,6 +5,7 @@ import attributeRenderer from "./attribute_renderer.js";
import libraryLoader from "./library_loader.js"; import libraryLoader from "./library_loader.js";
import treeService from "./tree.js"; import treeService from "./tree.js";
import utils from "./utils.js"; import utils from "./utils.js";
import FNote from "../entities/fnote.js";
const TPL = ` const TPL = `
<div class="note-list"> <div class="note-list">
@ -32,7 +33,7 @@ const TPL = `
.note-list.grid-view .note-book-card { .note-list.grid-view .note-book-card {
max-height: 300px; max-height: 300px;
} }
.note-list.grid-view .note-book-card img { .note-list.grid-view .note-book-card img {
max-height: 220px; max-height: 220px;
object-fit: contain; object-fit: contain;
@ -157,10 +158,21 @@ const TPL = `
</div>`; </div>`;
class NoteListRenderer { class NoteListRenderer {
private $noteList: JQuery<HTMLElement>;
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 * We're using noteIds so that it's not necessary to load all notes at once when paging
*/ */
constructor($parent, parentNote, noteIds, showNotePath = false) { constructor($parent: JQuery<HTMLElement>, parentNote: FNote, noteIds: string[], showNotePath: boolean = false) {
this.$noteList = $(TPL); this.$noteList = $(TPL);
// note list must be added to the DOM immediately, otherwise some functionality scripting (canvas) won't work // note list must be added to the DOM immediately, otherwise some functionality scripting (canvas) won't work
@ -178,7 +190,7 @@ class NoteListRenderer {
$parent.append(this.$noteList); $parent.append(this.$noteList);
this.page = 1; this.page = 1;
this.pageSize = parseInt(parentNote.getLabelValue('pageSize')); this.pageSize = parseInt(parentNote.getLabelValue('pageSize') || "");
if (!this.pageSize || this.pageSize < 1) { if (!this.pageSize || this.pageSize < 1) {
this.pageSize = 20; this.pageSize = 20;
@ -186,7 +198,7 @@ class NoteListRenderer {
this.viewType = parentNote.getLabelValue('viewType'); this.viewType = parentNote.getLabelValue('viewType');
if (!['list', 'grid'].includes(this.viewType)) { if (!['list', 'grid'].includes(this.viewType || "")) {
// when not explicitly set, decide based on the note type // when not explicitly set, decide based on the note type
this.viewType = parentNote.type === 'search' ? 'list' : 'grid'; this.viewType = parentNote.type === 'search' ? 'list' : 'grid';
} }
@ -207,7 +219,7 @@ class NoteListRenderer {
} }
async renderList() { async renderList() {
if (this.noteIds.length === 0) { if (this.noteIds.length === 0 || !this.page || !this.pageSize) {
this.$noteList.hide(); this.$noteList.hide();
return; return;
} }
@ -248,6 +260,10 @@ class NoteListRenderer {
renderPager() { renderPager() {
const $pager = this.$noteList.find('.note-list-pager').empty(); const $pager = this.$noteList.find('.note-list-pager').empty();
if (!this.page || !this.pageSize) {
return;
}
const pageCount = Math.ceil(this.noteIds.length / this.pageSize); const pageCount = Math.ceil(this.noteIds.length / this.pageSize);
$pager.toggle(pageCount > 1); $pager.toggle(pageCount > 1);
@ -285,7 +301,7 @@ class NoteListRenderer {
$pager.append(`<span class="note-list-pager-total-count">(${this.noteIds.length} notes)</span>`); $pager.append(`<span class="note-list-pager-total-count">(${this.noteIds.length} notes)</span>`);
} }
async renderNote(note, expand = false) { async renderNote(note: FNote, expand: boolean = false) {
const $expander = $('<span class="note-expander bx bx-chevron-right"></span>'); const $expander = $('<span class="note-expander bx bx-chevron-right"></span>');
const {$renderedAttributes} = await attributeRenderer.renderNormalAttributes(note); const {$renderedAttributes} = await attributeRenderer.renderNormalAttributes(note);
@ -330,7 +346,7 @@ class NoteListRenderer {
return $card; return $card;
} }
async toggleContent($card, note, expand) { async toggleContent($card: JQuery<HTMLElement>, note: FNote, expand: boolean) {
if (this.viewType === 'list' && ((expand && $card.hasClass("expanded")) || (!expand && !$card.hasClass("expanded")))) { if (this.viewType === 'list' && ((expand && $card.hasClass("expanded")) || (!expand && !$card.hasClass("expanded")))) {
return; return;
} }
@ -351,7 +367,7 @@ class NoteListRenderer {
} }
} }
async renderNoteContent(note) { async renderNoteContent(note: FNote) {
const $content = $('<div class="note-book-content">'); const $content = $('<div class="note-book-content">');
try { try {
@ -366,7 +382,7 @@ class NoteListRenderer {
separateWordSearch: false, separateWordSearch: false,
caseSensitive: false caseSensitive: false
}); });
} }
$content.append($renderedContent); $content.append($renderedContent);
$content.addClass(`type-${type}`); $content.addClass(`type-${type}`);

View File

@ -98,7 +98,7 @@ function isMac() {
return navigator.platform.indexOf('Mac') > -1; return navigator.platform.indexOf('Mac') > -1;
} }
function isCtrlKey(evt: KeyboardEvent | MouseEvent) { function isCtrlKey(evt: KeyboardEvent | MouseEvent | JQuery.ClickEvent) {
return (!isMac() && evt.ctrlKey) return (!isMac() && evt.ctrlKey)
|| (isMac() && evt.metaKey); || (isMac() && evt.metaKey);
} }
@ -166,7 +166,7 @@ function isMobile() {
|| (!window.glob?.device && /Mobi/.test(navigator.userAgent)); || (!window.glob?.device && /Mobi/.test(navigator.userAgent));
} }
function isDesktop() { function isDesktop() {
return window.glob?.device === "desktop" return window.glob?.device === "desktop"
// window.glob.device is not available in setup // window.glob.device is not available in setup
|| (!window.glob?.device && !/Mobi/.test(navigator.userAgent)); || (!window.glob?.device && !/Mobi/.test(navigator.userAgent));
@ -520,7 +520,7 @@ function createImageSrcUrl(note: { noteId: string; title: string }) {
/** /**
* Given a string representation of an SVG, triggers a download of the file on the client device. * Given a string representation of an SVG, triggers a download of the file on the client device.
* *
* @param nameWithoutExtension the name of the file. The .svg suffix is automatically added to it. * @param nameWithoutExtension the name of the file. The .svg suffix is automatically added to it.
* @param svgContent the content of the SVG file download. * @param svgContent the content of the SVG file download.
*/ */
@ -544,39 +544,39 @@ function downloadSvg(nameWithoutExtension: string, svgContent: string) {
* 1 if v1 is greater than v2 * 1 if v1 is greater than v2
* 0 if v1 is equal to v2 * 0 if v1 is equal to v2
* -1 if v1 is less than v2 * -1 if v1 is less than v2
* *
* @param v1 First version string * @param v1 First version string
* @param v2 Second version string * @param v2 Second version string
* @returns * @returns
*/ */
function compareVersions(v1: string, v2: string): number { function compareVersions(v1: string, v2: string): number {
// Remove 'v' prefix and everything after dash if present // Remove 'v' prefix and everything after dash if present
v1 = v1.replace(/^v/, '').split('-')[0]; v1 = v1.replace(/^v/, '').split('-')[0];
v2 = v2.replace(/^v/, '').split('-')[0]; v2 = v2.replace(/^v/, '').split('-')[0];
const v1parts = v1.split('.').map(Number); const v1parts = v1.split('.').map(Number);
const v2parts = v2.split('.').map(Number); const v2parts = v2.split('.').map(Number);
// Pad shorter version with zeros // Pad shorter version with zeros
while (v1parts.length < 3) v1parts.push(0); while (v1parts.length < 3) v1parts.push(0);
while (v2parts.length < 3) v2parts.push(0); while (v2parts.length < 3) v2parts.push(0);
// Compare major version // Compare major version
if (v1parts[0] !== v2parts[0]) { if (v1parts[0] !== v2parts[0]) {
return v1parts[0] > v2parts[0] ? 1 : -1; return v1parts[0] > v2parts[0] ? 1 : -1;
} }
// Compare minor version // Compare minor version
if (v1parts[1] !== v2parts[1]) { if (v1parts[1] !== v2parts[1]) {
return v1parts[1] > v2parts[1] ? 1 : -1; return v1parts[1] > v2parts[1] ? 1 : -1;
} }
// Compare patch version // Compare patch version
if (v1parts[2] !== v2parts[2]) { if (v1parts[2] !== v2parts[2]) {
return v1parts[2] > v2parts[2] ? 1 : -1; return v1parts[2] > v2parts[2] ? 1 : -1;
} }
return 0; return 0;
} }

View File

@ -85,6 +85,12 @@ declare global {
getSelectedExternalLink(this: HTMLElement): string | undefined; getSelectedExternalLink(this: HTMLElement): string | undefined;
setSelectedExternalLink(externalLink: string | null | undefined); setSelectedExternalLink(externalLink: string | null | undefined);
setNote(noteId: string); setNote(noteId: string);
markRegExp(regex: RegExp, opts: {
element: string;
className: string;
separateWordSearch: boolean;
caseSensitive: boolean;
})
} }
var logError: (message: string, e?: Error) => void; var logError: (message: string, e?: Error) => void;