forked from apache/incubator-annotator
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
85 lines (76 loc) · 2.67 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
/**
* @license
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
/* global corpus, debug, module, selectable */
import '@babel/polyfill';
import * as fragment from '@annotator/fragment-identifier';
import { describeTextQuoteByRange as describeRange } from '@annotator/dom';
import { mark } from './mark.js';
import { search } from './search.js';
const refresh = async () => {
corpus.innerHTML = corpus.innerText;
debug.classList.remove('error');
const identifier = window.location.hash.slice(1);
if (!identifier) return;
try {
const { selector } = fragment.parse(identifier);
debug.innerText = JSON.stringify(selector, null, 2);
const results = search(corpus, selector);
const ranges = [];
for await (let range of results) {
ranges.push(range);
}
for (let range of ranges) {
mark(range);
}
} catch (e) {
debug.classList.add('error');
debug.innerText = JSON.stringify(e, null, 2);
if (e instanceof fragment.SyntaxError) return;
else throw e;
}
};
async function onSelectionChange() {
const selection = document.getSelection();
if (selection === null || selection.isCollapsed) {
return;
}
const range = selection.getRangeAt(0);
if (!isWithinNode(range, selectable)) {
return;
}
const selectableRange = document.createRange();
selectableRange.selectNodeContents(selectable);
const descriptor = await describeRange({ range, context: selectableRange });
window.location.hash = fragment.stringify(descriptor);
}
function isWithinNode(range, node) {
const nodeRange = document.createRange();
nodeRange.selectNode(node);
return (
range.compareBoundaryPoints(Range.START_TO_START, nodeRange) >= 0 &&
range.compareBoundaryPoints(Range.END_TO_END, nodeRange) <= 0
);
}
window.addEventListener('hashchange', refresh);
document.addEventListener('DOMContentLoaded', refresh);
document.addEventListener('selectionchange', onSelectionChange);
if (module.hot) {
module.hot.accept();
module.hot.dispose(() => {
window.removeEventListener('hashchange', refresh);
document.removeEventListener('DOMContentLoaded', refresh);
document.removeEventListener('selectionchange', onSelectionChange);
});
}