From 1af3ac7bd9f927d0dbfb23ee32ac64a0c9ad88f6 Mon Sep 17 00:00:00 2001 From: Roy Johnson Date: Fri, 26 Jan 2024 13:36:07 -0600 Subject: [PATCH] Add dist for release --- dist/Highlight.d.ts | 45 +++ dist/Highlight.js | 133 +++++++ dist/Highlight.js.map | 1 + dist/Highlighter.d.ts | 53 +++ dist/Highlighter.js | 204 ++++++++++ dist/Highlighter.js.map | 1 + dist/Highlighter.test.d.ts | 1 + dist/Highlighter.test.js | 212 ++++++++++ dist/Highlighter.test.js.map | 1 + dist/SerializedHighlight.d.ts | 28 ++ dist/SerializedHighlight.js | 92 +++++ dist/SerializedHighlight.js.map | 1 + dist/api.d.ts | 3 + dist/api.js | 9 + dist/api.js.map | 1 + dist/dom.d.ts | 106 +++++ dist/dom.js | 252 ++++++++++++ dist/dom.js.map | 1 + dist/index.d.ts | 5 + dist/index.js | 9 + dist/index.js.map | 1 + dist/injectHighlightWrappers.d.ts | 14 + dist/injectHighlightWrappers.js | 361 ++++++++++++++++++ dist/injectHighlightWrappers.js.map | 1 + dist/injectHighlightWrappers.spec.d.ts | 1 + dist/injectHighlightWrappers.spec.data.d.ts | 3 + dist/injectHighlightWrappers.spec.data.js | 55 +++ dist/injectHighlightWrappers.spec.data.js.map | 1 + dist/injectHighlightWrappers.spec.js | 237 ++++++++++++ dist/injectHighlightWrappers.spec.js.map | 1 + dist/rangeContents.d.ts | 2 + dist/rangeContents.js | 83 ++++ dist/rangeContents.js.map | 1 + dist/removeHighlightWrappers.d.ts | 8 + dist/removeHighlightWrappers.js | 80 ++++ dist/removeHighlightWrappers.js.map | 1 + dist/selection.d.ts | 9 + dist/selection.js | 126 ++++++ dist/selection.js.map | 1 + .../TextPositionSelector/index.d.ts | 11 + .../TextPositionSelector/index.js | 33 ++ .../TextPositionSelector/index.js.map | 1 + .../XpathRangeSelector/index.d.ts | 13 + .../XpathRangeSelector/index.js | 40 ++ .../XpathRangeSelector/index.js.map | 1 + .../XpathRangeSelector/index.spec.d.ts | 1 + .../XpathRangeSelector/index.spec.js | 109 ++++++ .../XpathRangeSelector/index.spec.js.map | 1 + .../XpathRangeSelector/xpath.d.ts | 2 + .../XpathRangeSelector/xpath.js | 242 ++++++++++++ .../XpathRangeSelector/xpath.js.map | 1 + dist/serializationStrategies/index.d.ts | 9 + dist/serializationStrategies/index.js | 29 ++ dist/serializationStrategies/index.js.map | 1 + 54 files changed, 2638 insertions(+) create mode 100644 dist/Highlight.d.ts create mode 100644 dist/Highlight.js create mode 100644 dist/Highlight.js.map create mode 100644 dist/Highlighter.d.ts create mode 100644 dist/Highlighter.js create mode 100644 dist/Highlighter.js.map create mode 100644 dist/Highlighter.test.d.ts create mode 100644 dist/Highlighter.test.js create mode 100644 dist/Highlighter.test.js.map create mode 100644 dist/SerializedHighlight.d.ts create mode 100644 dist/SerializedHighlight.js create mode 100644 dist/SerializedHighlight.js.map create mode 100644 dist/api.d.ts create mode 100644 dist/api.js create mode 100644 dist/api.js.map create mode 100644 dist/dom.d.ts create mode 100644 dist/dom.js create mode 100644 dist/dom.js.map create mode 100644 dist/index.d.ts create mode 100644 dist/index.js create mode 100644 dist/index.js.map create mode 100644 dist/injectHighlightWrappers.d.ts create mode 100644 dist/injectHighlightWrappers.js create mode 100644 dist/injectHighlightWrappers.js.map create mode 100644 dist/injectHighlightWrappers.spec.d.ts create mode 100644 dist/injectHighlightWrappers.spec.data.d.ts create mode 100644 dist/injectHighlightWrappers.spec.data.js create mode 100644 dist/injectHighlightWrappers.spec.data.js.map create mode 100644 dist/injectHighlightWrappers.spec.js create mode 100644 dist/injectHighlightWrappers.spec.js.map create mode 100644 dist/rangeContents.d.ts create mode 100644 dist/rangeContents.js create mode 100644 dist/rangeContents.js.map create mode 100644 dist/removeHighlightWrappers.d.ts create mode 100644 dist/removeHighlightWrappers.js create mode 100644 dist/removeHighlightWrappers.js.map create mode 100644 dist/selection.d.ts create mode 100644 dist/selection.js create mode 100644 dist/selection.js.map create mode 100644 dist/serializationStrategies/TextPositionSelector/index.d.ts create mode 100644 dist/serializationStrategies/TextPositionSelector/index.js create mode 100644 dist/serializationStrategies/TextPositionSelector/index.js.map create mode 100644 dist/serializationStrategies/XpathRangeSelector/index.d.ts create mode 100644 dist/serializationStrategies/XpathRangeSelector/index.js create mode 100644 dist/serializationStrategies/XpathRangeSelector/index.js.map create mode 100644 dist/serializationStrategies/XpathRangeSelector/index.spec.d.ts create mode 100644 dist/serializationStrategies/XpathRangeSelector/index.spec.js create mode 100644 dist/serializationStrategies/XpathRangeSelector/index.spec.js.map create mode 100644 dist/serializationStrategies/XpathRangeSelector/xpath.d.ts create mode 100644 dist/serializationStrategies/XpathRangeSelector/xpath.js create mode 100644 dist/serializationStrategies/XpathRangeSelector/xpath.js.map create mode 100644 dist/serializationStrategies/index.d.ts create mode 100644 dist/serializationStrategies/index.js create mode 100644 dist/serializationStrategies/index.js.map diff --git a/dist/Highlight.d.ts b/dist/Highlight.d.ts new file mode 100644 index 0000000..e93dc05 --- /dev/null +++ b/dist/Highlight.d.ts @@ -0,0 +1,45 @@ +import SerializedHighlight from './SerializedHighlight'; +export declare const FOCUS_CSS = "focus"; +export interface IHighlightData { + style?: string; + id: string; + content: string; +} +export interface IOptions { + skipIDsBy?: RegExp; + formatMessage: (descriptor: { + id: string; + }, values: { + style: IHighlightData['style']; + }) => string; +} +export default class Highlight { + readonly id: string; + readonly content: string; + elements: HTMLElement[]; + readonly range: Range; + readonly options: IOptions; + private data; + private _elements; + constructor(range: Range, data: Pick> & Partial>, options: IOptions); + getMessage(id: string): string; + setStyle(style: string): void; + getStyle(): string | undefined; + removeStyle(): void; + isAttached(): boolean; + scrollTo(handler?: (elements: HTMLElement[]) => void): Highlight; + /** + * Add class 'focus' to all elements of this highlight. + */ + addFocusedStyles(): Highlight; + /** + * Move focus to the first element of this highlight. + * @return boolean indicating if the action was a success. + */ + focus(): boolean; + intersects(range: Range): boolean; + serialize(referenceElement?: HTMLElement): SerializedHighlight; + private loadStyle; + private checkReferenceElement; + private getValidReferenceElement; +} diff --git a/dist/Highlight.js b/dist/Highlight.js new file mode 100644 index 0000000..fe4259a --- /dev/null +++ b/dist/Highlight.js @@ -0,0 +1,133 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const uuid = require("uuid/v4"); +const dom_1 = require("./dom"); +const injectHighlightWrappers_1 = require("./injectHighlightWrappers"); +const SerializedHighlight_1 = require("./SerializedHighlight"); +exports.FOCUS_CSS = 'focus'; +class Highlight { + constructor(range, data, options) { + this._elements = []; + this.range = range; + this.options = options; + this.data = Object.assign({}, data, { id: data.id || uuid() }); + } + get id() { + return this.data.id; + } + get content() { + return this.data.content; + } + set elements(elements) { + if (this.elements.length > 0) { + throw new Error(`Hightlight elements aren't reloadable`); + } + this._elements = elements; + this.loadStyle(); + } + get elements() { + return this._elements; + } + getMessage(id) { + return this.options.formatMessage({ id }, { style: this.data.style }); + } + setStyle(style) { + this.removeStyle(); + this.data.style = style; + this.loadStyle(); + } + getStyle() { + return this.data.style; + } + removeStyle() { + const { style } = this.data; + if (style) { + this.elements.forEach((element) => element.classList.remove(style)); + delete this.data.style; + } + } + isAttached() { + // TODO - check and see if these are in the dom + return this.elements.length > 0; + } + scrollTo(handler) { + if (!this.isAttached()) { + return this; + } + else if (handler) { + handler(this.elements); + } + else { + this.elements[0].scrollIntoView(); + } + return this; + } + /** + * Add class 'focus' to all elements of this highlight. + */ + addFocusedStyles() { + this.elements.forEach((el) => el.classList.add(exports.FOCUS_CSS)); + return this; + } + /** + * Move focus to the first element of this highlight. + * @return boolean indicating if the action was a success. + */ + focus() { + const focusableElement = this.elements[0].querySelector(injectHighlightWrappers_1.DATA_SCREEN_READERS_ATTR_SELECTOR); + if (focusableElement) { + focusableElement.focus(); + return true; + } + return false; + } + intersects(range) { + if (!range) { + return false; + } + return this.range.compareBoundaryPoints(Range.START_TO_END, range) !== -1 + && this.range.compareBoundaryPoints(Range.END_TO_START, range) !== 1; + } + serialize(referenceElement) { + const validReferenceElement = this.getValidReferenceElement(referenceElement); + if (!validReferenceElement) { + throw new Error('reference element not found'); + } + return new SerializedHighlight_1.default(Object.assign({}, this.data, SerializedHighlight_1.default.defaultSerializer(this.range, validReferenceElement))); + } + loadStyle() { + const { style } = this.data; + if (style) { + this.elements.forEach((element) => element.classList.add(style)); + } + } + checkReferenceElement(referenceElement) { + if (!referenceElement || !referenceElement.id) { + return false; + } + if (!this.options.skipIDsBy) { + return true; + } + else { + return !this.options.skipIDsBy.test(referenceElement.id); + } + } + getValidReferenceElement(referenceElement) { + if (!referenceElement) { + referenceElement = dom_1.default(this.range.commonAncestorContainer).closest('[id]'); + } + const parentElement = referenceElement && referenceElement.parentElement; + if (this.checkReferenceElement(referenceElement)) { + return referenceElement; + } + else if (parentElement) { + const nextReferenceElement = dom_1.default(parentElement).closest('[id]'); + return this.getValidReferenceElement(nextReferenceElement); + } + else { + return null; + } + } +} +exports.default = Highlight; +//# sourceMappingURL=Highlight.js.map \ No newline at end of file diff --git a/dist/Highlight.js.map b/dist/Highlight.js.map new file mode 100644 index 0000000..a57af0c --- /dev/null +++ b/dist/Highlight.js.map @@ -0,0 +1 @@ +{"version":3,"file":"Highlight.js","sourceRoot":"","sources":["../src/Highlight.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/Highlighter.d.ts b/dist/Highlighter.d.ts new file mode 100644 index 0000000..e4ff4f1 --- /dev/null +++ b/dist/Highlighter.d.ts @@ -0,0 +1,53 @@ +import Highlight, { IHighlightData, IOptions as HighlightOptions } from './Highlight'; +import SerializedHighlight from './SerializedHighlight'; +export declare const ON_SELECT_DELAY = 300; +interface IOptions { + snapCode?: boolean; + snapTableRows?: boolean; + snapMathJax?: boolean; + snapWords?: boolean; + className?: string; + skipIDsBy?: RegExp; + formatMessage: (descriptor: { + id: string; + }, values: { + style: IHighlightData['style']; + }) => string; + onClick?: (highlight: Highlight | undefined, event: MouseEvent) => void; + onSelect?: (highlights: Highlight[], newHighlight?: Highlight) => void; + onFocusIn?: (highlight: Highlight) => void; + onFocusOut?: (highlight: Highlight) => void; +} +export default class Highlighter { + readonly container: HTMLElement; + private highlights; + private options; + private previousRange; + private focusInHandler; + private focusOutHandler; + constructor(container: HTMLElement, options: IOptions); + unmount(): void; + eraseAll: () => void; + teardown: () => void; + erase: (highlight: Highlight) => void; + highlight(highlight?: Highlight | SerializedHighlight): void; + getHighlight(id: string): Highlight | undefined; + getReferenceElement(id: string): HTMLElement | null; + clearFocusedStyles(): void; + getHighlights(): Highlight[]; + getHighlightOptions(): HighlightOptions; + getOrderedHighlights(): Highlight[]; + getHighlightBefore(target: Highlight): Highlight | undefined; + getHighlightAfter(target: Highlight): Highlight | undefined; + readonly document: Document; + private snapSelection; + private debouncedSnapSelection; + private debouncedOnSelect; + private onSelectionChange; + private onClickHandler; + private onFocusHandler; + private onClick; + private onSelect; + private compareRanges; +} +export {}; diff --git a/dist/Highlighter.js b/dist/Highlighter.js new file mode 100644 index 0000000..96c4c6e --- /dev/null +++ b/dist/Highlighter.js @@ -0,0 +1,204 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const lodash_1 = require("lodash"); +const dom_1 = require("./dom"); +const Highlight_1 = require("./Highlight"); +const injectHighlightWrappers_1 = require("./injectHighlightWrappers"); +const rangeContents_1 = require("./rangeContents"); +const removeHighlightWrappers_1 = require("./removeHighlightWrappers"); +const selection_1 = require("./selection"); +const SerializedHighlight_1 = require("./SerializedHighlight"); +exports.ON_SELECT_DELAY = 300; +class Highlighter { + constructor(container, options) { + this.highlights = {}; + this.previousRange = null; + this.eraseAll = () => { + this.getHighlights().forEach(this.erase); + }; + this.teardown = () => { + this.eraseAll(); + this.unmount(); + }; + this.erase = (highlight) => { + removeHighlightWrappers_1.default(highlight); + delete this.highlights[highlight.id]; + }; + this.snapSelection = () => { + const selection = this.document.getSelection(); + if (!selection || selection.isCollapsed) { + return; + } + return selection_1.snapSelection(selection, this.options); + }; + // Created in the constructor + this.debouncedSnapSelection = () => undefined; + // Created in the constructor + this.debouncedOnSelect = () => undefined; + this.onSelectionChange = () => { + const selection = this.document.getSelection(); + if (!selection + || selection.isCollapsed + || selection.type === 'None' + || !dom_1.default(this.container).contains(selection.anchorNode) + || !dom_1.default(this.container).contains(selection.focusNode) + || this.compareRanges(selection ? selection_1.getRange(selection) : null, this.previousRange) + || window.matchMedia('not all and (pointer: fine), (hover: none)').matches // noop for touch devices + ) { + return; + } + this.debouncedSnapSelection(); + }; + this.onClickHandler = (event) => { + this.onClick(event); + }; + this.onFocusHandler = (type) => (ev) => { + const handler = type === 'in' ? this.options.onFocusIn : this.options.onFocusOut; + if (!handler) { + return; + } + const highlightId = dom_1.isHtmlElement(ev.target) && ev.target.hasAttribute(injectHighlightWrappers_1.DATA_SCREEN_READERS_ATTR) + ? ev.target.getAttribute(injectHighlightWrappers_1.DATA_ID_ATTR) + : null; + const highlight = highlightId ? this.getHighlight(highlightId) : null; + if (highlight) { + handler(highlight); + } + }; + this.onSelect = () => { + const { onSelect } = this.options; + const selection = document.getSelection(); + if (!selection + || !dom_1.default(this.container).contains(selection.anchorNode) + || !dom_1.default(this.container).contains(selection.focusNode)) { + return; + } + const range = this.snapSelection(); + this.previousRange = range || null; + if (onSelect && range) { + const highlights = Object.values(this.highlights) + .filter((other) => other.intersects(range)); + if (highlights.length === 0) { + const highlight = new Highlight_1.default(range, { content: rangeContents_1.rangeContentsString(range) }, this.getHighlightOptions()); + onSelect(highlights, highlight); + } + else { + onSelect(highlights); + } + } + }; + this.container = container; + this.options = Object.assign({ className: 'highlight', onFocusIn: (highlight) => { + this.clearFocusedStyles(); + highlight.addFocusedStyles(); + }, onFocusOut: () => { + this.clearFocusedStyles(); + } }, options); + this.debouncedSnapSelection = lodash_1.debounce(this.snapSelection, exports.ON_SELECT_DELAY); + this.debouncedOnSelect = lodash_1.debounce(this.onSelect, exports.ON_SELECT_DELAY); + this.focusInHandler = this.onFocusHandler('in'); + this.focusOutHandler = this.onFocusHandler('out'); + this.container.addEventListener('click', this.onClickHandler); + document.addEventListener('selectionchange', this.onSelectionChange); + this.container.addEventListener('keyup', this.debouncedOnSelect); + this.container.addEventListener('mouseup', this.onSelect); + this.container.addEventListener('focusin', this.focusInHandler); + this.container.addEventListener('focusout', this.focusOutHandler); + } + unmount() { + this.container.removeEventListener('click', this.onClickHandler); + document.removeEventListener('selectionchange', this.onSelectionChange); + this.container.removeEventListener('keyup', this.debouncedOnSelect); + this.container.removeEventListener('mouseup', this.onSelect); + this.container.removeEventListener('focusin', this.focusInHandler); + this.container.removeEventListener('focusout', this.focusOutHandler); + } + highlight(highlight) { + if (highlight instanceof SerializedHighlight_1.default && highlight.isLoadable(this)) { + return this.highlight(highlight.load(this)); + } + else if (highlight instanceof Highlight_1.default) { + this.highlights[highlight.id] = highlight; + injectHighlightWrappers_1.default(highlight, this.options); + } + } + getHighlight(id) { + return this.highlights[id]; + } + getReferenceElement(id) { + return this.container.querySelector(`[id="${id}"]`); + } + clearFocusedStyles() { + this.container.querySelectorAll(`.${this.options.className}.${Highlight_1.FOCUS_CSS}`) + .forEach((el) => el.classList.remove(Highlight_1.FOCUS_CSS)); + } + getHighlights() { + return Object.values(this.highlights); + } + getHighlightOptions() { + const { formatMessage, skipIDsBy } = this.options; + return { + formatMessage, + skipIDsBy, + }; + } + getOrderedHighlights() { + const highlights = Object.values(this.highlights); + highlights.sort((a, b) => { + return a.range.compareBoundaryPoints(Range.START_TO_START, b.range); + }); + return highlights; + } + getHighlightBefore(target) { + return this.getOrderedHighlights().filter((highlight) => highlight.id !== target.id && + highlight.range.compareBoundaryPoints(Range.START_TO_START, target.range) < 0).pop(); + } + getHighlightAfter(target) { + return this.getOrderedHighlights().filter((highlight) => highlight.id !== target.id && + highlight.range.compareBoundaryPoints(Range.START_TO_START, target.range) >= 0).shift(); + } + get document() { + if (!this.container.ownerDocument) { + throw new Error('highlighter container is not mounted to a document!'); + } + return this.container.ownerDocument; + } + onClick(event) { + const { onClick } = this.options; + let target = event.target; + if (!onClick) { + return; + } + if (dom_1.default(target).isHtmlElement) { + target = dom_1.default(target); + while (target.isHtmlElement) { + if (target.el.getAttribute(injectHighlightWrappers_1.DATA_ATTR)) { + // there may be multiple highlighters active on the same document, + // check if the found highlight is known to this instance + const highlight = this.highlights[target.el.getAttribute(injectHighlightWrappers_1.DATA_ID_ATTR)]; + if (highlight) { + onClick(highlight, event); + return; + } + } + target = dom_1.default(target.el.parentElement); + } + } + onClick(undefined, event); + } + compareRanges(range1, range2) { + if (range1 === null && range2 === null) { + return true; + } + if (range1 === null && range2) { + return false; + } + if (range2 === null && range1) { + return false; + } + return range1.compareBoundaryPoints(Range.START_TO_START, range2) === 0 + && range1.compareBoundaryPoints(Range.END_TO_END, range2) === 0; + } +} +exports.default = Highlighter; +//# sourceMappingURL=Highlighter.js.map \ No newline at end of file diff --git a/dist/Highlighter.js.map b/dist/Highlighter.js.map new file mode 100644 index 0000000..38b7f45 --- /dev/null +++ b/dist/Highlighter.js.map @@ -0,0 +1 @@ +{"version":3,"file":"Highlighter.js","sourceRoot":"","sources":["../src/Highlighter.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/Highlighter.test.d.ts b/dist/Highlighter.test.d.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/dist/Highlighter.test.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/dist/Highlighter.test.js b/dist/Highlighter.test.js new file mode 100644 index 0000000..0f25ae3 --- /dev/null +++ b/dist/Highlighter.test.js @@ -0,0 +1,212 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const lodash = require("lodash"); +const Highlight_1 = require("./Highlight"); +const Highlighter_1 = require("./Highlighter"); +const injectHighlightWrappersUtils = require("./injectHighlightWrappers"); +const rangeContents = require("./rangeContents"); +const selection = require("./selection"); +describe('Reference elements', () => { + test('resolve', () => { + document.body.innerHTML = ` +
+
+
+
+
+ `; + const container = document.getElementById('container'); + const reference = document.getElementById('referenceElement2'); + if (!container) { + throw new Error('cannot find container'); + } + const highlighter = new Highlighter_1.default(container, { formatMessage: jest.fn() }); + expect(highlighter.getReferenceElement('referenceElement2')).toEqual(reference); + }); + test('do not resolve outside the container', () => { + document.body.innerHTML = ` +
+
+
+
+
+
+
+ `; + const container = document.getElementById('container'); + if (!container) { + throw new Error('can\'t find container'); + } + const highlighter = new Highlighter_1.default(container, { formatMessage: jest.fn() }); + expect(highlighter.getReferenceElement('referenceElement1')).toEqual(null); + }); +}); +describe('onClick', () => { + test('handle clicks inside of the container', () => { + const spyOnClick = jest.fn(); + const container = document.createElement('div'); + // tslint:disable-next-line no-unused-expression + new Highlighter_1.default(container, { onClick: spyOnClick, formatMessage: jest.fn() }); + const e = document.createEvent('MouseEvent'); + e.initEvent('click', true, true); + container.dispatchEvent(e); + expect(spyOnClick).toHaveBeenCalledWith(undefined, e); + }); + test('handle clicks on the highlights', () => { + const spyOnClick = jest.fn(); + const spyInjectHighlightWrappersUtils = jest.fn(); + const container = document.createElement('div'); + const highlightElement = document.createElement('span'); + highlightElement.setAttribute(injectHighlightWrappersUtils.DATA_ATTR, 'highlight'); + highlightElement.setAttribute(injectHighlightWrappersUtils.DATA_ID_ATTR, 'some-highlight'); + container.append(highlightElement); + const highlight = new Highlight_1.default(new Range(), { id: 'some-highlight', content: 'asd' }, { formatMessage: jest.fn() }); + jest.spyOn(injectHighlightWrappersUtils, 'default') + .mockImplementation(spyInjectHighlightWrappersUtils); + // tslint:disable-next-line no-unused-expression + const highlighter = new Highlighter_1.default(container, { onClick: spyOnClick, formatMessage: jest.fn() }); + highlighter.highlight(highlight); + const e = document.createEvent('MouseEvent'); + e.initEvent('click', true, true); + Object.defineProperty(e, 'target', { value: highlightElement }); + container.dispatchEvent(e); + expect(spyInjectHighlightWrappersUtils).toHaveBeenCalledWith(highlight, expect.anything()); + expect(spyOnClick).toHaveBeenCalledWith(highlight, e); + }); + test('does not handle clicks outside of the container', () => { + const spyOnClick = jest.fn(); + const container = document.createElement('div'); + // tslint:disable-next-line no-unused-expression + new Highlighter_1.default(container, { onClick: spyOnClick, formatMessage: jest.fn() }); + const e = document.createEvent('MouseEvent'); + e.initEvent('click', true, true); + document.dispatchEvent(e); + expect(spyOnClick).not.toHaveBeenCalled(); + }); +}); +describe('onSelect', () => { + let getSelectionSpy; + let snapSelectionSpy; + let rangeContentsStringSpy; + jest.useFakeTimers(); + beforeEach(() => { + getSelectionSpy = jest.spyOn(document, 'getSelection'); + snapSelectionSpy = jest.spyOn(selection, 'snapSelection'); + rangeContentsStringSpy = jest.spyOn(rangeContents, 'rangeContentsString'); + rangeContentsStringSpy.mockImplementation(() => ''); + }); + afterEach(() => { + getSelectionSpy.mockRestore(); + snapSelectionSpy.mockRestore(); + rangeContentsStringSpy.mockRestore(); + }); + it('returns a highlight with the snapped range, even if document selection returns something completely different (looking at you safari)', () => { + let highlight; + const container = document.createElement('div'); + const node = document.createElement('div'); + node.innerHTML = 'some text'; + container.appendChild(node); + window.matchMedia = () => ({ matches: false }); // doesnt match touch device media query + const spyDebounce = jest.spyOn(lodash, 'debounce') + .mockImplementation((fn) => fn); + // tslint:disable-next-line no-unused-expression + new Highlighter_1.default(container, { formatMessage: jest.fn(), onSelect: (_, newHighlight) => highlight = newHighlight }); + expect(spyDebounce).toHaveBeenCalled(); + const inputSelection = new Selection(); + const selectionRange = new Range(); + const snappedRange = new Range(); + selectionRange.setStart(node, 0); + selectionRange.setEnd(node, 5); + selectionRange.setStart(node, 0); + selectionRange.setEnd(node, 5); + Object.defineProperty(inputSelection, 'isCollapsed', { value: false }); + Object.defineProperty(inputSelection, 'anchorNode', { value: node }); + Object.defineProperty(inputSelection, 'focusNode', { value: node }); + inputSelection.setBaseAndExtent = jest.fn(() => inputSelection); + inputSelection.getRangeAt = jest.fn(() => selectionRange); + snapSelectionSpy.mockImplementation(() => snappedRange); + getSelectionSpy.mockImplementation(() => inputSelection); + const e = document.createEvent('Event'); + e.initEvent('selectionchange', true, true); + document.dispatchEvent(e); + const eKeyUp = document.createEvent('Event'); + eKeyUp.initEvent('keyup', true, true); + container.dispatchEvent(eKeyUp); + if (highlight === undefined) { + expect(highlight).toBeDefined(); + } + else { + expect(highlight.range).not.toEqual(selectionRange); + expect(highlight.range).toEqual(snappedRange); + } + }); + it('noops on selecitonchange event if there is no selection, selection is collapsed or selection type is None', () => { + const spyOnSelect = jest.fn(); + const container = document.createElement('div'); + const node = document.createElement('div'); + container.appendChild(node); + window.matchMedia = () => ({ matches: false }); // doesnt match touch device media query + const spyDebounce = jest.spyOn(lodash, 'debounce') + .mockImplementation((fn) => fn); + // tslint:disable-next-line no-unused-expression + new Highlighter_1.default(container, { onSelect: spyOnSelect, formatMessage: jest.fn() }); + expect(spyDebounce).toHaveBeenCalled(); + getSelectionSpy.mockImplementation(() => null); + const e = document.createEvent('Event'); + e.initEvent('selectionchange', true, true); + document.dispatchEvent(e); + expect(spyOnSelect).not.toHaveBeenCalled(); + getSelectionSpy.mockImplementation(() => ({ isCollapsed: true })); + expect(spyOnSelect).not.toHaveBeenCalled(); + getSelectionSpy.mockImplementation(() => ({ isCollapsed: false, type: 'None' })); + expect(spyOnSelect).not.toHaveBeenCalled(); + }); + it('noops on selecitonchange event if anchorNode or focusNode is not in the container', () => { + const spyOnSelect = jest.fn(); + const container = document.createElement('div'); + const nodeInside = document.createElement('div'); + const nodeOutside = document.createElement('div'); + container.appendChild(nodeInside); + window.matchMedia = () => ({ matches: false }); // doesnt match touch device media query + const spyDebounce = jest.spyOn(lodash, 'debounce') + .mockImplementation((fn) => fn); + // tslint:disable-next-line no-unused-expression + new Highlighter_1.default(container, { onSelect: spyOnSelect, formatMessage: jest.fn() }); + expect(spyDebounce).toHaveBeenCalled(); + getSelectionSpy.mockImplementation(() => ({ isCollapsed: false, anchorNode: nodeOutside, focusNode: nodeInside })); + const e = document.createEvent('Event'); + e.initEvent('selectionchange', true, true); + document.dispatchEvent(e); + expect(spyOnSelect).not.toHaveBeenCalled(); + getSelectionSpy.mockImplementation(() => ({ isCollapsed: false, anchorNode: nodeInside, focusNode: nodeOutside })); + expect(spyOnSelect).not.toHaveBeenCalled(); + }); + it('noops on selectionchange event for touch devices', () => { + const spyOnSelect = jest.fn(); + const container = document.createElement('div'); + const node = document.createElement('div'); + const inputSelection = new Selection(); + const selectionRange = new Range(); + selectionRange.setStart(node, 0); + selectionRange.setEnd(node, 5); + selectionRange.setStart(node, 0); + selectionRange.setEnd(node, 5); + Object.defineProperty(inputSelection, 'isCollapsed', { value: false }); + Object.defineProperty(inputSelection, 'anchorNode', { value: node }); + Object.defineProperty(inputSelection, 'focusNode', { value: node }); + inputSelection.getRangeAt = jest.fn(() => selectionRange); + container.appendChild(node); + window.matchMedia = () => ({ matches: true }); // matches touch device media query + const spyDebounce = jest.spyOn(lodash, 'debounce') + .mockImplementation((fn) => fn); + // tslint:disable-next-line no-unused-expression + new Highlighter_1.default(container, { onSelect: spyOnSelect, formatMessage: jest.fn() }); + expect(spyDebounce).toHaveBeenCalled(); + getSelectionSpy.mockImplementation(() => inputSelection); + const e = document.createEvent('Event'); + e.initEvent('selectionchange', true, true); + document.dispatchEvent(e); + expect(spyOnSelect).not.toHaveBeenCalled(); + }); +}); +//# sourceMappingURL=Highlighter.test.js.map \ No newline at end of file diff --git a/dist/Highlighter.test.js.map b/dist/Highlighter.test.js.map new file mode 100644 index 0000000..fc0dbf4 --- /dev/null +++ b/dist/Highlighter.test.js.map @@ -0,0 +1 @@ +{"version":3,"file":"Highlighter.test.js","sourceRoot":"","sources":["../src/Highlighter.test.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/SerializedHighlight.d.ts b/dist/SerializedHighlight.d.ts new file mode 100644 index 0000000..6006f37 --- /dev/null +++ b/dist/SerializedHighlight.d.ts @@ -0,0 +1,28 @@ +import { Highlight as ApiHighlight, NewHighlight as NewApiHighlight } from './api'; +import Highlight, { IHighlightData } from './Highlight'; +import Highlighter from './Highlighter'; +import { ISerializationData } from './serializationStrategies'; +import { serialize as defaultSerializer } from './serializationStrategies/XpathRangeSelector'; +declare type Omit = Pick>; +interface IOptionalApiData { + annotation?: string; +} +declare type IData = IHighlightData & ISerializationData & IOptionalApiData; +export default class SerializedHighlight { + readonly data: IData; + readonly id: string; + readonly content: string; + static defaultSerializer: typeof defaultSerializer; + static fromApiResponse(highlight: ApiHighlight): SerializedHighlight; + private _data; + private deserializer; + constructor(data: IData & { + [key: string]: any; + }); + getApiPayload(highlighter: Highlighter, highlight: Highlight): Omit & { + id: string; + }; + isLoadable(highlighter: Highlighter): boolean; + load(highlighter: Highlighter): Highlight; +} +export {}; diff --git a/dist/SerializedHighlight.js b/dist/SerializedHighlight.js new file mode 100644 index 0000000..da637d1 --- /dev/null +++ b/dist/SerializedHighlight.js @@ -0,0 +1,92 @@ +"use strict"; +var __rest = (this && this.__rest) || function (s, e) { + var t = {}; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) + t[p] = s[p]; + if (s != null && typeof Object.getOwnPropertySymbols === "function") + for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0) + t[p[i]] = s[p[i]]; + return t; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const change_case_1 = require("change-case"); +const api_1 = require("./api"); +const Highlight_1 = require("./Highlight"); +const serializationStrategies_1 = require("./serializationStrategies"); +const XpathRangeSelector_1 = require("./serializationStrategies/XpathRangeSelector"); +const mapKeys = (transform, obj) => Object.keys(obj).reduce((result, key) => (Object.assign({}, result, { [transform(key)]: obj[key] })), {}); +class SerializedHighlight { + constructor(data) { + this._data = data; + this.deserializer = serializationStrategies_1.getDeserializer(data); + } + get data() { + return this._data; + } + get id() { + return this.data.id; + } + get content() { + return this.data.content; + } + /* + * when (if?) tutor starts using the api, remove this method and + * pull these property names down through the rest of the logic + * + * TODO - support more better api interaction when above + * refactor happens: + * - loop over locationStrategies and pick the best one instead of + * the first one + * - use location strategy bindings instead of arbitrary mapKeys + * or revise swagger definition to properly use oneOf so that it + * does it automatically + */ + static fromApiResponse(highlight) { + if (!highlight.locationStrategies) { + throw new Error('highlight with no location strategies'); + } + if (!highlight.highlightedContent) { + throw new Error('highlight with no location strategies'); + } + if (!highlight.anchor) { + throw new Error('highlight with no location strategies'); + } + return new SerializedHighlight(Object.assign({}, mapKeys(change_case_1.camelCase, highlight.locationStrategies[0]), { annotation: highlight.annotation, content: highlight.highlightedContent, id: highlight.id, referenceElementId: highlight.anchor, style: highlight.color })); + } + /* + * when (if?) tutor starts using the api, rename these fields in the rest of the code + * so that less mapping is necessary + */ + getApiPayload(highlighter, highlight) { + const _a = this.data, { id, content, style, annotation, referenceElementId } = _a, serializationData = __rest(_a, ["id", "content", "style", "annotation", "referenceElementId"]); + const prevHighlight = highlighter.getHighlightBefore(highlight); + const nextHighlight = highlighter.getHighlightAfter(highlight); + if (!style) { + throw new Error('a style is requred to create an api payload'); + } + if (!api_1.styleIsColor(style)) { + throw new Error(`style ${style} doesn't match an api color`); + } + return { + anchor: referenceElementId, + annotation, + color: style, + highlightedContent: content, + id, + locationStrategies: [mapKeys(change_case_1.snakeCase, serializationData)], + nextHighlightId: nextHighlight && nextHighlight.id, + prevHighlightId: prevHighlight && prevHighlight.id, + }; + } + isLoadable(highlighter) { + return this.deserializer.isLoadable(highlighter); + } + load(highlighter) { + const range = this.deserializer.load(highlighter); + const highlightOptions = highlighter.getHighlightOptions(); + return new Highlight_1.default(range, this.data, highlightOptions); + } +} +SerializedHighlight.defaultSerializer = XpathRangeSelector_1.serialize; +exports.default = SerializedHighlight; +//# sourceMappingURL=SerializedHighlight.js.map \ No newline at end of file diff --git a/dist/SerializedHighlight.js.map b/dist/SerializedHighlight.js.map new file mode 100644 index 0000000..951a3e6 --- /dev/null +++ b/dist/SerializedHighlight.js.map @@ -0,0 +1 @@ +{"version":3,"file":"SerializedHighlight.js","sourceRoot":"","sources":["../src/SerializedHighlight.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/api.d.ts b/dist/api.d.ts new file mode 100644 index 0000000..986e2fb --- /dev/null +++ b/dist/api.d.ts @@ -0,0 +1,3 @@ +import { NewHighlightColorEnum } from '@openstax/highlights-client'; +export * from '@openstax/highlights-client'; +export declare const styleIsColor: (style: string) => style is NewHighlightColorEnum; diff --git a/dist/api.js b/dist/api.js new file mode 100644 index 0000000..15175bc --- /dev/null +++ b/dist/api.js @@ -0,0 +1,9 @@ +"use strict"; +function __export(m) { + for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; +} +Object.defineProperty(exports, "__esModule", { value: true }); +const highlights_client_1 = require("@openstax/highlights-client"); +__export(require("@openstax/highlights-client")); +exports.styleIsColor = (style) => Object.values(highlights_client_1.NewHighlightColorEnum).includes(style); +//# sourceMappingURL=api.js.map \ No newline at end of file diff --git a/dist/api.js.map b/dist/api.js.map new file mode 100644 index 0000000..3813c51 --- /dev/null +++ b/dist/api.js.map @@ -0,0 +1 @@ +{"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":";;;;;AAAA,mEAAoE;AAEpE,iDAA4C;AAE/B,QAAA,YAAY,GAAG,CAAC,KAAa,EAAkC,EAAE,CAC5E,MAAM,CAAC,MAAM,CAAC,yCAAqB,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC"} \ No newline at end of file diff --git a/dist/dom.d.ts b/dist/dom.d.ts new file mode 100644 index 0000000..7048b12 --- /dev/null +++ b/dist/dom.d.ts @@ -0,0 +1,106 @@ +/** + * Utility functions to make DOM manipulation easier. + */ +export default function dom(el: any): { + readonly el: any; + /** + * Adds class to element. + * @param {string} className + */ + addClass(className: any): void; + /** + * Removes class from element. + * @param {string} className + */ + removeClass(className: any): void; + /** + * Prepends child nodes to base element. + * @param {Node[]} nodesToPrepend + */ + prepend(nodesToPrepend: any): void; + /** + * Appends child nodes to base element. + * @param {Node[]} nodesToAppend + */ + append(nodesToAppend: any): void; + /** + * Inserts base element after refEl. + * @param {Node} refEl - node after which base element will be inserted + * @returns {Node} - inserted element + */ + insertAfter(refEl: any): any; + /** + * Inserts base element before refEl. + * @param {Node} refEl - node before which base element will be inserted + * @returns {Node} - inserted element + */ + insertBefore(refEl: any): any; + /** + * Removes base element from DOM. + */ + remove(): void; + /** + * Returns true if base element contains given child. + * @param {Node|HTMLElement} child + * @returns {boolean} + */ + contains(child: any): any; + /** + * Wraps base element in wrapper element. + * @param {HTMLElement} wrapper + * @returns {HTMLElement} wrapper element + */ + wrap(wrapper: any): any; + /** + * Unwraps base element. + * @returns {Node[]} - child nodes of unwrapped element. + */ + unwrap(): any; + /** + * Returns array of base element parents. + * @returns {HTMLElement[]} + */ + parents(): any[]; + /** + * Normalizes text nodes within base element, ie. merges sibling text nodes and assures that every + * element node has only one text node. + * It should does the same as standard element.normalize, but IE implements it incorrectly. + */ + normalizeTextNodes(): void; + /** + * Creates dom element from given html string. + * @param {string} html + * @returns {NodeList} + */ + fromHTML(html: any): NodeListOf; + /** + * Returns first range of the window of base element. + * @returns {Range} + */ + getRange(): any; + /** + * Removes all ranges of the window of base element. + */ + removeAllRanges(): void; + /** + * Returns selection object of the window of base element. + * @returns {Selection} + */ + getSelection(): any; + /** + * Returns window of the base element. + * @returns {Window} + */ + getWindow(): any; + /** + * Returns document of the base element. + * @returns {HTMLDocument} + */ + getDocument(): any; + matches(selector: any): any; + isParent(node: any, options?: any): boolean; + closest(selector: any): any; + farthest(selector: any): any; + readonly isHtmlElement: boolean; +}; +export declare const isHtmlElement: (thing: any) => thing is HTMLElement; diff --git a/dist/dom.js b/dist/dom.js new file mode 100644 index 0000000..371bfa9 --- /dev/null +++ b/dist/dom.js @@ -0,0 +1,252 @@ +"use strict"; +// tslint:disable +/** + * Utility functions to make DOM manipulation easier. + */ +Object.defineProperty(exports, "__esModule", { value: true }); +const NODE_TYPE = { + ELEMENT_NODE: 1, + TEXT_NODE: 3, +}; +function dom(el) { + return { + get el() { + return el; + }, + /** + * Adds class to element. + * @param {string} className + */ + addClass(className) { + if (el.classList) { + el.classList.add(className); + } + else { + el.className += ' ' + className; + } + }, + /** + * Removes class from element. + * @param {string} className + */ + removeClass(className) { + if (el.classList) { + el.classList.remove(className); + } + else { + el.className = el.className.replace(new RegExp('(^|\\b)' + className + '(\\b|$)', 'gi'), ' '); + } + }, + /** + * Prepends child nodes to base element. + * @param {Node[]} nodesToPrepend + */ + prepend(nodesToPrepend) { + let nodes = Array.prototype.slice.call(nodesToPrepend), i = nodes.length; + while (i--) { + el.insertBefore(nodes[i], el.firstChild); + } + }, + /** + * Appends child nodes to base element. + * @param {Node[]} nodesToAppend + */ + append(nodesToAppend) { + const nodes = Array.prototype.slice.call(nodesToAppend); + for (let i = 0, len = nodes.length; i < len; ++i) { + el.appendChild(nodes[i]); + } + }, + /** + * Inserts base element after refEl. + * @param {Node} refEl - node after which base element will be inserted + * @returns {Node} - inserted element + */ + insertAfter(refEl) { + return refEl.parentNode.insertBefore(el, refEl.nextSibling); + }, + /** + * Inserts base element before refEl. + * @param {Node} refEl - node before which base element will be inserted + * @returns {Node} - inserted element + */ + insertBefore(refEl) { + return refEl.parentNode.insertBefore(el, refEl); + }, + /** + * Removes base element from DOM. + */ + remove() { + el.parentNode.removeChild(el); + el = null; + }, + /** + * Returns true if base element contains given child. + * @param {Node|HTMLElement} child + * @returns {boolean} + */ + contains(child) { + return el !== child && el.contains(child); + }, + /** + * Wraps base element in wrapper element. + * @param {HTMLElement} wrapper + * @returns {HTMLElement} wrapper element + */ + wrap(wrapper) { + if (el.parentNode) { + el.parentNode.insertBefore(wrapper, el); + } + wrapper.appendChild(el); + return wrapper; + }, + /** + * Unwraps base element. + * @returns {Node[]} - child nodes of unwrapped element. + */ + unwrap() { + let nodes = Array.prototype.slice.call(el.childNodes), wrapper; + nodes.forEach(function (node) { + wrapper = node.parentNode; + dom(node).insertBefore(node.parentNode); + dom(wrapper).remove(); + }); + return nodes; + }, + /** + * Returns array of base element parents. + * @returns {HTMLElement[]} + */ + parents() { + let parent, path = []; + while ((parent = el.parentNode)) { + path.push(parent); + el = parent; + } + return path; + }, + /** + * Normalizes text nodes within base element, ie. merges sibling text nodes and assures that every + * element node has only one text node. + * It should does the same as standard element.normalize, but IE implements it incorrectly. + */ + normalizeTextNodes() { + if (!el) { + return; + } + if (el.nodeType === NODE_TYPE.TEXT_NODE) { + while (el.nextSibling && el.nextSibling.nodeType === NODE_TYPE.TEXT_NODE) { + el.nodeValue += el.nextSibling.nodeValue; + el.parentNode.removeChild(el.nextSibling); + } + } + else { + dom(el.firstChild).normalizeTextNodes(); + } + dom(el.nextSibling).normalizeTextNodes(); + }, + /** + * Creates dom element from given html string. + * @param {string} html + * @returns {NodeList} + */ + fromHTML(html) { + const div = document.createElement('div'); + div.innerHTML = html; + return div.childNodes; + }, + /** + * Returns first range of the window of base element. + * @returns {Range} + */ + getRange() { + let selection = dom(el).getSelection(), range; + if (selection.rangeCount > 0) { + range = selection.getRangeAt(0); + } + return range; + }, + /** + * Removes all ranges of the window of base element. + */ + removeAllRanges() { + const selection = dom(el).getSelection(); + selection.removeAllRanges(); + }, + /** + * Returns selection object of the window of base element. + * @returns {Selection} + */ + getSelection() { + return dom(el).getWindow().getSelection(); + }, + /** + * Returns window of the base element. + * @returns {Window} + */ + getWindow() { + return dom(el).getDocument().defaultView; + }, + /** + * Returns document of the base element. + * @returns {HTMLDocument} + */ + getDocument() { + // if ownerDocument is null then el is the document itself. + return el.ownerDocument || el; + }, + matches(selector) { + const method = el.matches || el.mozMatchesSelector || el.msMatchesSelector || el.oMatchesSelector || el.webkitMatchesSelector; + return (method != null ? method.call(el, selector) : undefined); + }, + isParent(node, options) { + if (options == null) { + options = { matchSame: true }; + } + if (!parent) { + return false; + } + if (options.matchSame && (node === el)) { + return true; + } + node = node.parentNode; + while (node) { + if (node === el) { + return true; + } + node = node.parentNode; + } + return false; + }, + closest(selector) { + if (this.matches(selector)) { + return el; + } + else { + return el.parentNode ? dom(el.parentNode).closest(selector) : null; + } + }, + farthest(selector) { + const thisMatches = this.matches(selector); + if (el.parentNode && thisMatches) { + return dom(el.parentNode).farthest(selector) || el; + } + else if (el.parentNode) { + return dom(el.parentNode).farthest(selector); + } + else { + return thisMatches ? el : null; + } + }, + get isHtmlElement() { + return typeof el === 'object' + && el !== null + && el.nodeType === 1 + && el.title !== undefined + && typeof el.nodeName === 'string'; + }, + }; +} +exports.default = dom; +exports.isHtmlElement = (thing) => dom(thing).isHtmlElement; +//# sourceMappingURL=dom.js.map \ No newline at end of file diff --git a/dist/dom.js.map b/dist/dom.js.map new file mode 100644 index 0000000..9ef79ea --- /dev/null +++ b/dist/dom.js.map @@ -0,0 +1 @@ +{"version":3,"file":"dom.js","sourceRoot":"","sources":["../src/dom.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/index.d.ts b/dist/index.d.ts new file mode 100644 index 0000000..917eb08 --- /dev/null +++ b/dist/index.d.ts @@ -0,0 +1,5 @@ +import Highlight from './Highlight'; +import Highlighter from './Highlighter'; +import SerializedHighlight from './SerializedHighlight'; +export default Highlighter; +export { Highlight, SerializedHighlight, }; diff --git a/dist/index.js b/dist/index.js new file mode 100644 index 0000000..e24c0bf --- /dev/null +++ b/dist/index.js @@ -0,0 +1,9 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const Highlight_1 = require("./Highlight"); +exports.Highlight = Highlight_1.default; +const Highlighter_1 = require("./Highlighter"); +const SerializedHighlight_1 = require("./SerializedHighlight"); +exports.SerializedHighlight = SerializedHighlight_1.default; +exports.default = Highlighter_1.default; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dist/index.js.map b/dist/index.js.map new file mode 100644 index 0000000..67bc6a8 --- /dev/null +++ b/dist/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;AAAA,2CAAoC;AAOlC,oBAPK,mBAAS,CAOL;AANX,+CAAwC;AACxC,+DAAwD;AAMtD,8BANK,6BAAmB,CAML;AAJrB,kBAAe,qBAAW,CAAC"} \ No newline at end of file diff --git a/dist/injectHighlightWrappers.d.ts b/dist/injectHighlightWrappers.d.ts new file mode 100644 index 0000000..cc23e95 --- /dev/null +++ b/dist/injectHighlightWrappers.d.ts @@ -0,0 +1,14 @@ +import Highlight from './Highlight'; +export declare const TIMESTAMP_ATTR = "data-timestamp"; +export declare const DATA_ATTR = "data-highlighted"; +export declare const DATA_ATTR_SELECTOR: string; +export declare const DATA_ID_ATTR = "data-highlight-id"; +export declare const DATA_SCREEN_READERS_ATTR = "data-for-screenreaders"; +export declare const DATA_SCREEN_READERS_ATTR_SELECTOR: string; +interface IOptions { + id?: string; + timestamp?: number; + className?: string; +} +export default function injectHighlightWrappers(highlight: Highlight, options?: IOptions): void; +export {}; diff --git a/dist/injectHighlightWrappers.js b/dist/injectHighlightWrappers.js new file mode 100644 index 0000000..ab2865b --- /dev/null +++ b/dist/injectHighlightWrappers.js @@ -0,0 +1,361 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +// tslint:disable +const dom_1 = require("./dom"); +exports.TIMESTAMP_ATTR = 'data-timestamp'; +exports.DATA_ATTR = 'data-highlighted'; +exports.DATA_ATTR_SELECTOR = '[' + exports.DATA_ATTR + ']'; +exports.DATA_ID_ATTR = 'data-highlight-id'; +exports.DATA_SCREEN_READERS_ATTR = 'data-for-screenreaders'; +exports.DATA_SCREEN_READERS_ATTR_SELECTOR = '[' + exports.DATA_SCREEN_READERS_ATTR + ']'; +const NODE_TYPE = { + ELEMENT_NODE: 1, + TEXT_NODE: 3, +}; +/** + * Don't highlight content of these tags. + * @type {string[]} + */ +const IGNORE_TAGS = [ + 'SCRIPT', 'STYLE', 'SELECT', 'OPTION', 'BUTTON', 'OBJECT', 'APPLET', + 'AUDIO', 'CANVAS', 'EMBED', 'PARAM', 'METER', 'PROGRESS', +]; +/** + * Highlights can be created around these block and text elements. + */ +const BLOCK_ELEMENTS = ['img', 'iframe']; +const TEXT_ELEMENTS = ['.MathJax']; +const ALLOWED_ELEMENTS = BLOCK_ELEMENTS.concat(TEXT_ELEMENTS).join(','); +const isEmptyTextNode = (node) => node.nodeType === NODE_TYPE.TEXT_NODE && node.textContent && !node.textContent.trim().length; +const isImgOrMediaSpan = (node) => node.nodeName === 'IMG' || (node.nodeName === 'SPAN' && node.dataset.type === 'media'); +function injectHighlightWrappers(highlight, options = {}) { + const wrapper = createWrapper(Object.assign({ id: highlight.id, timestamp: Date.now() }, options)); + const createdHighlights = highlightRange(highlight.range, wrapper); + const normalizedHighlights = normalizeHighlights(highlight, createdHighlights); + if (normalizedHighlights.length === 0) { + return; + } + highlight.range.setStartBefore(normalizedHighlights[0]); + highlight.range.setEndAfter(normalizedHighlights[normalizedHighlights.length - 1]); + highlight.elements = normalizedHighlights; +} +exports.default = injectHighlightWrappers; +/** + * Create empty span with tabindex=0 and all necessary information taken from @param highlight + * and insert this node at the first position inside @param element. + * @param highlight Highlight + * @param element HTMLElement highlight element for which we will insert the starting or ending element for screenreader + * @param position start | end + */ +function createAndInsertNodeForScreenReaders(highlight, element, position) { + const node = document.createElement('span'); + node.setAttribute(exports.DATA_SCREEN_READERS_ATTR, 'true'); + node.setAttribute(exports.DATA_ID_ATTR, highlight.id); + const ariaLabel = highlight.getMessage(`i18n:highlighter:highlight:${position}`); + node.setAttribute('aria-label', ariaLabel); + if (position === 'start') { + node.setAttribute('tabindex', '0'); + element.prepend(node); + } + else { + element.append(node); + } +} +/** + * Normalizes highlights. Ensures that highlighting is done with use of the smallest possible number of + * wrapping HTML elements. + * Flattens highlights structure and merges sibling highlights. Normalizes text nodes within highlights. + * Adds "first" and "last" classes to the highlights and "text" or "block" class for each highlight depends + * on the content. + * @param {Array} highlights - highlights to normalize. + * @returns {Array} - array of normalized highlights. Order and number of returned highlights may be different than + * input highlights. + */ +function normalizeHighlights(highlight, highlights) { + let normalizedHighlights; + //flattenNestedHighlights(highlights); + mergeSiblingHighlights(highlights); + // omit removed nodes + normalizedHighlights = highlights.filter(function (hl) { + return hl.parentElement ? hl : null; + }); + normalizedHighlights = unique(normalizedHighlights); + normalizedHighlights.sort(function (a, b) { + if (!a.compareDocumentPosition) { + // support for IE8 and below + return a.sourceIndex - b.sourceIndex; + } + const position = a.compareDocumentPosition(b); + if (position & Node.DOCUMENT_POSITION_FOLLOWING || position & Node.DOCUMENT_POSITION_CONTAINED_BY) { + return -1; + } + else if (position & Node.DOCUMENT_POSITION_PRECEDING || position & Node.DOCUMENT_POSITION_CONTAINS) { + return 1; + } + else { + return 0; + } + }); + for (const [index, node] of normalizedHighlights.entries()) { + if (index === 0) { + node.classList.add('first'); + createAndInsertNodeForScreenReaders(highlight, node, 'start'); + } + if (hasBlockContent(node)) { + node.classList.add('block'); + } + else { + node.classList.add('text'); + } + if (index === (normalizedHighlights.length - 1)) { + node.classList.add('last'); + createAndInsertNodeForScreenReaders(highlight, node, 'end'); + } + } + return normalizedHighlights; +} +/** + * Check if there are block elements inside node. + * Block elements are: img and iframe. + * @param {HTMLElement} node + * @returns {boolean} + */ +function hasBlockContent(node) { + return !!node.querySelector(BLOCK_ELEMENTS.join(',')); +} +/** + * Highlights range. + * Wraps text of given range object in wrapper element. + * @param {Range} range + * @param {HTMLElement} wrapper + * @returns {Array} - array of created highlights. + */ +function highlightRange(range, wrapper) { + if (!range || range.collapsed) { + return []; + } + let result = refineRangeBoundaries(range), startContainer = result.startContainer, endContainer = result.endContainer, goDeeper = result.goDeeper, done = false, node = startContainer, highlights = [], highlight, wrapperClone; + const highlightNode = (node) => { + wrapperClone = wrapper.cloneNode(true); + wrapperClone.setAttribute(exports.DATA_ATTR, 'true'); + highlight = dom_1.default(node).wrap(wrapperClone); + highlights.push(highlight); + }; + do { + if (!node) { + done = true; + } + if (dom_1.default(node).matches(ALLOWED_ELEMENTS)) { + highlightNode(node); + goDeeper = false; + } + if (goDeeper && node.nodeType === NODE_TYPE.TEXT_NODE) { + if (IGNORE_TAGS.indexOf(node.parentNode.tagName) === -1 && node.nodeValue.trim() !== '') { + highlightNode(node); + } + goDeeper = false; + } + if (node === endContainer && !(endContainer.hasChildNodes() && goDeeper)) { + done = true; + } + if (node.tagName && IGNORE_TAGS.indexOf(node.tagName) > -1) { + if (endContainer.parentNode === node) { + done = true; + } + goDeeper = false; + } + if (goDeeper && node.hasChildNodes()) { + node = node.firstChild; + } + else if (!goDeeper && node.contains(endContainer)) { + // stops traversing of tree if endContainer is a descendent of current allowed node + // this prevents a bug where the highlighter breaks out of its bounds and scans the remainder of the page + // (happens when firefox sets the comment inside an iframe as endcontainer) + done = true; + } + else if (node.nextSibling) { + node = node.nextSibling; + goDeeper = true; + } + else { + node = node.parentNode; + goDeeper = false; + } + } while (!done); + return highlights; +} +/** + * Takes range object as parameter and refines it boundaries + * @param range + * @returns {object} refined boundaries and initial state of highlighting algorithm. + */ +function refineRangeBoundaries(range) { + let startContainer = range.startContainer, endContainer = range.endContainer, ancestor = range.commonAncestorContainer, goDeeper = true; + if (range.endOffset === 0) { + while (!endContainer.previousSibling && endContainer.parentNode !== ancestor) { + endContainer = endContainer.parentNode; + } + // use previous sibling for end container unless end container is an img/media span preceded by an empty text node + // otherwise highlights ending on an img in firefox may not display correctly due to empty text nodes around img element + if (endContainer.previousSibling && !(isImgOrMediaSpan(endContainer) && isEmptyTextNode(endContainer.previousSibling))) { + endContainer = endContainer.previousSibling; + } + } + else if (endContainer.nodeType === NODE_TYPE.TEXT_NODE) { + if (range.endOffset < endContainer.nodeValue.length) { + endContainer.splitText(range.endOffset); + } + } + else if (range.endOffset > 0) { + endContainer = endContainer.childNodes.item(range.endOffset - 1); + } + if (startContainer.nodeType === NODE_TYPE.TEXT_NODE) { + if (range.startOffset === startContainer.nodeValue.length) { + goDeeper = false; + } + else if (range.startOffset > 0) { + startContainer = startContainer.splitText(range.startOffset); + if (endContainer === startContainer.previousSibling) { + endContainer = startContainer; + } + } + } + else if (range.startOffset < startContainer.childNodes.length) { + startContainer = startContainer.childNodes.item(range.startOffset); + // use next sibling for start container unless start container is an img/media span followed by an empty text node + // otherwise highlights starting on an img in firefox may not display correctly due to empty text nodes around img element + } + else if (startContainer.nextSibling && !(isImgOrMediaSpan(startContainer) && isEmptyTextNode(startContainer.nextSibling))) { + startContainer = startContainer.nextSibling; + } + // BEGIN this might not be necessary, test removing it + const getMath = (node) => { + const mathjax = dom_1.default(node).farthest('.MathJax'); + if (mathjax) { + return mathjax; + } + const mml = dom_1.default(node).farthest('script[type="math/mml"]'); + if (mml && mml.previousSibling.matches('.MathJax')) { + return mml.previousSibling; + } + if (mml && mml.previousSibling.matches('.MathJax_Display')) { + return mml.previousSibling.querySelector('.MathJax'); + } + return null; + }; + const endMath = getMath(endContainer); + if (endMath) { + endContainer = endMath; + } + const startMath = getMath(startContainer); + if (startMath) { + startContainer = startMath; + goDeeper = false; + } + // END this might not be necessary, test removing it + return { + startContainer, + endContainer, + goDeeper, + }; +} +/** + * Flattens highlights structure. + * Note: this method changes input highlights - their order and number after calling this method may change. + * @param {Array} highlights - highlights to flatten. + */ +// @ts-ignore +function flattenNestedHighlights(highlights) { + let again; + sortByDepth(highlights, true); + function flattenOnce() { + let again = false; + highlights.forEach(function (hl, i) { + const parent = hl.parentElement, parentPrev = parent.previousSibling, parentNext = parent.nextSibling; + if (isHighlight(parent)) { + if (!haveSameColor(parent, hl)) { + if (!hl.nextSibling) { + dom_1.default(hl).insertBefore(parentNext || parent); + again = true; + } + if (!hl.previousSibling) { + dom_1.default(hl).insertAfter(parentPrev || parent); + again = true; + } + if (!parent.hasChildNodes()) { + dom_1.default(parent).remove(); + } + } + else { + parent.replaceChild(hl.firstChild, hl); + highlights[i] = parent; + again = true; + } + } + }); + return again; + } + do { + again = flattenOnce(); + } while (again); +} +/** + * Merges sibling highlights and normalizes descendant text nodes. + * Note: this method changes input highlights - their order and number after calling this method may change. + * @param highlights + */ +function mergeSiblingHighlights(highlights) { + function shouldMerge(current, node) { + return isHighlight(current) && isHighlight(node) + && current.data && node.data + && current.data.id === node.data.id; + } + highlights.forEach(function (highlight) { + const prev = highlight.previousSibling, next = highlight.nextSibling; + if (shouldMerge(highlight, prev)) { + dom_1.default(highlight).prepend(prev.childNodes); + dom_1.default(prev).remove(); + } + if (shouldMerge(highlight, next)) { + dom_1.default(highlight).append(next.childNodes); + dom_1.default(next).remove(); + } + dom_1.default(highlight).normalizeTextNodes(); + }); +} +/** + * Creates wrapper for highlights. + */ +function createWrapper(options) { + const el = document.createElement('mark'); + el.className = options.className; + if (options.timestamp) { + el.setAttribute(exports.TIMESTAMP_ATTR, options.timestamp); + } + if (options.id) { + el.setAttribute(exports.DATA_ID_ATTR, options.id); + } + return el; +} +function isHighlight(el) { + return el && el.nodeType === NODE_TYPE.ELEMENT_NODE && el.matches(exports.DATA_ATTR_SELECTOR); +} +function sortByDepth(arr, descending) { + arr.sort(function (a, b) { + return dom_1.default(descending ? b : a).parents().length - dom_1.default(descending ? a : b).parents().length; + }); +} +function haveSameColor(_, __) { + return true; +} +/** + * Returns array without duplicated values. + * @param {Array} arr + * @returns {Array} + */ +function unique(arr) { + return arr.filter(function (value, idx, self) { + return self.indexOf(value) === idx; + }); +} +//# sourceMappingURL=injectHighlightWrappers.js.map \ No newline at end of file diff --git a/dist/injectHighlightWrappers.js.map b/dist/injectHighlightWrappers.js.map new file mode 100644 index 0000000..46b55ec --- /dev/null +++ b/dist/injectHighlightWrappers.js.map @@ -0,0 +1 @@ +{"version":3,"file":"injectHighlightWrappers.js","sourceRoot":"","sources":["../src/injectHighlightWrappers.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/injectHighlightWrappers.spec.d.ts b/dist/injectHighlightWrappers.spec.d.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/dist/injectHighlightWrappers.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/dist/injectHighlightWrappers.spec.data.d.ts b/dist/injectHighlightWrappers.spec.data.d.ts new file mode 100644 index 0000000..de8d5cf --- /dev/null +++ b/dist/injectHighlightWrappers.spec.data.d.ts @@ -0,0 +1,3 @@ +export declare const paragraphFigureAndCaption = "\n
\n

A hardware store sells 16-ft ladders and 24-ft ladders. A window is located 12 feet above the ground. A ladder needs to be purchased that will reach the window from a point on the ground 5 feet from the building.

\n\n
\n
\n\n \n\n \"A\n\n \n\n
\n
\n Figure \n 1\n \n \n
\n
\n
\n"; +export declare const imageBetweenParagraphs = "\n
\n
\n

A shortcut called FOIL is sometimes used to find the product of two binomials. It is called FOIL because we multiply the first terms, the outer terms, the inner terms, and then the last terms of each binomial.

\n \n \"Two\n \n

The FOIL method arises out of the distributive property. We are simply multiplying each term of the first binomial by each term of the second binomial, and then combining like terms.

\n
\n
\n"; +export declare const adjacentTextSections = "\n
\n
\n

\n How To\n

\n
\n
\n
\n\n

\n Given multiple polynomials, add or subtract them to simplify the expressions.\n

\n
\n
\n
\n"; diff --git a/dist/injectHighlightWrappers.spec.data.js b/dist/injectHighlightWrappers.spec.data.js new file mode 100644 index 0000000..0678256 --- /dev/null +++ b/dist/injectHighlightWrappers.spec.data.js @@ -0,0 +1,55 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +// tslint:disable: max-line-length +exports.paragraphFigureAndCaption = ` +
+

A hardware store sells 16-ft ladders and 24-ft ladders. A window is located 12 feet above the ground. A ladder needs to be purchased that will reach the window from a point on the ground 5 feet from the building.

+ +
+
+ + + + A right triangle with a base of 5 feet, a height of 12 feet, and a hypotenuse labeled c + + + +
+
+ Figure + 1 + + +
+
+
+`; +exports.imageBetweenParagraphs = ` +
+
+

A shortcut called FOIL is sometimes used to find the product of two binomials. It is called FOIL because we multiply the first terms, the outer terms, the inner terms, and then the last terms of each binomial.

+ + Two quantities in parentheses are being multiplied, the first being: a times x plus b and the second being: c times x plus d. + +

The FOIL method arises out of the distributive property. We are simply multiplying each term of the first binomial by each term of the second binomial, and then combining like terms.

+
+
+`; +exports.adjacentTextSections = ` +
+
+

+ How To +

+
+
+
+ +

+ Given multiple polynomials, add or subtract them to simplify the expressions. +

+
+
+
+`; +//# sourceMappingURL=injectHighlightWrappers.spec.data.js.map \ No newline at end of file diff --git a/dist/injectHighlightWrappers.spec.data.js.map b/dist/injectHighlightWrappers.spec.data.js.map new file mode 100644 index 0000000..e2b37b1 --- /dev/null +++ b/dist/injectHighlightWrappers.spec.data.js.map @@ -0,0 +1 @@ +{"version":3,"file":"injectHighlightWrappers.spec.data.js","sourceRoot":"","sources":["../src/injectHighlightWrappers.spec.data.ts"],"names":[],"mappings":";;AAAA,kCAAkC;AACrB,QAAA,yBAAyB,GAAG;;;;;;;;;;;;;;;;;;;;;;CAsBxC,CAAC;AAEW,QAAA,sBAAsB,GAAG;;;;;;;;;;CAUrC,CAAC;AAEW,QAAA,oBAAoB,GAAG;;;;;;;;;;;;;;;;CAgBnC,CAAC"} \ No newline at end of file diff --git a/dist/injectHighlightWrappers.spec.js b/dist/injectHighlightWrappers.spec.js new file mode 100644 index 0000000..962733c --- /dev/null +++ b/dist/injectHighlightWrappers.spec.js @@ -0,0 +1,237 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const Highlight_1 = require("./Highlight"); +const Highlighter_1 = require("./Highlighter"); +const injectHighlightWrappers_1 = require("./injectHighlightWrappers"); +const injectHighlightWrappers_spec_data_1 = require("./injectHighlightWrappers.spec.data"); +const messages = { + 'i18n:highlighter:highlight:end': 'End of highlight', + 'i18n:highlighter:highlight:start': 'Start of highlight', +}; +describe('inject highlight wrappers for figure with caption', () => { + let page; + let img; + let p; + let textNode; + let span; + let captionTitle; + let captionContainer; + let captionTitleText; + let rangeDefaults; + let mockMessages; + const highlightData = { id: 'some-highlight', content: 'asd', style: 'yellow' }; + beforeEach(() => { + document.body.innerHTML = injectHighlightWrappers_spec_data_1.paragraphFigureAndCaption; + page = document.getElementById('container'); + img = document.getElementById('test-img'); + p = document.getElementById('test-p'); + textNode = p.childNodes[0]; + span = document.getElementById('test-span'); + captionContainer = document.getElementById('test-caption-container'); + captionTitle = document.getElementById('test-caption-title'); + captionTitleText = captionTitle.childNodes[0]; + Date.now = jest.fn(); + rangeDefaults = { + collapse: false, + commonAncestorContainer: page, + setEndAfter: jest.fn(), + setStartBefore: jest.fn(), + }; + mockMessages = jest.fn((descriptor) => messages[descriptor.id]); + }); + describe('for highlight ending on an ', () => { + it('in chrome and safari', () => { + const range = Object.assign({}, rangeDefaults, { endContainer: span, endOffset: 2, startContainer: textNode, startOffset: 2 }); + const highlight = new Highlight_1.default(range, highlightData, { formatMessage: mockMessages }); + const highlighter = new Highlighter_1.default(page, { onClick: jest.fn(), formatMessage: mockMessages }); + highlighter.highlight(highlight); + const highlightSpans = document.querySelectorAll(`[${injectHighlightWrappers_1.DATA_ATTR}='true']`); + highlightSpans.forEach((el) => { + el.classList.add('highlight'); + expect(el).toMatchSnapshot(); + }); + }); + it('in firefox', () => { + const range = Object.assign({}, rangeDefaults, { endContainer: captionTitleText, endOffset: 0, startContainer: textNode, startOffset: 2 }); + const highlight = new Highlight_1.default(range, highlightData, { formatMessage: mockMessages }); + const highlighter = new Highlighter_1.default(page, { onClick: jest.fn(), formatMessage: mockMessages }); + highlighter.highlight(highlight); + const highlightSpans = document.querySelectorAll(`[${injectHighlightWrappers_1.DATA_ATTR}='true']`); + highlightSpans.forEach((el) => { + expect(el).toMatchSnapshot(); + }); + }); + }); + describe('for highlight starting on an ', () => { + it('in chrome and safari', () => { + const range = Object.assign({}, rangeDefaults, { endContainer: captionTitleText, endOffset: 6, startContainer: textNode, startOffset: textNode.nodeValue.length }); + const highlight = new Highlight_1.default(range, highlightData, { formatMessage: mockMessages }); + const highlighter = new Highlighter_1.default(page, { onClick: jest.fn(), formatMessage: mockMessages }); + highlighter.highlight(highlight); + const highlightSpans = document.querySelectorAll(`[${injectHighlightWrappers_1.DATA_ATTR}='true']`); + highlightSpans.forEach((el) => { + expect(el).toMatchSnapshot(); + }); + }); + it('in firefox', () => { + const range = Object.assign({}, rangeDefaults, { endContainer: captionTitleText, endOffset: 6, startContainer: textNode, startOffset: textNode.nodeValue.length }); + const highlight = new Highlight_1.default(range, highlightData, { formatMessage: mockMessages }); + const highlighter = new Highlighter_1.default(page, { onClick: jest.fn(), formatMessage: mockMessages }); + highlighter.highlight(highlight); + const highlightSpans = document.querySelectorAll(`[${injectHighlightWrappers_1.DATA_ATTR}='true']`); + highlightSpans.forEach((el) => { + expect(el).toMatchSnapshot(); + }); + }); + }); + describe('for highlight starting on an where img is first element on page', () => { + it('in chrome', () => { + p.remove(); + const range = Object.assign({}, rangeDefaults, { endContainer: captionContainer, endOffset: 0, startContainer: span, startOffset: 1 }); + const highlight = new Highlight_1.default(range, highlightData, { formatMessage: mockMessages }); + const highlighter = new Highlighter_1.default(page, { onClick: jest.fn(), formatMessage: mockMessages }); + highlighter.highlight(highlight); + const highlightSpans = document.querySelectorAll(`[${injectHighlightWrappers_1.DATA_ATTR}='true']`); + highlightSpans.forEach((el) => { + expect(el).toMatchSnapshot(); + }); + }); + it('in firefox', () => { + p.remove(); + const range = Object.assign({}, rangeDefaults, { endContainer: img, endOffset: 0, startContainer: img, startOffset: 0 }); + const highlight = new Highlight_1.default(range, highlightData, { formatMessage: mockMessages }); + const highlighter = new Highlighter_1.default(page, { onClick: jest.fn(), formatMessage: mockMessages }); + highlighter.highlight(highlight); + const highlightSpans = document.querySelectorAll(`[${injectHighlightWrappers_1.DATA_ATTR}='true']`); + highlightSpans.forEach((el) => { + expect(el).toMatchSnapshot(); + }); + }); + it('in safari', () => { + p.remove(); + const range = Object.assign({}, rangeDefaults, { endContainer: span, endOffset: 2, startContainer: page, startOffset: 0 }); + const highlight = new Highlight_1.default(range, highlightData, { formatMessage: mockMessages }); + const highlighter = new Highlighter_1.default(page, { onClick: jest.fn(), formatMessage: mockMessages }); + highlighter.highlight(highlight); + const highlightSpans = document.querySelectorAll(`[${injectHighlightWrappers_1.DATA_ATTR}='true']`); + highlightSpans.forEach((el) => { + expect(el).toMatchSnapshot(); + }); + }); + }); + describe('for highlight starting and ending on an ', () => { + it('in chrome and safari', () => { + const range = Object.assign({}, rangeDefaults, { endContainer: span, endOffset: 2, startContainer: textNode, startOffset: textNode.nodeValue.length }); + const highlight = new Highlight_1.default(range, highlightData, { formatMessage: mockMessages }); + const highlighter = new Highlighter_1.default(page, { onClick: jest.fn(), formatMessage: mockMessages }); + highlighter.highlight(highlight); + const highlightSpans = document.querySelectorAll(`[${injectHighlightWrappers_1.DATA_ATTR}='true']`); + highlightSpans.forEach((el) => { + expect(el).toMatchSnapshot(); + }); + }); + it('in firefox', () => { + const range = Object.assign({}, rangeDefaults, { endContainer: img, endOffset: 0, startContainer: textNode, startOffset: textNode.nodeValue.length }); + const highlight = new Highlight_1.default(range, highlightData, { formatMessage: mockMessages }); + const highlighter = new Highlighter_1.default(page, { onClick: jest.fn(), formatMessage: mockMessages }); + highlighter.highlight(highlight); + const highlightSpans = document.querySelectorAll(`[${injectHighlightWrappers_1.DATA_ATTR}='true']`); + highlightSpans.forEach((el) => { + expect(el).toMatchSnapshot(); + }); + }); + }); +}); +describe('inject highlight wrappers for img between paragraphs', () => { + let section; + let p1; + let p2; + let textNode1; + let textNode2; + let rangeDefaults; + let mockMessages; + const highlightData = { id: 'some-highlight', content: 'asd', style: 'yellow' }; + beforeEach(() => { + document.body.innerHTML = injectHighlightWrappers_spec_data_1.imageBetweenParagraphs; + section = document.getElementById('container'); + p1 = document.getElementById('test-p1'); + p2 = document.getElementById('test-p2'); + textNode1 = p1.childNodes[0]; + textNode2 = p2.childNodes[0]; + Date.now = jest.fn(); + rangeDefaults = { + collapse: false, + commonAncestorContainer: section, + setEndAfter: jest.fn(), + setStartBefore: jest.fn(), + }; + mockMessages = jest.fn((descriptor) => messages[descriptor.id]); + }); + it('in firefox', () => { + const range = Object.assign({}, rangeDefaults, { endContainer: textNode2, endOffset: 0, startContainer: textNode1, startOffset: 117 }); + const highlight = new Highlight_1.default(range, highlightData, { formatMessage: mockMessages }); + const highlighter = new Highlighter_1.default(section, { onClick: jest.fn(), formatMessage: mockMessages }); + highlighter.highlight(highlight); + const highlightSpans = document.querySelectorAll(`[${injectHighlightWrappers_1.DATA_ATTR}='true']`); + highlightSpans.forEach((el) => { + expect(el).toMatchSnapshot(); + }); + }); + it('in chrome and safari', () => { + const range = Object.assign({}, rangeDefaults, { endContainer: p2, endOffset: 0, startContainer: textNode1, startOffset: 117 }); + const highlight = new Highlight_1.default(range, highlightData, { formatMessage: mockMessages }); + const highlighter = new Highlighter_1.default(section, { onClick: jest.fn(), formatMessage: mockMessages }); + highlighter.highlight(highlight); + const highlightSpans = document.querySelectorAll(`[${injectHighlightWrappers_1.DATA_ATTR}='true']`); + highlightSpans.forEach((el) => { + expect(el).toMatchSnapshot(); + }); + }); +}); +describe('inject highlight wrappers for text followed by section', () => { + let section; + let heading; + let p; + let textNode1; + let textNode2; + let rangeDefaults; + let mockMessages; + const highlightData = { id: 'some-highlight', content: 'asd', style: 'yellow' }; + beforeEach(() => { + document.body.innerHTML = injectHighlightWrappers_spec_data_1.adjacentTextSections; + section = document.getElementById('test-container'); + heading = document.getElementById('test-span'); + p = document.getElementById('test-p'); + textNode1 = heading.childNodes[0]; + textNode2 = p.childNodes[0]; + Date.now = jest.fn(); + rangeDefaults = { + collapse: false, + commonAncestorContainer: section, + setEndAfter: jest.fn(), + setStartBefore: jest.fn(), + }; + mockMessages = jest.fn((descriptor) => messages[descriptor.id]); + }); + it('in chrome and safari', () => { + const range = Object.assign({}, rangeDefaults, { endContainer: p, endOffset: 0, startContainer: textNode1, startOffset: 0 }); + const highlight = new Highlight_1.default(range, highlightData, { formatMessage: mockMessages }); + const highlighter = new Highlighter_1.default(section, { onClick: jest.fn(), formatMessage: mockMessages }); + highlighter.highlight(highlight); + const highlightSpans = document.querySelectorAll(`[${injectHighlightWrappers_1.DATA_ATTR}='true']`); + highlightSpans.forEach((el) => { + expect(el).toMatchSnapshot(); + }); + }); + it('in firefox', () => { + const range = Object.assign({}, rangeDefaults, { endContainer: textNode2, endOffset: 0, startContainer: textNode1, startOffset: 0 }); + const highlight = new Highlight_1.default(range, highlightData, { formatMessage: mockMessages }); + const highlighter = new Highlighter_1.default(section, { onClick: jest.fn(), formatMessage: mockMessages }); + highlighter.highlight(highlight); + const highlightSpans = document.querySelectorAll(`[${injectHighlightWrappers_1.DATA_ATTR}='true']`); + highlightSpans.forEach((el) => { + expect(el).toMatchSnapshot(); + }); + }); +}); +//# sourceMappingURL=injectHighlightWrappers.spec.js.map \ No newline at end of file diff --git a/dist/injectHighlightWrappers.spec.js.map b/dist/injectHighlightWrappers.spec.js.map new file mode 100644 index 0000000..4ffcbb3 --- /dev/null +++ b/dist/injectHighlightWrappers.spec.js.map @@ -0,0 +1 @@ +{"version":3,"file":"injectHighlightWrappers.spec.js","sourceRoot":"","sources":["../src/injectHighlightWrappers.spec.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/rangeContents.d.ts b/dist/rangeContents.d.ts new file mode 100644 index 0000000..b6a5937 --- /dev/null +++ b/dist/rangeContents.d.ts @@ -0,0 +1,2 @@ +export declare const rangeContentsString: (range: Range) => string; +export declare const cloneRangeContents: (range: Range) => DocumentFragment; diff --git a/dist/rangeContents.js b/dist/rangeContents.js new file mode 100644 index 0000000..419da20 --- /dev/null +++ b/dist/rangeContents.js @@ -0,0 +1,83 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const dom_1 = require("./dom"); +const removeHighlightWrappers_1 = require("./removeHighlightWrappers"); +exports.rangeContentsString = (range) => { + const fragment = exports.cloneRangeContents(range); + const container = document.createElement('div'); + const removeAll = (nodes) => nodes.forEach((element) => element.remove()); + container.appendChild(fragment); + removeAll(container.querySelectorAll('.MathJax')); + removeAll(container.querySelectorAll('.MathJax_Display')); + removeAll(container.querySelectorAll('.MathJax_Preview')); + removeAll(container.querySelectorAll('.MJX_Assistive_MathML')); + removeHighlightWrappers_1.removeAllHighlights(container); + container.querySelectorAll('script[type="math/mml"]').forEach((element) => { + const template = document.createElement('template'); + template.innerHTML = element.textContent || ''; + const math = template.content.firstChild; + if (math && element.parentElement) { + element.parentElement.insertBefore(math, element); + element.remove(); + } + }); + return container.innerHTML; +}; +exports.cloneRangeContents = (range) => { + const tableTags = ['TR', 'TBODY', 'TABLE']; + const fragment = document.createDocumentFragment(); + const getStartNode = () => { + if (range.commonAncestorContainer.nodeType === 3 /* #text */) { + return range.commonAncestorContainer.parentNode; + } + else if (tableTags.indexOf(range.commonAncestorContainer.nodeName) > -1) { + return dom_1.default(range.commonAncestorContainer).closest('table').parentNode; + } + else { + return range.commonAncestorContainer; + } + }; + cloneForRange(getStartNode(), range).childNodes.forEach((node) => fragment.appendChild(node.cloneNode(true))); + return fragment; +}; +function cloneForRange(element, range, foundStart = false) { + const isStart = (node) => node.parentElement === range.startContainer + && Array.prototype.indexOf.call(range.startContainer.childNodes, node) === range.startOffset; + const isEnd = (node) => node.parentElement === range.endContainer + && Array.prototype.indexOf.call(range.endContainer.childNodes, node) === range.endOffset; + const result = element.cloneNode(); + if (element.nodeType === 3 /* #text */) { + if (element === range.startContainer && element === range.endContainer) { + result.textContent = (element.textContent || '').substring(range.startOffset, range.endOffset + 1); + } + else if (element === range.startContainer) { + result.textContent = (element.textContent || '').substring(range.startOffset); + } + else if (element === range.endContainer) { + result.textContent = (element.textContent || '').substring(0, range.endOffset); + } + else { + result.textContent = element.textContent; + } + } + else { + let node = element.firstChild; + let foundEnd; + while (node && !isEnd(node) && !foundEnd) { + foundStart = foundStart || isStart(node); + foundEnd = dom_1.default(node).isParent(range.endContainer); + if (foundStart && !foundEnd) { + const copy = node.cloneNode(true); + result.appendChild(copy); + } + else if (foundStart || dom_1.default(node).isParent(range.startContainer)) { + const copy = cloneForRange(node, range, foundStart); + result.appendChild(copy); + foundStart = true; + } + node = node.nextSibling; + } + } + return result; +} +//# sourceMappingURL=rangeContents.js.map \ No newline at end of file diff --git a/dist/rangeContents.js.map b/dist/rangeContents.js.map new file mode 100644 index 0000000..18ef40d --- /dev/null +++ b/dist/rangeContents.js.map @@ -0,0 +1 @@ +{"version":3,"file":"rangeContents.js","sourceRoot":"","sources":["../src/rangeContents.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/removeHighlightWrappers.d.ts b/dist/removeHighlightWrappers.d.ts new file mode 100644 index 0000000..3405ce8 --- /dev/null +++ b/dist/removeHighlightWrappers.d.ts @@ -0,0 +1,8 @@ +import Highlight from './Highlight'; +/** + * Removes highlights from element. If element is a highlight itself, it is removed as well. + * If no element is given, all highlights all removed. + * @param {HTMLElement} [element] - element to remove highlights from + */ +export declare function removeAllHighlights(element: HTMLElement): void; +export default function (highlight: Highlight): void; diff --git a/dist/removeHighlightWrappers.js b/dist/removeHighlightWrappers.js new file mode 100644 index 0000000..6336861 --- /dev/null +++ b/dist/removeHighlightWrappers.js @@ -0,0 +1,80 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +// tslint:disable +const dom_1 = require("./dom"); +const injectHighlightWrappers_1 = require("./injectHighlightWrappers"); +const NODE_TYPE = { + ELEMENT_NODE: 1, + TEXT_NODE: 3, +}; +/** + * Removes highlights from element. If element is a highlight itself, it is removed as well. + * If no element is given, all highlights all removed. + * @param {HTMLElement} [element] - element to remove highlights from + */ +function removeAllHighlights(element) { + getHighlights(element).forEach(removeHighlightElement); +} +exports.removeAllHighlights = removeAllHighlights; +function default_1(highlight) { + highlight.elements.forEach(removeHighlightElement); +} +exports.default = default_1; +function removeHighlightElement(element) { + getScreenReaderLabels(element).forEach((label) => label.remove()); + const container = element, highlights = getHighlights(container); + function mergeSiblingTextNodes(textNode) { + const prev = textNode.previousSibling, next = textNode.nextSibling; + if (prev && prev.nodeType === NODE_TYPE.TEXT_NODE) { + textNode.nodeValue = prev.nodeValue + textNode.nodeValue; + dom_1.default(prev).remove(); + } + if (next && next.nodeType === NODE_TYPE.TEXT_NODE) { + textNode.nodeValue = textNode.nodeValue + next.nodeValue; + dom_1.default(next).remove(); + } + } + function removeHighlight(highlight) { + const textNodes = dom_1.default(highlight).unwrap(); + textNodes.forEach(function (node) { + mergeSiblingTextNodes(node); + }); + } + sortByDepth(highlights, true); + highlights.forEach(removeHighlight); +} +/** + * Returns highlights from given container. + * @param {HTMLElement} container - return highlights from this element + * @returns {Array} - array of highlights. + */ +function getHighlights(container) { + const nodeList = container.querySelectorAll(injectHighlightWrappers_1.DATA_ATTR_SELECTOR), highlights = Array.prototype.slice.call(nodeList); + if (container.matches(injectHighlightWrappers_1.DATA_ATTR_SELECTOR)) { + highlights.push(container); + } + return highlights; +} +/** + * Returns screenreader labels from given container. + * @param {HTMLElement} container - return nodes created for screenreder from this element + * @returns {Array} - array of screenreader HTMLElements. + */ +function getScreenReaderLabels(container) { + const nodeList = container.querySelectorAll(injectHighlightWrappers_1.DATA_SCREEN_READERS_ATTR_SELECTOR), screenreaderLabels = Array.prototype.slice.call(nodeList); + if (container.matches(injectHighlightWrappers_1.DATA_SCREEN_READERS_ATTR_SELECTOR)) { + screenreaderLabels.push(container); + } + return screenreaderLabels; +} +/** + * Sorts array of DOM elements by its depth in DOM tree. + * @param {HTMLElement[]} arr - array to sort. + * @param {boolean} descending - order of sort. + */ +function sortByDepth(arr, descending) { + arr.sort(function (a, b) { + return dom_1.default(descending ? b : a).parents().length - dom_1.default(descending ? a : b).parents().length; + }); +} +//# sourceMappingURL=removeHighlightWrappers.js.map \ No newline at end of file diff --git a/dist/removeHighlightWrappers.js.map b/dist/removeHighlightWrappers.js.map new file mode 100644 index 0000000..b0cfd81 --- /dev/null +++ b/dist/removeHighlightWrappers.js.map @@ -0,0 +1 @@ +{"version":3,"file":"removeHighlightWrappers.js","sourceRoot":"","sources":["../src/removeHighlightWrappers.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/selection.d.ts b/dist/selection.d.ts new file mode 100644 index 0000000..97a55c8 --- /dev/null +++ b/dist/selection.d.ts @@ -0,0 +1,9 @@ +export declare const getRange: (selection: Selection) => Range; +interface IOptions { + snapTableRows?: boolean; + snapMathJax?: boolean; + snapWords?: boolean; + snapCode?: boolean; +} +export declare const snapSelection: (selection: Selection, options: IOptions) => Range | undefined; +export {}; diff --git a/dist/selection.js b/dist/selection.js new file mode 100644 index 0000000..1297b59 --- /dev/null +++ b/dist/selection.js @@ -0,0 +1,126 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const dom_1 = require("./dom"); +exports.getRange = (selection) => { + if (selection.rangeCount < 1) { + throw new Error('selection had no ranges'); + } + // set up range to modify + const range = selection.getRangeAt(0).cloneRange(); + const endRange = selection.getRangeAt(selection.rangeCount - 1); + range.setEnd(endRange.endContainer, endRange.endOffset); + return range; +}; +const getDirection = (selection) => { + const anchorNode = selection.anchorNode; + const anchorOffset = selection.anchorOffset; + const range = exports.getRange(selection); + if (anchorNode !== range.startContainer || anchorOffset !== range.startOffset) { + return 'backward'; + } + return 'forward'; +}; +const snapToCode = (range) => { + const getCode = (node) => dom_1.default(node).farthest('[data-type="code"]'); + const startCode = getCode(range.startContainer.nodeType === 3 /* #text */ + ? range.startContainer + : range.startContainer.childNodes[range.startOffset] || range.startContainer); + if (startCode) { + range.setStartBefore(startCode); + } + const endCode = getCode(range.endContainer.nodeType === 3 /* #text */ + ? range.endContainer + : range.endContainer.childNodes[range.endOffset - 1] || range.endContainer); + if (endCode) { + const endContainer = endCode.parentNode; + range.setEnd(endContainer, Array.prototype.indexOf.call(endContainer.childNodes, endCode) + 1); + } +}; +const snapToMath = (range) => { + const getMath = (node) => dom_1.default(node).farthest('.MathJax,.MathJax_Display'); + const startMath = getMath(range.startContainer.nodeType === 3 /* #text */ + ? range.startContainer + : range.startContainer.childNodes[range.startOffset] || range.startContainer); + if (startMath) { + range.setStartBefore(startMath); + } + const endMath = getMath(range.endContainer.nodeType === 3 /* #text */ + ? range.endContainer + : range.endContainer.childNodes[range.endOffset - 1] || range.endContainer); + if (endMath) { + const endElement = dom_1.default(endMath.nextSibling).matches('script[type="math/mml"]') ? endMath.nextSibling : endMath; + const endContainer = endElement.parentNode; + range.setEnd(endContainer, Array.prototype.indexOf.call(endContainer.childNodes, endElement) + 1); + } +}; +exports.snapSelection = (selection, options) => { + const selectionDirection = getDirection(selection); + const range = exports.getRange(selection); + if (!range) { + return; + } + if (options.snapTableRows) { + if (['TBODY', 'TR'].indexOf(range.commonAncestorContainer.nodeName) > -1) { + const startRow = dom_1.default(range.startContainer).farthest('tr'); + const endRow = dom_1.default(range.endContainer).farthest('tr'); + if (startRow) { + range.setStartBefore(startRow.firstElementChild.firstChild); + } + if (endRow) { + range.setEndAfter(endRow.lastElementChild.lastChild); + } + } + } + if (options.snapCode) { + snapToCode(range); + } + if (options.snapMathJax) { + snapToMath(range); + } + if (options.snapWords) { + const shouldGobbleCharacter = (container, targetOffset) => targetOffset >= 0 && container.length >= targetOffset && /\S/.test(container.substr(targetOffset, 1)); + const shouldGobbleBackward = () => { + return range.startContainer.textContent && + // ensure range of selection overlaps with startContainer before gobbling + // fixes firefox behavior that prevented starting highlights on images + range.startOffset < range.startContainer.textContent.length && + shouldGobbleCharacter(range.startContainer.textContent, range.startOffset - 1); + }; + const shouldGobbleForward = () => { + return range.endContainer.textContent && + // ensure range of selection overlaps with endContainer before gobbling + // fixes firefox behavior that prevented ending highlights on images + range.endOffset > 0 && + shouldGobbleCharacter(range.endContainer.textContent, range.endOffset); + }; + const gobbleBackward = () => { + range.setStart(range.startContainer, range.startOffset - 1); + }; + const gobbleForward = () => { + range.setEnd(range.endContainer, range.endOffset + 1); + }; + if (range.startContainer.nodeName === '#text') { + while (shouldGobbleBackward()) { + gobbleBackward(); + } + } + if (range.endContainer.nodeName === '#text') { + while (shouldGobbleForward()) { + gobbleForward(); + } + } + } + if (selectionDirection === 'backward') { + // https://stackoverflow.com/a/10705853 + const endRange = range.cloneRange(); + endRange.collapse(false); + selection.removeAllRanges(); + selection.addRange(endRange); + selection.extend(range.startContainer, range.startOffset); + return range; + } + selection.removeAllRanges(); + selection.addRange(range); + return range; +}; +//# sourceMappingURL=selection.js.map \ No newline at end of file diff --git a/dist/selection.js.map b/dist/selection.js.map new file mode 100644 index 0000000..0e8488a --- /dev/null +++ b/dist/selection.js.map @@ -0,0 +1 @@ +{"version":3,"file":"selection.js","sourceRoot":"","sources":["../src/selection.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/serializationStrategies/TextPositionSelector/index.d.ts b/dist/serializationStrategies/TextPositionSelector/index.d.ts new file mode 100644 index 0000000..0822f84 --- /dev/null +++ b/dist/serializationStrategies/TextPositionSelector/index.d.ts @@ -0,0 +1,11 @@ +import Highlighter from '../../Highlighter'; +export declare const discriminator = "TextPositionSelector"; +export interface IData { + type: 'TextPositionSelector'; + referenceElementId: string; + start: number; + end: number; +} +export declare function serialize(range: Range, referenceElement: HTMLElement): IData; +export declare function isLoadable(highlighter: Highlighter, data: IData): boolean; +export declare function load(highlighter: Highlighter, data: IData): Range; diff --git a/dist/serializationStrategies/TextPositionSelector/index.js b/dist/serializationStrategies/TextPositionSelector/index.js new file mode 100644 index 0000000..02b19a4 --- /dev/null +++ b/dist/serializationStrategies/TextPositionSelector/index.js @@ -0,0 +1,33 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const serialize_selection_1 = require("serialize-selection"); +exports.discriminator = 'TextPositionSelector'; +function serialize(range, referenceElement) { + // modified copy/paste out of 'serialize-selection' module + const cloneRange = range.cloneRange(); + const startContainer = cloneRange.startContainer; + const startOffset = cloneRange.startOffset; + const contentLength = cloneRange.toString().length; + cloneRange.selectNodeContents(referenceElement); + cloneRange.setEnd(startContainer, startOffset); + return { + end: cloneRange.toString().length + contentLength, + referenceElementId: referenceElement.id, + start: cloneRange.toString().length, + type: exports.discriminator, + }; +} +exports.serialize = serialize; +function isLoadable(highlighter, data) { + return !!highlighter.document.getElementById(data.referenceElementId); +} +exports.isLoadable = isLoadable; +function load(highlighter, data) { + const referenceElement = highlighter.getReferenceElement(data.referenceElementId); + const selection = serialize_selection_1.default.restore(data, referenceElement); + const range = selection.getRangeAt(0); + selection.removeAllRanges(); + return range; +} +exports.load = load; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dist/serializationStrategies/TextPositionSelector/index.js.map b/dist/serializationStrategies/TextPositionSelector/index.js.map new file mode 100644 index 0000000..5be5ade --- /dev/null +++ b/dist/serializationStrategies/TextPositionSelector/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/serializationStrategies/TextPositionSelector/index.ts"],"names":[],"mappings":";;AAAA,6DAAqD;AAGxC,QAAA,aAAa,GAAG,sBAAsB,CAAC;AASpD,SAAgB,SAAS,CAAC,KAAY,EAAE,gBAA6B;IAEnE,0DAA0D;IAC1D,MAAM,UAAU,GAAG,KAAK,CAAC,UAAU,EAAE,CAAC;IACtC,MAAM,cAAc,GAAG,UAAU,CAAC,cAAc,CAAC;IACjD,MAAM,WAAW,GAAG,UAAU,CAAC,WAAW,CAAC;IAC3C,MAAM,aAAa,GAAG,UAAU,CAAC,QAAQ,EAAE,CAAC,MAAM,CAAC;IAEnD,UAAU,CAAC,kBAAkB,CAAC,gBAAgB,CAAC,CAAC;IAChD,UAAU,CAAC,MAAM,CAAC,cAAc,EAAE,WAAW,CAAC,CAAC;IAE/C,OAAO;QACL,GAAG,EAAE,UAAU,CAAC,QAAQ,EAAE,CAAC,MAAM,GAAG,aAAa;QACjD,kBAAkB,EAAE,gBAAgB,CAAC,EAAE;QACvC,KAAK,EAAE,UAAU,CAAC,QAAQ,EAAE,CAAC,MAAM;QACnC,IAAI,EAAE,qBAAa;KACpB,CAAC;AACJ,CAAC;AAjBD,8BAiBC;AAED,SAAgB,UAAU,CAAC,WAAwB,EAAE,IAAW;IAC9D,OAAO,CAAC,CAAC,WAAW,CAAC,QAAQ,CAAC,cAAc,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;AACxE,CAAC;AAFD,gCAEC;AAED,SAAgB,IAAI,CAAC,WAAwB,EAAE,IAAW;IACxD,MAAM,gBAAgB,GAAG,WAAW,CAAC,mBAAmB,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;IAClF,MAAM,SAAS,GAAG,6BAAkB,CAAC,OAAO,CAAC,IAAI,EAAE,gBAAgB,CAAC,CAAC;IACrE,MAAM,KAAK,GAAG,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;IACtC,SAAS,CAAC,eAAe,EAAE,CAAC;IAC5B,OAAO,KAAK,CAAC;AACf,CAAC;AAND,oBAMC"} \ No newline at end of file diff --git a/dist/serializationStrategies/XpathRangeSelector/index.d.ts b/dist/serializationStrategies/XpathRangeSelector/index.d.ts new file mode 100644 index 0000000..62b4584 --- /dev/null +++ b/dist/serializationStrategies/XpathRangeSelector/index.d.ts @@ -0,0 +1,13 @@ +import Highlighter from '../../Highlighter'; +export declare const discriminator = "XpathRangeSelector"; +export interface IData { + type: 'XpathRangeSelector'; + referenceElementId: string; + startContainer: string; + startOffset: number; + endContainer: string; + endOffset: number; +} +export declare function serialize(range: Range, referenceElement: HTMLElement): IData; +export declare function isLoadable(highlighter: Highlighter, data: IData): boolean; +export declare function load(highlighter: Highlighter, data: IData): Range; diff --git a/dist/serializationStrategies/XpathRangeSelector/index.js b/dist/serializationStrategies/XpathRangeSelector/index.js new file mode 100644 index 0000000..5220097 --- /dev/null +++ b/dist/serializationStrategies/XpathRangeSelector/index.js @@ -0,0 +1,40 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const xpath_1 = require("./xpath"); +exports.discriminator = 'XpathRangeSelector'; +function serialize(range, referenceElement) { + const [endContainer, endOffset] = xpath_1.getXPathForElement(range.endContainer, range.endOffset, referenceElement); + const [startContainer, startOffset] = xpath_1.getXPathForElement(range.startContainer, range.startOffset, referenceElement); + return { + endContainer, + endOffset, + referenceElementId: referenceElement.id, + startContainer, + startOffset, + type: exports.discriminator, + }; +} +exports.serialize = serialize; +function isLoadable(highlighter, data) { + const referenceElement = highlighter.getReferenceElement(data.referenceElementId); + if (!referenceElement) { + return false; + } + const [startContainer] = xpath_1.getFirstByXPath(data.startContainer, data.startOffset, referenceElement); + const [endContainer] = xpath_1.getFirstByXPath(data.endContainer, data.endOffset, referenceElement); + return !!startContainer && !!endContainer; +} +exports.isLoadable = isLoadable; +function load(highlighter, data) { + const range = highlighter.document.createRange(); + const referenceElement = highlighter.getReferenceElement(data.referenceElementId); + const [startContainer, startOffset] = xpath_1.getFirstByXPath(data.startContainer, data.startOffset, referenceElement); + const [endContainer, endOffset] = xpath_1.getFirstByXPath(data.endContainer, data.endOffset, referenceElement); + if (startContainer && endContainer) { + range.setStart(startContainer, startOffset); + range.setEnd(endContainer, endOffset); + } + return range; +} +exports.load = load; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dist/serializationStrategies/XpathRangeSelector/index.js.map b/dist/serializationStrategies/XpathRangeSelector/index.js.map new file mode 100644 index 0000000..9f78532 --- /dev/null +++ b/dist/serializationStrategies/XpathRangeSelector/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/serializationStrategies/XpathRangeSelector/index.ts"],"names":[],"mappings":";;AACA,mCAA8D;AAEjD,QAAA,aAAa,GAAG,oBAAoB,CAAC;AAWlD,SAAgB,SAAS,CAAC,KAAY,EAAE,gBAA6B;IAEnE,MAAM,CAAC,YAAY,EAAE,SAAS,CAAC,GAAG,0BAAkB,CAAC,KAAK,CAAC,YAAY,EAAE,KAAK,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC;IAC5G,MAAM,CAAC,cAAc,EAAE,WAAW,CAAC,GAAG,0BAAkB,CAAC,KAAK,CAAC,cAAc,EAAE,KAAK,CAAC,WAAW,EAAE,gBAAgB,CAAC,CAAC;IAEpH,OAAO;QACL,YAAY;QACZ,SAAS;QACT,kBAAkB,EAAE,gBAAgB,CAAC,EAAE;QACvC,cAAc;QACd,WAAW;QACX,IAAI,EAAE,qBAAa;KACpB,CAAC;AACJ,CAAC;AAbD,8BAaC;AAED,SAAgB,UAAU,CAAC,WAAwB,EAAE,IAAW;IAC9D,MAAM,gBAAgB,GAAG,WAAW,CAAC,mBAAmB,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;IAClF,IAAI,CAAC,gBAAgB,EAAE;QACrB,OAAO,KAAK,CAAC;KACd;IAED,MAAM,CAAC,cAAc,CAAC,GAAG,uBAAe,CAAC,IAAI,CAAC,cAAc,EAAE,IAAI,CAAC,WAAW,EAAE,gBAAgB,CAAC,CAAC;IAClG,MAAM,CAAC,YAAY,CAAC,GAAG,uBAAe,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC;IAE5F,OAAO,CAAC,CAAC,cAAc,IAAI,CAAC,CAAC,YAAY,CAAC;AAC5C,CAAC;AAVD,gCAUC;AAED,SAAgB,IAAI,CAAC,WAAwB,EAAE,IAAW;IACxD,MAAM,KAAK,GAAG,WAAW,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC;IACjD,MAAM,gBAAgB,GAAG,WAAW,CAAC,mBAAmB,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;IAElF,MAAM,CAAC,cAAc,EAAE,WAAW,CAAC,GAAG,uBAAe,CAAC,IAAI,CAAC,cAAc,EAAE,IAAI,CAAC,WAAW,EAAE,gBAAiB,CAAC,CAAC;IAChH,MAAM,CAAC,YAAY,EAAE,SAAS,CAAC,GAAG,uBAAe,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,SAAS,EAAE,gBAAiB,CAAC,CAAC;IAExG,IAAI,cAAc,IAAI,YAAY,EAAE;QAClC,KAAK,CAAC,QAAQ,CAAC,cAAc,EAAE,WAAW,CAAC,CAAC;QAC5C,KAAK,CAAC,MAAM,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC;KACvC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAbD,oBAaC"} \ No newline at end of file diff --git a/dist/serializationStrategies/XpathRangeSelector/index.spec.d.ts b/dist/serializationStrategies/XpathRangeSelector/index.spec.d.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/dist/serializationStrategies/XpathRangeSelector/index.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/dist/serializationStrategies/XpathRangeSelector/index.spec.js b/dist/serializationStrategies/XpathRangeSelector/index.spec.js new file mode 100644 index 0000000..9eebb8b --- /dev/null +++ b/dist/serializationStrategies/XpathRangeSelector/index.spec.js @@ -0,0 +1,109 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const serializer = require("."); +const Highlighter_1 = require("../../Highlighter"); +describe('load', () => { + it('returns a range', () => { + document.body.innerHTML = ` +
+
+ asdfasdfasdlf aklsdfj l;dksfj as;ldfkjals;d fjas;ldkfj as;ldfkj +
+
+ `; + const highligherEl = document.getElementById('highlighter'); + const highlighter = new Highlighter_1.default(highligherEl, { formatMessage: jest.fn() }); + const result = serializer.load(highlighter, { + endContainer: './text()[1]', + endOffset: 10, + referenceElementId: 'referenceElement', + startContainer: './text()[1]', + startOffset: 0, + type: 'XpathRangeSelector', + }); + expect(result).toBeInstanceOf(Range); + }); +}); +describe('isLoadable', () => { + it('returns true', () => { + document.body.innerHTML = ` +
+
+ asdfasdfasdlf aklsdfj l;dksfj as;ldfkjals;d fjas;ldkfj as;ldfkj +
+
+ `; + const highligherEl = document.getElementById('highlighter'); + const highlighter = new Highlighter_1.default(highligherEl, { formatMessage: jest.fn() }); + const result = serializer.isLoadable(highlighter, { + endContainer: './text()[1]', + endOffset: 10, + referenceElementId: 'referenceElement', + startContainer: './text()[1]', + startOffset: 0, + type: 'XpathRangeSelector', + }); + expect(result).toEqual(true); + }); + it('returns false when reference element cant be found', () => { + document.body.innerHTML = ` +
+
+ asdfasdfasdlf aklsdfj l;dksfj as;ldfkjals;d fjas;ldkfj as;ldfkj +
+
+ `; + const highligherEl = document.getElementById('highlighter'); + const highlighter = new Highlighter_1.default(highligherEl, { formatMessage: jest.fn() }); + const result = serializer.isLoadable(highlighter, { + endContainer: './text()[1]', + endOffset: 10, + referenceElementId: 'doesnt exist', + startContainer: './text()[1]', + startOffset: 0, + type: 'XpathRangeSelector', + }); + expect(result).toEqual(false); + }); + it('returns false when start container cant be found', () => { + document.body.innerHTML = ` +
+
+ asdfasdfasdlf aklsdfj l;dksfj as;ldfkjals;d fjas;ldkfj as;ldfkj +
+
+ `; + const highligherEl = document.getElementById('highlighter'); + const highlighter = new Highlighter_1.default(highligherEl, { formatMessage: jest.fn() }); + const result = serializer.isLoadable(highlighter, { + endContainer: './text()[1]', + endOffset: 10, + referenceElementId: 'referenceElement', + startContainer: './text()[8]', + startOffset: 0, + type: 'XpathRangeSelector', + }); + expect(result).toEqual(false); + }); + it('returns false when end container cant be found', () => { + document.body.innerHTML = ` +
+
+ asdfasdfasdlf aklsdfj l;dksfj as;ldfkjals;d fjas;ldkfj as;ldfkj +
+
+ `; + const highligherEl = document.getElementById('highlighter'); + const highlighter = new Highlighter_1.default(highligherEl, { formatMessage: jest.fn() }); + const result = serializer.isLoadable(highlighter, { + endContainer: './text()[8]', + endOffset: 10, + referenceElementId: 'referenceElement', + startContainer: './text()[0]', + startOffset: 0, + type: 'XpathRangeSelector', + }); + expect(result).toEqual(false); + }); +}); +//# sourceMappingURL=index.spec.js.map \ No newline at end of file diff --git a/dist/serializationStrategies/XpathRangeSelector/index.spec.js.map b/dist/serializationStrategies/XpathRangeSelector/index.spec.js.map new file mode 100644 index 0000000..7953c9c --- /dev/null +++ b/dist/serializationStrategies/XpathRangeSelector/index.spec.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.spec.js","sourceRoot":"","sources":["../../../src/serializationStrategies/XpathRangeSelector/index.spec.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/serializationStrategies/XpathRangeSelector/xpath.d.ts b/dist/serializationStrategies/XpathRangeSelector/xpath.d.ts new file mode 100644 index 0000000..099dda6 --- /dev/null +++ b/dist/serializationStrategies/XpathRangeSelector/xpath.d.ts @@ -0,0 +1,2 @@ +export declare function getXPathForElement(targetElement: Node, offset: number, reference: HTMLElement): [string, number]; +export declare function getFirstByXPath(path: string, offset: number, referenceElement: HTMLElement): [HTMLElement | null, number]; diff --git a/dist/serializationStrategies/XpathRangeSelector/xpath.js b/dist/serializationStrategies/XpathRangeSelector/xpath.js new file mode 100644 index 0000000..7a25817 --- /dev/null +++ b/dist/serializationStrategies/XpathRangeSelector/xpath.js @@ -0,0 +1,242 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +// tslint:disable +const injectHighlightWrappers_1 = require("../../injectHighlightWrappers"); +const findNonTextChild = (node) => Array.prototype.find.call(node.childNodes, (node) => node.nodeType === Node.ELEMENT_NODE && !isTextHighlightOrScreenReaderNode(node)); +const isHighlight = (node) => !!node && node.getAttribute && node.getAttribute(injectHighlightWrappers_1.DATA_ATTR) !== null; +const isHighlightOrScreenReaderNode = (node) => isHighlight(node) || isScreenReaderNode(node); +const isTextHighlight = (node) => isHighlight(node) && !findNonTextChild(node); +const isTextHighlightOrScreenReaderNode = (node) => (isHighlight(node) || isScreenReaderNode(node)) && !findNonTextChild(node); +const isText = (node) => !!node && node.nodeType === 3; +const isTextOrTextHighlight = (node) => isText(node) || isTextHighlight(node); +const isTextOrTextHighlightOrScreenReaderNode = (node) => isText(node) || isTextHighlightOrScreenReaderNode(node) || isScreenReaderNode(node); +const isElement = (node) => node && node.nodeType === 1; +const isElementNotHighlight = (node) => isElement(node) && !isHighlight(node); +const nodeIndex = (list, element) => Array.prototype.indexOf.call(list, element); +const isScreenReaderNode = (node) => !!node && isElement(node) && node.getAttribute(injectHighlightWrappers_1.DATA_SCREEN_READERS_ATTR) !== null; +const IS_PATH_PART_SELF = /^\.$/; +const IS_PATH_PART_TEXT = /^text\(\)\[(\d+)\]$/; +const IS_PATH_PART_ELEMENT = /\*\[name\(\)='(.+)'\]\[(\d+)\]/; +const getTextLength = (node) => { + if (isText(node)) { + return node.length; + } + else if (node && node.textContent) { + return node.textContent.length; + } + else { + return 0; + } +}; +const getMaxOffset = (node) => { + if (isText(node)) { + return node.length; + } + else { + return node.childNodes.length; + } +}; +const recurseBackwardsThroughText = (current, container, resultOffset) => { + // we don't count the current, we count the previous + const previous = current.previousSibling; + if (previous && isTextOrTextHighlightOrScreenReaderNode(previous)) { + return recurseBackwardsThroughText(previous, container, resultOffset + getTextLength(previous)); + } + else if (current.parentNode && isTextHighlightOrScreenReaderNode(current.parentNode)) { + return recurseBackwardsThroughText(current.parentNode, container, resultOffset); + } + else { + return [current, resultOffset]; + } +}; +const resolveTextHighlightsToTextOffset = (element, offset, container) => { + // this won't catch things that are right at the tail of the container, which is good, because we + // want to contiue using element offset if possible + if (isElement(element) && isTextOrTextHighlightOrScreenReaderNode(element.childNodes[offset])) { + return recurseBackwardsThroughText(element.childNodes[offset], container, 0); + // however, if the element, is a highlgiht, then we should float + } + else if (isTextHighlightOrScreenReaderNode(element)) { + return recurseBackwardsThroughText(element, container, getTextLength(element)); + // preserve the offset if the elment is text + } + else if (isText(element)) { + return recurseBackwardsThroughText(element, container, offset); + } + else { + return [element, offset]; + } +}; +const floatThroughText = (element, offset, container) => { + if (isTextOrTextHighlightOrScreenReaderNode(element) && offset === 0 && element.parentNode && element.parentNode !== container) { + return floatThroughText(element.parentNode, nodeIndex(element.parentNode.childNodes, element), container); + } + else if (isTextOrTextHighlightOrScreenReaderNode(element) && offset === getMaxOffset(element) && element.parentNode && element.parentNode !== container) { + return floatThroughText(element.parentNode, nodeIndex(element.parentNode.childNodes, element) + 1, container); + } + else if (isTextOrTextHighlight(element) + && (offset + 1) === getMaxOffset(element) + && isElement(element.childNodes[offset]) + && isScreenReaderNode(element.childNodes[offset]) + && element.parentNode + && element.parentNode !== container) { + return floatThroughText(element.parentNode, nodeIndex(element.parentNode.childNodes, element) + 1, container); + } + else { + return [element, offset]; + } +}; +const resolveToNextElementOffsetIfPossible = (element, offset) => { + if (isTextOrTextHighlightOrScreenReaderNode(element) && element.parentNode && offset === getMaxOffset(element) && (!element.nextSibling || !isHighlightOrScreenReaderNode(element.nextSibling))) { + return [element.parentNode, nodeIndex(element.parentNode.childNodes, element) + 1]; + } + return [element, offset]; +}; +const resolveToPreviousElementOffsetIfPossible = (element, offset) => { + if (isTextOrTextHighlightOrScreenReaderNode(element) && element.parentNode && offset === 0 && (!element.previousSibling || !isHighlightOrScreenReaderNode(element.previousSibling))) { + return [element.parentNode, nodeIndex(element.parentNode.childNodes, element)]; + } + return [element, offset]; +}; +// kinda copied from https://developer.mozilla.org/en-US/docs/Web/XPath/Snippets#getXPathForElement +function getXPathForElement(targetElement, offset, reference) { + [targetElement, offset] = floatThroughText(targetElement, offset, reference); + [targetElement, offset] = resolveToNextElementOffsetIfPossible(targetElement, offset); + [targetElement, offset] = resolveTextHighlightsToTextOffset(targetElement, offset, reference); + [targetElement, offset] = resolveToPreviousElementOffsetIfPossible(targetElement, offset); + let xpath = ''; + let pos, element = targetElement.previousSibling, focus = targetElement; + // for element targets, highlight children might be artifically + // inflating the range offset, fix. + if (isElement(focus)) { + let search = focus.childNodes[offset - 1]; + while (search) { + if (isTextOrTextHighlight(search)) { + search = search.previousSibling; + while (isTextOrTextHighlight(search)) { + offset--; + search = search.previousSibling; + } + } + search = search ? search.previousSibling : null; + } + } + while (focus !== reference) { + pos = 1; + while (element) { + // highlights in text change the number of nodes in the nodelist, + // compensate by gobbling adjacent highlights and text + if (isTextOrTextHighlightOrScreenReaderNode(focus) && isTextOrTextHighlightOrScreenReaderNode(element)) { + while (isTextOrTextHighlightOrScreenReaderNode(element)) { + element = element.previousSibling; + } + pos += 1; + } + else { + if (isElementNotHighlight(focus) && isElementNotHighlight(element) && element.nodeName === focus.nodeName) { + pos += 1; + } + element = element.previousSibling; + } + } + if (isText(focus) || isTextHighlightOrScreenReaderNode(focus)) { + xpath = 'text()[' + pos + ']' + '/' + xpath; + } + else if (!isHighlightOrScreenReaderNode(focus)) { + xpath = '*[name()=\'' + focus.nodeName.toLowerCase() + '\'][' + pos + ']' + '/' + xpath; + } + focus = focus.parentNode; + element = focus.previousSibling; + } + xpath = './' + xpath; + xpath = xpath.replace(/\/$/, ''); + return [xpath, offset]; +} +exports.getXPathForElement = getXPathForElement; +function getFirstByXPath(path, offset, referenceElement) { + const parts = path.split('/'); + let node = referenceElement; + let part = parts.shift(); + while (node && part) { + node = followPart(node, part); + part = parts.shift(); + } + // the part following is greedy, so walk back to the first matching + // textish node before computing offset + while (isTextOrTextHighlightOrScreenReaderNode(node) && isTextOrTextHighlightOrScreenReaderNode(node.previousSibling)) { + node = node.previousSibling; + } + // highligts split up text nodes that should be treated as one, iterate through + // until we find the text node that the offset specifies, modifying the offset + // as we go. prefer leaving highlights if we have the option to deal with + // adjacent highlights. + while ((isTextHighlightOrScreenReaderNode(node) && offset >= node.textContent.length) || (isText(node) && offset > node.textContent.length)) { + offset -= node.textContent.length; + node = isTextOrTextHighlightOrScreenReaderNode(node.nextSibling) ? node.nextSibling : null; + } + // for element targets, highlight children might be artifically + // inflating the range offset, fix. + if (node && isElement(node)) { + let search = node.childNodes[0]; + let offsetElementsFound = 0; + let modifyOffset = 0; + while (search && offsetElementsFound < offset) { + offsetElementsFound++; + if (isTextOrTextHighlightOrScreenReaderNode(search)) { + search = search.nextSibling; + while (isTextOrTextHighlightOrScreenReaderNode(search)) { + modifyOffset++; + search = search.nextSibling; + } + } + else { + search = search.nextSibling; + } + } + offset += modifyOffset; + } + if (node && isHighlightOrScreenReaderNode(node)) { + node = null; + } + if (isElement(node) && node.childNodes.length < offset) { + node = null; + } + return [node, offset]; +} +exports.getFirstByXPath = getFirstByXPath; +function followPart(node, part) { + const findFirst = (nodeList, predicate) => Array.prototype.find.call(nodeList, (node) => predicate(node)); + const findFirstAfter = (nodeList, afterThis, predicate) => findFirst(Array.prototype.slice.call(nodeList, Array.prototype.indexOf.call(nodeList, afterThis) + 1), predicate); + if (IS_PATH_PART_SELF.test(part)) { + return node; + } + if (IS_PATH_PART_TEXT.test(part)) { + let [, index] = part.match(IS_PATH_PART_TEXT); + let text = findFirst(node.childNodes, isTextOrTextHighlightOrScreenReaderNode); + while (text && index > 1) { + let search = text; + while (isTextOrTextHighlightOrScreenReaderNode(search)) { + search = search.nextSibling; + } + index--; + if (search) { + text = findFirstAfter(node.childNodes, search, isTextOrTextHighlightOrScreenReaderNode); + } + else { + text = search; + } + } + return text; + } + if (IS_PATH_PART_ELEMENT.test(part)) { + let [, type, index] = part.match(IS_PATH_PART_ELEMENT); + const nodeMatches = (node) => isElement(node) && node.nodeName.toLowerCase() === type.toLowerCase() && !isHighlightOrScreenReaderNode(node); + let element = findFirst(node.childNodes, nodeMatches); + while (element && index > 1) { + index--; + element = findFirstAfter(node.childNodes, element, nodeMatches); + } + return element; + } +} +//# sourceMappingURL=xpath.js.map \ No newline at end of file diff --git a/dist/serializationStrategies/XpathRangeSelector/xpath.js.map b/dist/serializationStrategies/XpathRangeSelector/xpath.js.map new file mode 100644 index 0000000..83f454f --- /dev/null +++ b/dist/serializationStrategies/XpathRangeSelector/xpath.js.map @@ -0,0 +1 @@ +{"version":3,"file":"xpath.js","sourceRoot":"","sources":["../../../src/serializationStrategies/XpathRangeSelector/xpath.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/serializationStrategies/index.d.ts b/dist/serializationStrategies/index.d.ts new file mode 100644 index 0000000..75515c7 --- /dev/null +++ b/dist/serializationStrategies/index.d.ts @@ -0,0 +1,9 @@ +import Highlighter from '../Highlighter'; +import * as TextPositionSelector from './TextPositionSelector'; +import * as XpathRangeSelector from './XpathRangeSelector'; +export declare type ISerializationData = XpathRangeSelector.IData | TextPositionSelector.IData; +export interface IDeserializer { + isLoadable(highlighter: Highlighter): boolean; + load(highlighter: Highlighter): Range; +} +export declare function getDeserializer(data: ISerializationData): IDeserializer; diff --git a/dist/serializationStrategies/index.js b/dist/serializationStrategies/index.js new file mode 100644 index 0000000..544332e --- /dev/null +++ b/dist/serializationStrategies/index.js @@ -0,0 +1,29 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const TextPositionSelector = require("./TextPositionSelector"); +const XpathRangeSelector = require("./XpathRangeSelector"); +function getDeserializer(data) { + switch (data.type) { + case TextPositionSelector.discriminator: + return { + isLoadable: (highlighter) => TextPositionSelector.isLoadable(highlighter, data), + load: (highlighter) => TextPositionSelector.load(highlighter, data), + }; + case XpathRangeSelector.discriminator: + return { + isLoadable: (highlighter) => XpathRangeSelector.isLoadable(highlighter, data), + load: (highlighter) => XpathRangeSelector.load(highlighter, data), + }; + default: + ((bad) => { + throw new Error(`not a valid serialization: ${JSON.stringify(bad)}`); + return null; + })(data); + return { + isLoadable: () => false, + load: (highlighter) => highlighter.document.createRange(), + }; + } +} +exports.getDeserializer = getDeserializer; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dist/serializationStrategies/index.js.map b/dist/serializationStrategies/index.js.map new file mode 100644 index 0000000..17d0872 --- /dev/null +++ b/dist/serializationStrategies/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/serializationStrategies/index.ts"],"names":[],"mappings":";;AACA,+DAA+D;AAC/D,2DAA2D;AAS3D,SAAgB,eAAe,CAAC,IAAwB;IACtD,QAAQ,IAAI,CAAC,IAAI,EAAE;QACjB,KAAK,oBAAoB,CAAC,aAAa;YACrC,OAAO;gBACL,UAAU,EAAE,CAAC,WAAwB,EAAE,EAAE,CAAC,oBAAoB,CAAC,UAAU,CAAC,WAAW,EAAE,IAAI,CAAC;gBAC5F,IAAI,EAAE,CAAC,WAAwB,EAAE,EAAE,CAAC,oBAAoB,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC;aACjF,CAAC;QACJ,KAAK,kBAAkB,CAAC,aAAa;YACnC,OAAO;gBACL,UAAU,EAAE,CAAC,WAAwB,EAAE,EAAE,CAAC,kBAAkB,CAAC,UAAU,CAAC,WAAW,EAAE,IAAI,CAAC;gBAC1F,IAAI,EAAE,CAAC,WAAwB,EAAE,EAAE,CAAC,kBAAkB,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC;aAC/E,CAAC;QACJ;YACE,CAAC,CAAC,GAAU,EAAQ,EAAE;gBACpB,MAAM,IAAI,KAAK,CAAC,8BAA8B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;gBACrE,OAAO,IAAI,CAAC;YACd,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YAET,OAAO;gBACL,UAAU,EAAE,GAAG,EAAE,CAAC,KAAK;gBACvB,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,WAAW,CAAC,QAAQ,CAAC,WAAW,EAAE;aAC1D,CAAC;KACL;AACH,CAAC;AAvBD,0CAuBC"} \ No newline at end of file