mirror of
https://github.com/zadam/trilium.git
synced 2025-12-04 22:44:25 +01:00
feat(client): implement photoswipe at different points
This commit is contained in:
parent
78c27dbe04
commit
5024e27885
@ -5,6 +5,7 @@
|
||||
|
||||
import mediaViewer from './media_viewer.js';
|
||||
import galleryManager from './gallery_manager.js';
|
||||
import appContext from '../components/app_context.js';
|
||||
import type { MediaItem } from './media_viewer.js';
|
||||
import type { GalleryItem } from './gallery_manager.js';
|
||||
|
||||
@ -97,9 +98,11 @@ class CKEditorPhotoSwipeIntegration {
|
||||
return;
|
||||
}
|
||||
|
||||
// Make image clickable
|
||||
// Make image clickable and mark it as PhotoSwipe-enabled
|
||||
img.style.cursor = 'zoom-in';
|
||||
img.style.transition = 'opacity 0.2s';
|
||||
img.classList.add('photoswipe-enabled');
|
||||
img.setAttribute('data-photoswipe', 'true');
|
||||
|
||||
// Store event handlers for cleanup
|
||||
const mouseEnterHandler = () => {
|
||||
@ -121,6 +124,24 @@ class CKEditorPhotoSwipeIntegration {
|
||||
// Store handlers for cleanup
|
||||
(img as any)._photoswipeHandlers = { mouseEnterHandler, mouseLeaveHandler };
|
||||
|
||||
// Add double-click handler to prevent default navigation behavior
|
||||
const dblClickHandler = (e: MouseEvent) => {
|
||||
// Only prevent double-click in specific contexts to avoid breaking other features
|
||||
if (img.closest('.attachment-detail-wrapper') ||
|
||||
img.closest('.note-detail-editable-text') ||
|
||||
img.closest('.note-detail-readonly-text')) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
e.stopImmediatePropagation();
|
||||
|
||||
// Trigger the same behavior as single click (open lightbox)
|
||||
img.click();
|
||||
}
|
||||
};
|
||||
|
||||
img.addEventListener('dblclick', dblClickHandler, true); // Use capture phase to ensure we get it first
|
||||
(img as any)._photoswipeHandlers.dblClickHandler = dblClickHandler;
|
||||
|
||||
// Add click handler
|
||||
img.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
@ -194,6 +215,27 @@ class CKEditorPhotoSwipeIntegration {
|
||||
}
|
||||
}, {
|
||||
onClose: () => {
|
||||
// Check if we're in attachment detail view and need to reset viewScope
|
||||
const activeContext = appContext.tabManager.getActiveContext();
|
||||
if (activeContext?.viewScope?.viewMode === 'attachments') {
|
||||
// Get the note ID from the image source
|
||||
const attachmentMatch = img.src.match(/\/api\/attachments\/([A-Za-z0-9_]+)\/image\//);
|
||||
if (attachmentMatch) {
|
||||
const currentAttachmentId = activeContext.viewScope.attachmentId;
|
||||
if (currentAttachmentId === attachmentMatch[1]) {
|
||||
// Actually reset the viewScope instead of just logging
|
||||
try {
|
||||
if (activeContext.note) {
|
||||
activeContext.setNote(activeContext.note.noteId, {
|
||||
viewScope: { viewMode: 'default' }
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to reset viewScope after PhotoSwipe close:', error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Restore focus to the image
|
||||
img.focus();
|
||||
}
|
||||
@ -429,6 +471,9 @@ class CKEditorPhotoSwipeIntegration {
|
||||
if (handlers) {
|
||||
img.removeEventListener('mouseenter', handlers.mouseEnterHandler);
|
||||
img.removeEventListener('mouseleave', handlers.mouseLeaveHandler);
|
||||
if (handlers.dblClickHandler) {
|
||||
img.removeEventListener('dblclick', handlers.dblClickHandler, true);
|
||||
}
|
||||
delete (img as any)._photoswipeHandlers;
|
||||
}
|
||||
|
||||
|
||||
@ -9,6 +9,7 @@ import contentRenderer from "../services/content_renderer.js";
|
||||
import toastService from "../services/toast.js";
|
||||
import type FAttachment from "../entities/fattachment.js";
|
||||
import type { EventData } from "../components/app_context.js";
|
||||
import appContext from "../components/app_context.js";
|
||||
import mediaViewer from "../services/media_viewer.js";
|
||||
import type { MediaItem } from "../services/media_viewer.js";
|
||||
|
||||
@ -114,7 +115,9 @@ const TPL = /*html*/`
|
||||
<div class="attachment-actions-container"></div>
|
||||
<h4 class="attachment-title"></h4>
|
||||
<div class="attachment-details"></div>
|
||||
<div style="flex: 1 1;"></div>
|
||||
<button class="btn btn-sm back-to-note-btn" style="margin-left: auto;" title="Back to Note">
|
||||
<span class="bx bx-arrow-back"></span> Back to Note
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="attachment-deletion-warning alert alert-info" style="margin-top: 15px;"></div>
|
||||
@ -150,6 +153,14 @@ export default class AttachmentDetailWidget extends BasicWidget {
|
||||
this.$widget.find(".attachment-detail-wrapper").empty().append($(TPL).find(".attachment-detail-wrapper").html());
|
||||
this.$wrapper = this.$widget.find(".attachment-detail-wrapper");
|
||||
this.$wrapper.addClass(this.isFullDetail ? "full-detail" : "list-view");
|
||||
|
||||
// Setup back to note button (only show in full detail mode)
|
||||
if (this.isFullDetail) {
|
||||
const $backBtn = this.$wrapper.find('.back-to-note-btn');
|
||||
$backBtn.on('click', () => this.handleBackToNote());
|
||||
} else {
|
||||
this.$wrapper.find('.back-to-note-btn').hide();
|
||||
}
|
||||
|
||||
if (!this.isFullDetail) {
|
||||
const $link = await linkService.createLink(this.attachment.ownerId, {
|
||||
@ -255,6 +266,15 @@ export default class AttachmentDetailWidget extends BasicWidget {
|
||||
console.log('Attachment image opened in lightbox');
|
||||
},
|
||||
onClose: () => {
|
||||
// Check if we're in attachment detail view and reset viewScope if needed
|
||||
const activeContext = appContext.tabManager.getActiveContext();
|
||||
if (activeContext?.viewScope?.viewMode === 'attachments' &&
|
||||
activeContext?.viewScope?.attachmentId === this.attachment.attachmentId) {
|
||||
// Reset to normal note view when closing lightbox from attachment detail
|
||||
activeContext.setNote(this.attachment.ownerId, {
|
||||
viewScope: { viewMode: 'default' }
|
||||
});
|
||||
}
|
||||
// Restore focus to the image
|
||||
$img.focus();
|
||||
}
|
||||
@ -307,6 +327,28 @@ export default class AttachmentDetailWidget extends BasicWidget {
|
||||
}
|
||||
}
|
||||
|
||||
async handleBackToNote() {
|
||||
try {
|
||||
const activeContext = appContext.tabManager.getActiveContext();
|
||||
if (!activeContext) {
|
||||
console.warn('No active context available for navigation');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.attachment.ownerId) {
|
||||
console.error('Cannot navigate back: no owner ID available');
|
||||
return;
|
||||
}
|
||||
|
||||
await activeContext.setNote(this.attachment.ownerId, {
|
||||
viewScope: { viewMode: 'default' }
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Failed to navigate back to note:', error);
|
||||
toastService.showError('Failed to navigate back to note');
|
||||
}
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
// Remove all event handlers before cleanup
|
||||
const $contentWrapper = this.$wrapper?.find('.attachment-content-wrapper');
|
||||
@ -318,6 +360,9 @@ export default class AttachmentDetailWidget extends BasicWidget {
|
||||
}
|
||||
}
|
||||
|
||||
// Remove back button handler
|
||||
this.$wrapper?.find('.back-to-note-btn').off('click');
|
||||
|
||||
super.cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,6 +6,7 @@ import contentRenderer from "../../services/content_renderer.js";
|
||||
import utils from "../../services/utils.js";
|
||||
import options from "../../services/options.js";
|
||||
import attributes from "../../services/attributes.js";
|
||||
import ckeditorPhotoswipeIntegration from "../../services/ckeditor_photoswipe_integration.js";
|
||||
|
||||
export default class AbstractTextTypeWidget extends TypeWidget {
|
||||
doRender() {
|
||||
@ -35,7 +36,29 @@ export default class AbstractTextTypeWidget extends TypeWidget {
|
||||
const parsedImage = await this.parseFromImage($img);
|
||||
|
||||
if (parsedImage) {
|
||||
appContext.tabManager.getActiveContext()?.setNote(parsedImage.noteId, { viewScope: parsedImage.viewScope });
|
||||
// Check if this is an attachment image and PhotoSwipe is available
|
||||
if (parsedImage.viewScope?.attachmentId) {
|
||||
// Instead of navigating to attachment detail, trigger PhotoSwipe
|
||||
// Check if the image is already processed by PhotoSwipe
|
||||
const imgElement = $img[0] as HTMLImageElement;
|
||||
|
||||
// Check if PhotoSwipe is integrated with this image using multiple reliable indicators
|
||||
const hasPhotoSwipe = imgElement.classList.contains('photoswipe-enabled') ||
|
||||
imgElement.hasAttribute('data-photoswipe') ||
|
||||
imgElement.style.cursor === 'zoom-in';
|
||||
|
||||
if (hasPhotoSwipe) {
|
||||
// Image has PhotoSwipe integration, trigger click to open lightbox
|
||||
$img.trigger('click');
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, fall back to opening attachment detail (but with improved navigation)
|
||||
appContext.tabManager.getActiveContext()?.setNote(parsedImage.noteId, { viewScope: parsedImage.viewScope });
|
||||
} else {
|
||||
// Regular note image, navigate normally
|
||||
appContext.tabManager.getActiveContext()?.setNote(parsedImage.noteId, { viewScope: parsedImage.viewScope });
|
||||
}
|
||||
} else {
|
||||
window.open($img.prop("src"), "_blank");
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user