-
Notifications
You must be signed in to change notification settings - Fork 0
/
colorContrast.js
127 lines (114 loc) · 4.03 KB
/
colorContrast.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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
import { ColorUtil } from "./colorUtil.js";
class ColorContrastChecker {
constructor(containerElement, criteriaInfo, styleObj) {
this.criteriaInfo = criteriaInfo
? criteriaInfo
: { fontSize: "23.994px", fontWeight: 700, contrastThreshold: 4.5 };
this.styleObj = styleObj
? styleObj
: {
"border-width": "2px",
"border-style": "dashed",
"border-color": "red",
};
this.colorUtil = new ColorUtil();
if (!containerElement) {
console.info(`since you didn't pass the container Element, we will use the document body`);
}
this.containerElement = containerElement ? containerElement : document.body;
this.startCheck;
}
init() {
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", () => this.startObserving());
} else {
this.startObserving();
}
}
startObserving() {
this.startCheck = setTimeout(() => {
this.checkContrastForChildren();
this.observer = new MutationObserver((mutations) => {
for (var mutation of mutations) {
if (mutation.type === "childList") {
this.checkContrastForChildren(mutation.target);
} else if (mutation.type === "attributes") {
if (mutation.attributeName === "style" || mutation.attributeName === "class") {
setTimeout(() => this.checkContrastForChildren(mutation.target), 5000);
}
}
}
});
this.observer.observe(this.containerElement, {
childList: true,
subtree: true,
attributes: true,
attributeFilter: ["class", "style"],
});
}, 1);
}
checkContrastForChildren(element = this.containerElement) {
const children = element.children;
for (const child of children) {
const isNotDisabled = !child.hasAttribute("disabled");
const isNotHidden = !child.hasAttribute("hidden");
const isValidElement = isNotDisabled && isNotHidden;
if (isValidElement) {
const hasValidText = Array.from(child.childNodes).some(
(node) => node.nodeType === Node.TEXT_NODE && node.textContent.trim() !== "",
);
const hasText =
"value" in child
? child.value !== "" && child.tagName.toLowerCase() === "li" && child.value !== 0
: hasValidText && child.textContent !== "";
if (hasText) {
const childStyle = this.colorUtil.getElementStyle(child);
const contrast = this.calculateContrastRatio(
this.colorUtil.getEffectiveColor(child, "bgColor"),
childStyle.color,
);
// check whether the element matches the criteria or not
const isLargeFont = childStyle.fontSize <= this.criteriaInfo.fontSize;
const isBold = childStyle.fontWeight <= this.criteriaInfo.fontWeight;
this.criteriaInfo.contrastThreshold = isLargeFont && isBold ? 4.5 : 3.1;
if (contrast < this.criteriaInfo.contrastThreshold) {
const currEleStyle = window.getComputedStyle(child);
child.setAttribute("data-color-contrast", contrast);
this.colorUtil.setStyle(child, this.styleObj);
const childStyleVal = {
class: `${child.tagName.toLowerCase()}.${child.classList.value}`,
bgColor: this.colorUtil.getEffectiveColor(child, "bgColor"),
color: this.colorUtil.getEffectiveColor(child, "color"),
fontSize: childStyle.fontSize,
fontWeight: childStyle.fontWeight,
contrastRatio: contrast,
content: child.textContent,
};
// console.table(childStyleVal);
} else {
if (child.hasAttribute("data-color-contrast")) {
child.style.border = "unset";
}
}
}
if (child.children.length > 0) {
this.checkContrastForChildren(child);
}
}
}
}
calculateContrastRatio(bgColor, textColor) {
const bgLuminance = this.colorUtil.getRelativeLuminance(this.colorUtil.parseColor(bgColor));
const textLuminance = this.colorUtil.getRelativeLuminance(this.colorUtil.parseColor(textColor));
const lighter = Math.max(bgLuminance, textLuminance);
const darker = Math.min(bgLuminance, textLuminance);
return (lighter + 0.05) / (darker + 0.05);
}
destroy() {
if (this.observer) {
this.observer.disconnect();
}
this.startCheck;
}
}
export { ColorContrastChecker };