forked from chapmanu/fragmentions
/
content.js
59 lines (51 loc) · 1.55 KB
/
content.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
// return first element in scope containing case-sensitive text
function getElementByText(scope, text) {
// iterate descendants of scope
for (var all = scope.childNodes, index = 0, element; (element = all[index]); ++index) {
// conditionally return element containing visible, case-sensitive text (matched)
if (element.nodeType == 1) {
var el_text = element.innerText || element.textContent || '';
el_text = el_text.replace(/\s+/g, ' ');
if (el_text.indexOf(text) !== -1) {
return getElementByText(element, text);
}
}
}
// return scope (unmatched)
return scope;
}
// on dom loaded or hash change
function onHashChange() {
// detect auto-anchor
// This doesn't use hash because of e.g.
// https://bugzilla.mozilla.org/show_bug.cgi?id=378962
var text = location.href.match(/#(#|%23)(.+)/);
if (text) {
// get element containing text (or return document)
var element = getElementByText(
// document scope
document,
// uri-decoded text
decodeURIComponent(text[2].replace(/\+/g, ' '))
);
// if element found
if (element !== document) {
// after 1/60 second delay
setTimeout(function () {
// scroll to element
element.scrollIntoView();
// focus element
element.focus();
// if element could not be focused
if (document.activeElement !== element) {
// focus as focusable element
element.setAttribute('tabindex', 0);
element.focus();
}
}, 16);
}
}
}
// event listeners
window.addEventListener('hashchange', onHashChange);
document.addEventListener('DOMContentLoaded', onHashChange);