recogito-client-core/src/selection/SelectionHandler.js

106 lines
2.8 KiB
JavaScript

import { trimRange, rangeToSelection, enableTouch } from './SelectionUtils';
import EventEmitter from 'tiny-emitter';
const IS_TOUCH = 'ontouchstart' in window || navigator.maxTouchPoints > 0;
export default class SelectionHandler extends EventEmitter {
constructor(element, highlighter, readOnly) {
super();
this.el = element;
this.highlighter = highlighter;
this.readOnly = readOnly;
this.isEnabled = true;
element.addEventListener('mousedown', this._onMouseDown);
element.addEventListener('mouseup', this._onMouseUp);
if (IS_TOUCH)
enableTouch(element, this._onMouseUp);
}
get enabled() {
return this.isEnabled;
}
set enabled(enabled) {
this.isEnabled = enabled;
}
_onMouseDown = evt => {
this.clearSelection();
}
_onMouseUp = evt => {
if (this.isEnabled) {
const selection = getSelection();
if (selection.isCollapsed) {
const annotationSpan = evt.target.closest('.r6o-annotation');
if (annotationSpan) {
this.emit('select', {
selection: this.highlighter.getAnnotationsAt(annotationSpan)[0],
element: annotationSpan
});
} else {
// De-select
this.emit('select', {});
}
} else if (!this.readOnly) {
const selectedRange = trimRange(selection.getRangeAt(0));
// Make sure the selection is entirely inside this.el
const { commonAncestorContainer } = selectedRange;
if (this.el.contains(commonAncestorContainer)) {
const stub = rangeToSelection(selectedRange, this.el);
const spans = this.highlighter.wrapRange(selectedRange);
spans.forEach(span => span.className = 'r6o-selection');
this._hideNativeSelection();
this.emit('select', {
selection: stub,
element: selectedRange
});
}
}
}
}
_hideNativeSelection = () => {
this.el.classList.add('hide-selection');
}
clearSelection = () => {
this._currentSelection = null;
// Remove native selection, if any
if (window.getSelection) {
if (window.getSelection().empty) { // Chrome
window.getSelection().empty();
} else if (window.getSelection().removeAllRanges) { // Firefox
window.getSelection().removeAllRanges();
}
} else if (document.selection) { // IE?
document.selection.empty();
}
this.el.classList.remove('hide-selection');
const spans = Array.prototype.slice.call(this.el.querySelectorAll('.r6o-selection'));
if (spans) {
spans.forEach(span => {
const parent = span.parentNode;
parent.insertBefore(document.createTextNode(span.textContent), span);
parent.removeChild(span);
});
}
this.el.normalize();
}
}