Polyfills to enable editor positoning on MS Edge (issue #7)
This commit is contained in:
parent
a22068960a
commit
41529a4cd1
|
@ -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 {
|
|||
</Editor>
|
||||
}
|
||||
|
||||
{ this.state.selectedRelation &&
|
||||
<RelationEditor
|
||||
{ this.state.selectedRelation &&
|
||||
<RelationEditor
|
||||
relation={this.state.selectedRelation}
|
||||
onRelationCreated={this.onCreateOrUpdateRelation}
|
||||
onRelationUpdated={this.onCreateOrUpdateRelation}
|
||||
onRelationDeleted={this.onDeleteRelation}
|
||||
onCancel={this.closeRelationsEditor}
|
||||
/>
|
||||
/>
|
||||
}
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
export default setPosition;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
}
|
Loading…
Reference in New Issue