forked from whatwg/html
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathvar-click-highlighting.js
More file actions
83 lines (76 loc) · 2.67 KB
/
var-click-highlighting.js
File metadata and controls
83 lines (76 loc) · 2.67 KB
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
// Derived from https://github.com/speced/bikeshed/blob/3a2640eecd45fd5d8abe5d37b5adaf23cc945b88/bikeshed/stylescript/var-click-highlighting.js with an addition for var-scope.
/*
Color-choosing design:
* Colors are ordered by goodness.
* On clicking a var, give it the earliest color
with the lowest usage in the algorithm.
* On re-clicking, re-use the var's most recent color
if that's not currently being used elsewhere.
*/
const COLOR_COUNT = 7;
document.addEventListener("click", e=>{
if(e.target.nodeName == "VAR") {
highlightSameAlgoVars(e.target);
}
});
function highlightSameAlgoVars(v) {
// Find the algorithm container.
let algoContainer = findAlgoContainer(v);
// Not highlighting document-global vars,
// too likely to be unrelated.
if(algoContainer == null) return;
const varName = nameFromVar(v);
if(!v.hasAttribute("data-var-color")) {
const newColor = chooseHighlightColor(algoContainer, v);
for(const el of algoContainer.querySelectorAll("var")) {
if(nameFromVar(el) == varName) {
el.setAttribute("data-var-color", newColor);
el.setAttribute("data-var-last-color", newColor);
}
}
} else {
for(const el of algoContainer.querySelectorAll("var")) {
if(nameFromVar(el) == varName) {
el.removeAttribute("data-var-color");
}
}
}
}
function findAlgoContainer(el) {
while(el != document.body) {
if(el.hasAttribute("data-algorithm") || el.hasAttribute("data-var-scope")) return el;
el = el.parentNode;
}
return null;
}
function nameFromVar(el) {
return el.textContent.replace(/(\s|\xa0)+/g, " ").trim();
}
function colorCountsFromContainer(container) {
const namesFromColor = Array.from({length:COLOR_COUNT}, x=>new Set());
for(let v of container.querySelectorAll("var[data-var-color]")) {
let color = +v.getAttribute("data-var-color");
namesFromColor[color].add(nameFromVar(v));
}
return namesFromColor.map(x=>x.size);
}
function leastUsedColor(colors) {
// Find the earliest color with the lowest count.
let minCount = Infinity;
let minColor = null;
for(var i = 0; i < colors.length; i++) {
if(colors[i] < minCount) {
minColor = i;
minCount = colors[i];
}
}
return minColor;
}
function chooseHighlightColor(container, v) {
const colorCounts = colorCountsFromContainer(container);
if(v.hasAttribute("data-var-last-color")) {
let color = +v.getAttribute("data-var-last-color");
if(colorCounts[color] == 0) return color;
}
return leastUsedColor(colorCounts);
}