From e26b41c8121d5e25a7f627f44151c3384924111d Mon Sep 17 00:00:00 2001 From: Juha Sadeharju Date: Mon, 22 Sep 2025 14:43:24 +0300 Subject: [PATCH 1/4] Added a windowed presentation option to settings and updated related presentation logic --- .../presentation-canvas-extension.ts | 68 ++++++++++++------- src/settings.ts | 19 ++++-- 2 files changed, 58 insertions(+), 29 deletions(-) diff --git a/src/canvas-extensions/presentation-canvas-extension.ts b/src/canvas-extensions/presentation-canvas-extension.ts index 3692078..dd3cba4 100644 --- a/src/canvas-extensions/presentation-canvas-extension.ts +++ b/src/canvas-extensions/presentation-canvas-extension.ts @@ -12,6 +12,7 @@ export default class PresentationCanvasExtension extends CanvasExtension { isPresentationMode: boolean = false visitedNodeIds: string[] = [] fullscreenModalObserver: MutationObserver | null = null + presentationUsesFullscreen: boolean = false isEnabled() { return 'presentationFeatureEnabled' as const } @@ -259,11 +260,21 @@ export default class PresentationCanvasExtension extends CanvasExtension { zoom: canvas.tZoom, } - // Enter fullscreen mode + const shouldEnterFullscreen = this.plugin.settings.getSetting('fullscreenPresentationEnabled') as boolean + this.presentationUsesFullscreen = shouldEnterFullscreen + canvas.wrapperEl.focus() - canvas.wrapperEl.requestFullscreen() canvas.wrapperEl.classList.add('presentation-mode') + if (shouldEnterFullscreen) { + try { + await canvas.wrapperEl.requestFullscreen() + } catch (_err) { + // If fullscreen fails, fall back to windowed mode for this session + this.presentationUsesFullscreen = false + } + } + // Lock canvas canvas.setReadonly(true) @@ -284,30 +295,36 @@ export default class PresentationCanvasExtension extends CanvasExtension { } } - // Keep modals while in fullscreen mode - this.fullscreenModalObserver = new MutationObserver((mutationRecords) => { - mutationRecords.forEach((mutationRecord) => { - mutationRecord.addedNodes.forEach((node) => { - document.body.removeChild(node) - document.fullscreenElement?.appendChild(node) + if (this.presentationUsesFullscreen) { + // Keep modals while in fullscreen mode + this.fullscreenModalObserver = new MutationObserver((mutationRecords) => { + mutationRecords.forEach((mutationRecord) => { + mutationRecord.addedNodes.forEach((node) => { + document.body.removeChild(node) + document.fullscreenElement?.appendChild(node) + }) }) - }) - const inputField = document.querySelector(".prompt-input") as HTMLInputElement|null - if (inputField) inputField.focus() - }) - this.fullscreenModalObserver.observe(document.body, { childList: true }) + const inputField = document.querySelector('.prompt-input') as HTMLInputElement | null + if (inputField) inputField.focus() + }) + this.fullscreenModalObserver.observe(document.body, { childList: true }) - // Register event handler for exiting presentation mode - canvas.wrapperEl.onfullscreenchange = (_e: any) => { - if (document.fullscreenElement) return - this.endPresentation(canvas) + // Register event handler for exiting presentation mode + canvas.wrapperEl.onfullscreenchange = (_e: any) => { + if (document.fullscreenElement) return + this.endPresentation(canvas) + } + } else { + this.fullscreenModalObserver?.disconnect() + this.fullscreenModalObserver = null + canvas.wrapperEl.onfullscreenchange = null } this.isPresentationMode = true // Wait for fullscreen to be enabled - await sleep(500) + if (this.presentationUsesFullscreen) await sleep(500) // Zoom to first node const startNodeId = this.visitedNodeIds.first() @@ -321,10 +338,14 @@ export default class PresentationCanvasExtension extends CanvasExtension { private endPresentation(canvas: Canvas) { // Unregister event handlers - this.fullscreenModalObserver?.disconnect() - this.fullscreenModalObserver = null + if (this.presentationUsesFullscreen) { + this.fullscreenModalObserver?.disconnect() + this.fullscreenModalObserver = null + } else { + this.fullscreenModalObserver = null + } canvas.wrapperEl.onkeydown = null - canvas.wrapperEl.onfullscreenchange = null + if (this.presentationUsesFullscreen) canvas.wrapperEl.onfullscreenchange = null // Unlock canvas canvas.setReadonly(false) @@ -335,13 +356,14 @@ export default class PresentationCanvasExtension extends CanvasExtension { // Exit fullscreen mode canvas.wrapperEl.classList.remove('presentation-mode') - if (document.fullscreenElement) document.exitFullscreen() + if (this.presentationUsesFullscreen && document.fullscreenElement) document.exitFullscreen() // Reset viewport if (this.plugin.settings.getSetting('resetViewportOnPresentationEnd')) canvas.setViewport(this.savedViewport.x, this.savedViewport.y, this.savedViewport.zoom) this.isPresentationMode = false + this.presentationUsesFullscreen = false } private nextNode(canvas: Canvas) { @@ -401,4 +423,4 @@ export default class PresentationCanvasExtension extends CanvasExtension { this.animateNodeTransition(canvas, fromNode, toNode) } -} \ No newline at end of file +} diff --git a/src/settings.ts b/src/settings.ts index 239281e..e071c01 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -89,6 +89,7 @@ export interface AdvancedCanvasPluginSettingsValues { usePgUpPgDownKeysToChangeSlides: boolean zoomToSlideWithoutPadding: boolean useUnclampedZoomWhilePresenting: boolean + fullscreenPresentationEnabled: boolean slideTransitionAnimationDuration: number slideTransitionAnimationIntensity: number @@ -184,6 +185,7 @@ export const DEFAULT_SETTINGS_VALUES: AdvancedCanvasPluginSettingsValues = { usePgUpPgDownKeysToChangeSlides: true, zoomToSlideWithoutPadding: true, useUnclampedZoomWhilePresenting: false, + fullscreenPresentationEnabled: true, slideTransitionAnimationDuration: 0.5, slideTransitionAnimationIntensity: 1.25, @@ -508,6 +510,11 @@ export const SETTINGS = { description: 'When enabled, the zoom will not be clamped while presenting.', type: 'boolean' }, + fullscreenPresentationEnabled: { + label: 'Enter fullscreen while presenting', + description: 'When enabled, presentations automatically request fullscreen. Disable to keep Obsidian windowed during presentations.', + type: 'boolean' + }, slideTransitionAnimationDuration: { label: 'Slide transition animation duration', description: 'The duration of the slide transition animation in seconds. Set to 0 to disable the animation.', @@ -616,9 +623,9 @@ export const SETTINGS = { children: { } }, } as const satisfies { - [key in keyof AdvancedCanvasPluginSettingsValues]: SettingsHeading & { - children: { - [key in keyof AdvancedCanvasPluginSettingsValues]?: Setting + [key in keyof AdvancedCanvasPluginSettingsValues]: SettingsHeading & { + children: { + [key in keyof AdvancedCanvasPluginSettingsValues]?: Setting } } } @@ -674,9 +681,9 @@ export class AdvancedCanvasPluginSettingTab extends PluginSettingTab { // Generate settings from SETTINGS object for (const [headingId, heading] of Object.entries(SETTINGS) as [string, SettingsHeading][]) { this.createFeatureHeading( - containerEl, - heading.label, - heading.description, + containerEl, + heading.label, + heading.description, heading.infoSection, heading.disableToggle ? null : headingId as keyof AdvancedCanvasPluginSettingsValues ) From 7394cee821ae770670142fbd2ccd7422567ef563 Mon Sep 17 00:00:00 2001 From: Juha Sadeharju Date: Mon, 22 Sep 2025 15:40:20 +0300 Subject: [PATCH 2/4] Fixed Escape key handling in windowed mode to end presentation --- .../presentation-canvas-extension.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/canvas-extensions/presentation-canvas-extension.ts b/src/canvas-extensions/presentation-canvas-extension.ts index dd3cba4..b86c40a 100644 --- a/src/canvas-extensions/presentation-canvas-extension.ts +++ b/src/canvas-extensions/presentation-canvas-extension.ts @@ -283,7 +283,14 @@ export default class PresentationCanvasExtension extends CanvasExtension { canvas.screenshotting = true // Register event handler for keyboard navigation - canvas.wrapperEl.onkeydown = (e: any) => { + canvas.wrapperEl.onkeydown = (e: KeyboardEvent) => { + if (e.key === 'Escape') { + e.preventDefault() + e.stopPropagation() + this.endPresentation(canvas) + return + } + if (this.plugin.settings.getSetting('useArrowKeysToChangeSlides')) { if (e.key === 'ArrowRight') this.nextNode(canvas) else if (e.key === 'ArrowLeft') this.previousNode(canvas) @@ -337,6 +344,8 @@ export default class PresentationCanvasExtension extends CanvasExtension { } private endPresentation(canvas: Canvas) { + if (!this.isPresentationMode) return + // Unregister event handlers if (this.presentationUsesFullscreen) { this.fullscreenModalObserver?.disconnect() From eca58eee55fd2c4af503535cb299aa920e830943 Mon Sep 17 00:00:00 2001 From: Juha Sadeharju Date: Mon, 22 Sep 2025 16:14:22 +0300 Subject: [PATCH 3/4] Update src/canvas-extensions/presentation-canvas-extension.ts Removes redundant defensives. Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/canvas-extensions/presentation-canvas-extension.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/canvas-extensions/presentation-canvas-extension.ts b/src/canvas-extensions/presentation-canvas-extension.ts index b86c40a..f861239 100644 --- a/src/canvas-extensions/presentation-canvas-extension.ts +++ b/src/canvas-extensions/presentation-canvas-extension.ts @@ -323,8 +323,6 @@ export default class PresentationCanvasExtension extends CanvasExtension { this.endPresentation(canvas) } } else { - this.fullscreenModalObserver?.disconnect() - this.fullscreenModalObserver = null canvas.wrapperEl.onfullscreenchange = null } From 07079250bb1432c0198a18cb5b9e7fd89dbf57b2 Mon Sep 17 00:00:00 2001 From: Juha Sadeharju Date: Mon, 22 Sep 2025 16:14:48 +0300 Subject: [PATCH 4/4] Update src/canvas-extensions/presentation-canvas-extension.ts Removes redundant defensives. Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/canvas-extensions/presentation-canvas-extension.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/canvas-extensions/presentation-canvas-extension.ts b/src/canvas-extensions/presentation-canvas-extension.ts index f861239..acf537a 100644 --- a/src/canvas-extensions/presentation-canvas-extension.ts +++ b/src/canvas-extensions/presentation-canvas-extension.ts @@ -348,8 +348,6 @@ export default class PresentationCanvasExtension extends CanvasExtension { if (this.presentationUsesFullscreen) { this.fullscreenModalObserver?.disconnect() this.fullscreenModalObserver = null - } else { - this.fullscreenModalObserver = null } canvas.wrapperEl.onkeydown = null if (this.presentationUsesFullscreen) canvas.wrapperEl.onfullscreenchange = null