You've already forked joplin
mirror of
https://github.com/laurent22/joplin.git
synced 2025-12-20 23:30:05 +02:00
scroll
This commit is contained in:
@@ -4,58 +4,56 @@ import { NoteEntity } from '@joplin/lib/services/database/types';
|
||||
import { Size } from '@joplin/utils/types';
|
||||
import useAsyncEffect from '@joplin/lib/hooks/useAsyncEffect';
|
||||
import * as Mustache from 'mustache';
|
||||
import { createHash } from 'crypto';
|
||||
|
||||
interface RenderedNote {
|
||||
id: string;
|
||||
hash: string;
|
||||
html: string;
|
||||
}
|
||||
|
||||
const useRenderedNotes = (notes: NoteEntity[], selectedNoteIds: string[], itemSize: Size, listRenderer: ListRenderer) => {
|
||||
const initialValue = notes.map(n => {
|
||||
return {
|
||||
id: n.id,
|
||||
html: '',
|
||||
};
|
||||
});
|
||||
const hashContent = (content: any) => {
|
||||
return createHash('sha1').update(JSON.stringify(content)).digest('hex');
|
||||
};
|
||||
|
||||
const [renderedNotes, setRenderedNotes] = useState<RenderedNote[]>(initialValue);
|
||||
const prepareViewProps = async (dependencies: ListRendererDepependency[], note: NoteEntity, itemSize: Size, selected: boolean) => {
|
||||
const output: any = {};
|
||||
|
||||
const prepareViewProps = async (dependencies: ListRendererDepependency[], note: NoteEntity, itemSize: Size, selected: boolean) => {
|
||||
const output: any = {};
|
||||
for (const dep of dependencies) {
|
||||
for (const dep of dependencies) {
|
||||
|
||||
if (dep.startsWith('note.')) {
|
||||
const splitted = dep.split('.');
|
||||
if (splitted.length !== 2) throw new Error(`Invalid dependency name: ${dep}`);
|
||||
const propName = splitted.pop();
|
||||
if (!output.note) output.note = {};
|
||||
if (!(propName in note)) throw new Error(`Invalid dependency name: ${dep}`);
|
||||
output.note[propName] = (note as any)[propName];
|
||||
}
|
||||
|
||||
if (dep.startsWith('item.size.')) {
|
||||
const splitted = dep.split('.');
|
||||
if (splitted.length !== 3) throw new Error(`Invalid dependency name: ${dep}`);
|
||||
const propName = splitted.pop();
|
||||
if (!output.item) output.item = {};
|
||||
if (!output.item.size) output.item.size = {};
|
||||
if (!(propName in itemSize)) throw new Error(`Invalid dependency name: ${dep}`);
|
||||
output.item.size[propName] = (itemSize as any)[propName];
|
||||
}
|
||||
|
||||
if (dep === 'item.selected') {
|
||||
if (!output.item) output.item = {};
|
||||
output.item.selected = selected;
|
||||
}
|
||||
if (dep.startsWith('note.')) {
|
||||
const splitted = dep.split('.');
|
||||
if (splitted.length !== 2) throw new Error(`Invalid dependency name: ${dep}`);
|
||||
const propName = splitted.pop();
|
||||
if (!output.note) output.note = {};
|
||||
if (!(propName in note)) throw new Error(`Invalid dependency name: ${dep}`);
|
||||
output.note[propName] = (note as any)[propName];
|
||||
}
|
||||
|
||||
return output;
|
||||
};
|
||||
if (dep.startsWith('item.size.')) {
|
||||
const splitted = dep.split('.');
|
||||
if (splitted.length !== 3) throw new Error(`Invalid dependency name: ${dep}`);
|
||||
const propName = splitted.pop();
|
||||
if (!output.item) output.item = {};
|
||||
if (!output.item.size) output.item.size = {};
|
||||
if (!(propName in itemSize)) throw new Error(`Invalid dependency name: ${dep}`);
|
||||
output.item.size[propName] = (itemSize as any)[propName];
|
||||
}
|
||||
|
||||
if (dep === 'item.selected') {
|
||||
if (!output.item) output.item = {};
|
||||
output.item.selected = selected;
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
};
|
||||
|
||||
const useRenderedNotes = (startNoteIndex: number, endNoteIndex: number, notes: NoteEntity[], selectedNoteIds: string[], itemSize: Size, listRenderer: ListRenderer) => {
|
||||
const [renderedNotes, setRenderedNotes] = useState<Record<string, RenderedNote>>({});
|
||||
|
||||
useAsyncEffect(async (event) => {
|
||||
const newRenderedNotes: RenderedNote[] = [];
|
||||
|
||||
for (const note of notes) {
|
||||
const renderNote = async (note: NoteEntity): Promise<void> => {
|
||||
const view = await listRenderer.onRenderNote(await prepareViewProps(
|
||||
listRenderer.dependencies,
|
||||
note,
|
||||
@@ -63,16 +61,33 @@ const useRenderedNotes = (notes: NoteEntity[], selectedNoteIds: string[], itemSi
|
||||
selectedNoteIds.includes(note.id)
|
||||
));
|
||||
|
||||
newRenderedNotes.push({
|
||||
id: note.id,
|
||||
html: Mustache.render(listRenderer.itemTemplate, view),
|
||||
if (event.cancelled) return null;
|
||||
|
||||
const viewHash = hashContent(view);
|
||||
|
||||
setRenderedNotes(prev => {
|
||||
if (prev[note.id] && prev[note.id].hash === viewHash) return prev;
|
||||
|
||||
return {
|
||||
...prev,
|
||||
[note.id]: {
|
||||
id: note.id,
|
||||
hash: viewHash,
|
||||
html: Mustache.render(listRenderer.itemTemplate, view),
|
||||
},
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
const promises: Promise<void>[] = [];
|
||||
|
||||
for (let i = startNoteIndex; i <= endNoteIndex; i++) {
|
||||
const note = notes[i];
|
||||
promises.push(renderNote(note));
|
||||
}
|
||||
|
||||
if (event.cancelled) return null;
|
||||
|
||||
setRenderedNotes(newRenderedNotes);
|
||||
}, [notes, selectedNoteIds, itemSize]);
|
||||
await Promise.all(promises);
|
||||
}, [startNoteIndex, endNoteIndex, notes, selectedNoteIds, itemSize, listRenderer]);
|
||||
|
||||
return renderedNotes;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user