From 17fbebacf0002229e80c6348ae20dcce936d778e Mon Sep 17 00:00:00 2001 From: Richard Eckart de Castilho Date: Thu, 22 Feb 2024 22:57:57 +0100 Subject: [PATCH] #4547 - Cannot create long-distance relation in PDF editor - Added support for context menu in PDF editor --- .../src/main/ts/src/PdfAnnotationEditor.ts | 35 ++++++++++++++++--- .../core/src/model/AbstractAnnotation.ts | 19 +++++++++- .../core/src/model/RelationAnnotation.ts | 14 +++++--- .../pdfanno/core/src/model/SpanAnnotation.ts | 3 ++ 4 files changed, 61 insertions(+), 10 deletions(-) diff --git a/inception/inception-pdf-editor2/src/main/ts/src/PdfAnnotationEditor.ts b/inception/inception-pdf-editor2/src/main/ts/src/PdfAnnotationEditor.ts index 06c0637f26c..50723ad934b 100644 --- a/inception/inception-pdf-editor2/src/main/ts/src/PdfAnnotationEditor.ts +++ b/inception/inception-pdf-editor2/src/main/ts/src/PdfAnnotationEditor.ts @@ -28,10 +28,16 @@ export class PdfAnnotationEditor implements AnnotationEditor { this.ajax = ajax this.root = element - element.addEventListener('annotationSelected', ev => this.onAnnotationSelected(ev)) - element.addEventListener('createSpanAnnotation', ev => this.onCreateSpanAnnotation(ev)) - element.addEventListener('createRelationAnnotation', ev => this.onCreateRelationAnnotation(ev)) - element.addEventListener('doubleClickAnnotation', ev => this.onDoubleClickAnnotation(ev)) + // Prevent right-click from triggering a selection event + this.root.addEventListener('mousedown', e => this.cancelRightClick(e), { capture: true }) + this.root.addEventListener('mouseup', e => this.cancelRightClick(e), { capture: true }) + this.root.addEventListener('mouseclick', e => this.cancelRightClick(e), { capture: true }) + + this.root.addEventListener('annotationSelected', ev => this.onAnnotationSelected(ev)) + this.root.addEventListener('createSpanAnnotation', ev => this.onCreateSpanAnnotation(ev)) + this.root.addEventListener('createRelationAnnotation', ev => this.onCreateRelationAnnotation(ev)) + this.root.addEventListener('doubleClickAnnotation', ev => this.onDoubleClickAnnotation(ev)) + this.root.addEventListener('openContextMenu', ev => this.onOpenContextMenu(ev)) } async init (): Promise { @@ -47,6 +53,27 @@ export class PdfAnnotationEditor implements AnnotationEditor { scrollTo(args) } + private cancelRightClick (e: Event): void { + if (e instanceof MouseEvent) { + if (e.button === 2) { + console.log("cancelled") + e.preventDefault() + e.stopPropagation() + } + } + } + + onOpenContextMenu (ev: Event) { + if (ev instanceof CustomEvent) { + const ann = ev.detail.ann as AbstractAnnotation + const oev = ev.detail.originalEvent + + if (!(oev instanceof MouseEvent) || !(oev.target instanceof Node)) return + + if (ann.vid) this.ajax.openContextMenu(ann.vid, oev) + } + } + onAnnotationSelected (ev: Event) { if (ev instanceof CustomEvent) { const ann = ev.detail as AbstractAnnotation diff --git a/inception/inception-pdf-editor2/src/main/ts/src/pdfanno/core/src/model/AbstractAnnotation.ts b/inception/inception-pdf-editor2/src/main/ts/src/pdfanno/core/src/model/AbstractAnnotation.ts index 277ebfcde7c..7b2f44b3a1f 100644 --- a/inception/inception-pdf-editor2/src/main/ts/src/pdfanno/core/src/model/AbstractAnnotation.ts +++ b/inception/inception-pdf-editor2/src/main/ts/src/pdfanno/core/src/model/AbstractAnnotation.ts @@ -100,7 +100,7 @@ export default abstract class AbstractAnnotation extends EventEmitter { } /** - * Handle a click event. + * Handle a left-click event. */ handleSingleClickEvent (e: Event) { if (this.element) { @@ -110,6 +110,23 @@ export default abstract class AbstractAnnotation extends EventEmitter { } } + /** + * Handle a right-click event. + */ + handleRightClickEvent (e: Event) { + if (this.element && e instanceof MouseEvent) { + // If the user shift-right-clicks, open the normal browser context menu. This is useful + // e.g. during debugging / developing + if (e.shiftKey) return + + e.preventDefault() + + const event = document.createEvent('CustomEvent') + event.initCustomEvent('openContextMenu', true, true, { ann: this, originalEvent: e}) + this.element.dispatchEvent(event) + } + } + /** * Handle a hoverIn event. */ diff --git a/inception/inception-pdf-editor2/src/main/ts/src/pdfanno/core/src/model/RelationAnnotation.ts b/inception/inception-pdf-editor2/src/main/ts/src/pdfanno/core/src/model/RelationAnnotation.ts index d12940586cd..b666071d23c 100644 --- a/inception/inception-pdf-editor2/src/main/ts/src/pdfanno/core/src/model/RelationAnnotation.ts +++ b/inception/inception-pdf-editor2/src/main/ts/src/pdfanno/core/src/model/RelationAnnotation.ts @@ -31,6 +31,7 @@ export default class RelationAnnotation extends AbstractAnnotation { // Need to bind these event handler methods this.handleSingleClickEvent = this.handleSingleClickEvent.bind(this) + this.handleRightClickEvent = this.handleRightClickEvent.bind(this) this.handleHoverInEvent = this.handleHoverInEvent.bind(this) this.handleHoverOutEvent = this.handleHoverOutEvent.bind(this) @@ -220,9 +221,10 @@ export default class RelationAnnotation extends AbstractAnnotation { super.enableViewMode() if (!this.readOnly) { - this.element?.querySelectorAll('path').forEach(e => - e.addEventListener('click', this.handleSingleClickEvent)) - } + this.element?.querySelectorAll('path').forEach(e => { + e.addEventListener('click', this.handleSingleClickEvent) + e.addEventListener('contextmenu', this.handleRightClickEvent) + })} } /** @@ -230,8 +232,10 @@ export default class RelationAnnotation extends AbstractAnnotation { */ disableViewMode () { super.disableViewMode() - this.element?.querySelectorAll('path').forEach(e => - e.removeEventListener('click', this.handleSingleClickEvent)) + this.element?.querySelectorAll('path').forEach(e => { + e.removeEventListener('click', this.handleSingleClickEvent) + e.removeEventListener('contextmenu', this.handleRightClickEvent) + }) } /** diff --git a/inception/inception-pdf-editor2/src/main/ts/src/pdfanno/core/src/model/SpanAnnotation.ts b/inception/inception-pdf-editor2/src/main/ts/src/pdfanno/core/src/model/SpanAnnotation.ts index 7ab1b698440..3c6bdd7a719 100644 --- a/inception/inception-pdf-editor2/src/main/ts/src/pdfanno/core/src/model/SpanAnnotation.ts +++ b/inception/inception-pdf-editor2/src/main/ts/src/pdfanno/core/src/model/SpanAnnotation.ts @@ -30,6 +30,7 @@ export default class SpanAnnotation extends AbstractAnnotation { // Need to bind these event handler methods this.handleClickEvent = this.handleClickEvent.bind(this) + this.handleRightClickEvent = this.handleRightClickEvent.bind(this) this.handleHoverInEvent = this.handleHoverInEvent.bind(this) this.handleHoverOutEvent = this.handleHoverOutEvent.bind(this) @@ -117,6 +118,7 @@ export default class SpanAnnotation extends AbstractAnnotation { this.element?.querySelectorAll('.anno-knob').forEach(e => { e.addEventListener('mousedown', this.preventFocusChange) e.addEventListener('click', this.handleClickEvent) + e.addEventListener('contextmenu', this.handleRightClickEvent) }) } @@ -162,6 +164,7 @@ export default class SpanAnnotation extends AbstractAnnotation { super.disableViewMode() this.element?.querySelectorAll('.anno-knob').forEach(e => { e.removeEventListener('click', this.handleClickEvent) + e.removeEventListener('contextmenu', this.handleRightClickEvent) e.removeEventListener('mousedown', this.preventFocusChange) }) }