diff --git a/src/TextAnnotator.jsx b/src/TextAnnotator.jsx index 63e9f9c..ae7f32b 100644 --- a/src/TextAnnotator.jsx +++ b/src/TextAnnotator.jsx @@ -2,9 +2,11 @@ import React, { Component } from 'preact/compat'; import Editor from './editor/Editor'; import Highlighter from './highlighter/Highlighter'; import SelectionHandler from './selection/SelectionHandler'; -import RelationsLayer from './relations/RelationsLayer'; +import RelationsLayer from './relations/RelationsLayer'; import RelationEditor from './relations/editor/RelationEditor'; +import './utils/MSEdgePolyfills'; + /** * Pulls the strings between the annotation highlight layer * and the editor popup. @@ -53,18 +55,18 @@ export default class TextAnnotator extends Component { document.removeEventListener('keydown', this.handleEscape); } - /**************************/ + /**************************/ /* Annotation CRUD events */ - /**************************/ + /**************************/ /** Selection on the text **/ handleSelect = evt => { const { selection, clientRect } = evt; if (selection) { - this.setState({ - selectedAnnotation: null, - selectionBounds: null - }, () => this.setState({ + this.setState({ + selectedAnnotation: null, + selectionBounds: null + }, () => this.setState({ selectedAnnotation: selection, selectionBounds: clientRect })) @@ -76,12 +78,12 @@ export default class TextAnnotator extends Component { /** * A convenience method that allows the external application to * override the autogenerated Id for an annotation. - * + * * Usually, the override will happen almost immediately after * the annotation is created. But we need to be defensive and assume * that the override might come in with considerable delay, thus * the user might have made further edits already. - * + * * A key challenge here is that there may be dependencies between * the original annotation and relations that were created meanwhile. */ @@ -113,14 +115,14 @@ export default class TextAnnotator extends Component { } } - /** + /** * A convenience method that allows the external application to * override the autogenerated Id for a relation. - * + * * This operation is less problematic than .overrideAnnotation(). * We just need to make sure the RelationEditor is closed, so that * the annotation doesn't become orphaned. Otherwise, there are - * no dependencies. + * no dependencies. */ overrideRelationId = originalId => forcedId => { if (this.state.selectedRelation) { @@ -134,14 +136,14 @@ export default class TextAnnotator extends Component { /** Common handler for annotation CREATE or UPDATE **/ onCreateOrUpdateAnnotation = method => (annotation, previous) => { this.clearState(); - + this.selectionHandler.clearSelection(); this.highlighter.addOrUpdateAnnotation(annotation, previous); // Call CREATE or UPDATE handler if (previous) this.props[method](annotation.clone(), previous.clone()); - else + else this.props[method](annotation.clone(), this.overrideAnnotationId(annotation)); } @@ -162,9 +164,9 @@ export default class TextAnnotator extends Component { this.selectionHandler.clearSelection(); } - /************************/ + /************************/ /* Relation CRUD events */ - /************************/ + /************************/ // Shorthand closeRelationsEditor = () => { @@ -177,7 +179,7 @@ export default class TextAnnotator extends Component { * or newly created connection for editing. */ onEditRelation = relation => { - this.setState({ + this.setState({ selectedRelation: relation }); } @@ -205,9 +207,9 @@ export default class TextAnnotator extends Component { this.props.onAnnotationDeleted(relation.annotation); } - /****************/ + /****************/ /* External API */ - /****************/ + /****************/ addAnnotation = annotation => { this.highlighter.addOrUpdateAnnotation(annotation.clone()); @@ -223,7 +225,7 @@ export default class TextAnnotator extends Component { } setAnnotations = annotations => { - const clones = annotations.map(a => a.clone()); + const clones = annotations.map(a => a.clone()); this.highlighter.init(clones).then(() => this.relationsLayer.init(clones)); } @@ -237,14 +239,14 @@ export default class TextAnnotator extends Component { setMode = mode => { if (mode === 'RELATIONS') { this.clearState(); - + this.selectionHandler.enabled = false; this.relationsLayer.readOnly = false; this.relationsLayer.startDrawing(); } else { this.setState({ selectedRelation: null }); - + this.selectionHandler.enabled = true; this.relationsLayer.readOnly = true; @@ -252,7 +254,7 @@ export default class TextAnnotator extends Component { } } - applyTemplate = (bodies, headless) => + applyTemplate = (bodies, headless) => this.setState({ applyTemplate: bodies, headless }) render() { @@ -276,17 +278,17 @@ export default class TextAnnotator extends Component { } - { this.state.selectedRelation && - + /> } ); - } + } } diff --git a/src/editor/setPosition.js b/src/editor/setPosition.js index 01e857d..e31213e 100644 --- a/src/editor/setPosition.js +++ b/src/editor/setPosition.js @@ -11,9 +11,9 @@ const setPosition = (wrapperEl, editorEl, annotationBounds) => { editorEl.style.opacity = 1; // Default orientation - const { x, y, height, top, right } = annotationBounds; - editorEl.style.top = `${y + height - containerBounds.top}px`; - editorEl.style.left = `${x + scrollX - containerBounds.left}px`; + const { left, top, right, height } = annotationBounds; + editorEl.style.top = `${top + height - containerBounds.top}px`; + editorEl.style.left = `${left + scrollX - containerBounds.left}px`; const defaultOrientation = editorEl.getBoundingClientRect(); @@ -27,11 +27,11 @@ const setPosition = (wrapperEl, editorEl, annotationBounds) => { // Flip vertically const annotationTop = top + scrollY; // Annotation top relative to parents const containerHeight = containerBounds.height + containerBounds.top + scrollY; - + editorEl.classList.add('align-bottom'); editorEl.style.top = 'auto'; editorEl.style.bottom = `${containerHeight - annotationTop}px`; } } -export default setPosition; \ No newline at end of file +export default setPosition; diff --git a/src/selection/SelectionHandler.js b/src/selection/SelectionHandler.js index e83ca89..67d3bf3 100644 --- a/src/selection/SelectionHandler.js +++ b/src/selection/SelectionHandler.js @@ -17,7 +17,7 @@ export default class SelectionHandler extends EventEmitter { element.addEventListener('mouseup', this._onMouseUp); if (IS_TOUCH) - enableTouch(element, this._onMouseUp); + enableTouch(element, this._onMouseUp); } get enabled() { @@ -39,9 +39,9 @@ export default class SelectionHandler extends EventEmitter { if (selection.isCollapsed) { const annotationSpan = evt.target.closest('.r6o-annotation'); if (annotationSpan) { - this.emit('select', { + this.emit('select', { selection: this.highlighter.getAnnotationsAt(annotationSpan)[0], - clientRect: annotationSpan.getBoundingClientRect() + clientRect: annotationSpan.getBoundingClientRect() }); } else { // De-select @@ -92,4 +92,4 @@ export default class SelectionHandler extends EventEmitter { this.el.normalize(); } -} \ No newline at end of file +} diff --git a/src/utils/MSEdgePolyfills.js b/src/utils/MSEdgePolyfills.js new file mode 100644 index 0000000..d349b88 --- /dev/null +++ b/src/utils/MSEdgePolyfills.js @@ -0,0 +1,16 @@ +if (!Element.prototype.matches) { + Element.prototype.matches = Element.prototype.msMatchesSelector || + Element.prototype.webkitMatchesSelector; +} + +if (!Element.prototype.closest) { + Element.prototype.closest = function(s) { + let el = this; + + do { + if (Element.prototype.matches.call(el, s)) return el; + el = el.parentElement || el.parentNode; + } while (el !== null && el.nodeType === 1); + return null; + }; +}