mirror of
https://github.com/zadam/trilium.git
synced 2025-10-26 07:46:30 +01:00
feat(client/print): print presentations with waiting for slides to load
This commit is contained in:
@@ -2,6 +2,7 @@ import FNote from "./entities/fnote";
|
||||
import { render } from "preact";
|
||||
import { CustomNoteList } from "./widgets/collections/NoteList";
|
||||
import "./print.css";
|
||||
import { useCallback, useRef } from "preact/hooks";
|
||||
|
||||
async function main() {
|
||||
const notePath = window.location.hash.substring(1);
|
||||
@@ -12,10 +13,25 @@ async function main() {
|
||||
const note = await froca.getNote(noteId);
|
||||
|
||||
if (!note) return;
|
||||
render(getElementForNote(note), document.body);
|
||||
render(<App note={note} />, document.body);
|
||||
}
|
||||
|
||||
function getElementForNote(note: FNote) {
|
||||
function App({ note }: { note: FNote }) {
|
||||
return (
|
||||
<>
|
||||
<ContentRenderer note={note} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function ContentRenderer({ note }: { note: FNote }) {
|
||||
const sentReadyEvent = useRef(false);
|
||||
const onReady = useCallback(() => {
|
||||
if (sentReadyEvent.current) return;
|
||||
window.dispatchEvent(new Event("note-ready"));
|
||||
sentReadyEvent.current = true;
|
||||
}, []);
|
||||
|
||||
// Collections.
|
||||
if (note.type === "book") {
|
||||
return <CustomNoteList
|
||||
@@ -25,6 +41,7 @@ function getElementForNote(note: FNote) {
|
||||
ntxId="print"
|
||||
highlightedTokens={null}
|
||||
media="print"
|
||||
onReady={onReady}
|
||||
/>;
|
||||
}
|
||||
|
||||
|
||||
@@ -2422,4 +2422,14 @@ footer.webview-footer button {
|
||||
.revision-diff-removed {
|
||||
background: rgba(255, 100, 100, 0.5);
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
iframe.print-iframe {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: -600px;
|
||||
right: -600px;
|
||||
bottom: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
@@ -23,9 +23,10 @@ interface NoteListProps {
|
||||
isEnabled: boolean;
|
||||
ntxId: string | null | undefined;
|
||||
media: ViewModeMedia;
|
||||
onReady: () => void;
|
||||
}
|
||||
|
||||
export default function NoteList<T extends object>(props: Pick<NoteListProps, "displayOnlyCollections" | "media">) {
|
||||
export default function NoteList<T extends object>(props: Pick<NoteListProps, "displayOnlyCollections" | "media" | "onReady">) {
|
||||
const { note, noteContext, notePath, ntxId } = useNoteContext();
|
||||
const isEnabled = noteContext?.hasNoteList();
|
||||
return <CustomNoteList note={note} isEnabled={!!isEnabled} notePath={notePath} ntxId={ntxId} {...props} />
|
||||
|
||||
@@ -16,4 +16,5 @@ export interface ViewModeProps<T extends object> {
|
||||
viewConfig: T | undefined;
|
||||
saveConfig(newConfig: T): void;
|
||||
media: ViewModeMedia;
|
||||
onReady(): void;
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import { t } from "../../../services/i18n";
|
||||
import { DEFAULT_THEME, loadPresentationTheme } from "./themes";
|
||||
import FNote from "../../../entities/fnote";
|
||||
|
||||
export default function PresentationView({ note, noteIds, media }: ViewModeProps<{}>) {
|
||||
export default function PresentationView({ note, noteIds, media, onReady }: ViewModeProps<{}>) {
|
||||
const [ presentation, setPresentation ] = useState<PresentationModel>();
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const [ api, setApi ] = useState<Reveal.Api>();
|
||||
@@ -33,6 +33,14 @@ export default function PresentationView({ note, noteIds, media }: ViewModeProps
|
||||
|
||||
useLayoutEffect(refresh, [ note, noteIds ]);
|
||||
|
||||
useEffect(() => {
|
||||
// We need to wait for Reveal.js to initialize (by setting api) and for the presentation to become available.
|
||||
if (api && presentation) {
|
||||
// Timeout is necessary because it otherwise can cause flakiness by rendering only the first slide.
|
||||
setTimeout(onReady, 200);
|
||||
}
|
||||
}, [ api, presentation ]);
|
||||
|
||||
if (!presentation || !stylesheets) return;
|
||||
const content = (
|
||||
<>
|
||||
|
||||
@@ -297,8 +297,19 @@ export default class NoteDetailWidget extends NoteContextAwareWidget {
|
||||
return;
|
||||
}
|
||||
|
||||
// Trigger in timeout to dismiss the menu while printing.
|
||||
setTimeout(window.print, 0);
|
||||
const iframe = document.createElement('iframe');
|
||||
iframe.src = `?print#${this.notePath}`;
|
||||
iframe.className = "print-iframe";
|
||||
document.body.appendChild(iframe);
|
||||
iframe.onload = () => {
|
||||
console.log("Got ", iframe, iframe.contentWindow);
|
||||
if (iframe.contentWindow) {
|
||||
iframe.contentWindow.addEventListener("note-ready", () => {
|
||||
iframe.contentWindow?.print();
|
||||
document.body.removeChild(iframe);
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
async exportAsPdfEvent() {
|
||||
|
||||
@@ -47,11 +47,11 @@ function NoteContextMenu({ note, noteContext }: { note: FNote, noteContext?: Not
|
||||
const canBeConvertedToAttachment = note?.isEligibleForConversionToAttachment();
|
||||
const isSearchable = ["text", "code", "book", "mindMap", "doc"].includes(note.type);
|
||||
const isInOptions = note.noteId.startsWith("_options");
|
||||
const isPrintable = ["text", "code"].includes(note.type);
|
||||
const isPrintable = ["text", "code", "book"].includes(note.type);
|
||||
const isElectron = getIsElectron();
|
||||
const isMac = getIsMac();
|
||||
const hasSource = ["text", "code", "relationMap", "mermaid", "canvas", "mindMap"].includes(note.type);
|
||||
const isSearchOrBook = ["search", "book"].includes(note.type);
|
||||
const isSearchOrBook = ["search", "book"].includes(note.type);
|
||||
|
||||
return (
|
||||
<Dropdown
|
||||
@@ -74,7 +74,7 @@ function NoteContextMenu({ note, noteContext }: { note: FNote, noteContext?: Not
|
||||
<CommandItem icon="bx bx-export" text={t("note_actions.export_note")}
|
||||
disabled={isInOptions || note.noteId === "_backendLog"}
|
||||
command={() => noteContext?.notePath && parentComponent?.triggerCommand("showExportDialog", {
|
||||
notePath: noteContext.notePath,
|
||||
notePath: noteContext.notePath,
|
||||
defaultType: "single"
|
||||
})} />
|
||||
<FormDropdownDivider />
|
||||
@@ -133,4 +133,4 @@ function ConvertToAttachment({ note }: { note: FNote }) {
|
||||
}}
|
||||
>{t("note_actions.convert_into_attachment")}</FormListItem>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user