@qualweb/act-rules 0.7.5 → 0.7.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/__webpack/act.bundle.js +1 -1
- package/dist/rules/QW-ACT-R37.d.ts +13 -15
- package/dist/rules/QW-ACT-R37.d.ts.map +1 -1
- package/dist/rules/QW-ACT-R37.js +145 -258
- package/package.json +3 -3
|
@@ -1,23 +1,21 @@
|
|
|
1
1
|
import type { QWElement } from '@qualweb/qw-element';
|
|
2
|
-
import { Test } from '@qualweb/core/evaluation';
|
|
3
2
|
import { AtomicRule } from '../lib/AtomicRule.object';
|
|
4
3
|
declare class QW_ACT_R37 extends AtomicRule {
|
|
5
4
|
execute(element: QWElement): void;
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
parseRGBString
|
|
14
|
-
|
|
15
|
-
|
|
5
|
+
private isHumanLanguage;
|
|
6
|
+
private evaluateGradient;
|
|
7
|
+
private parseGradientString;
|
|
8
|
+
private getColorInGradient;
|
|
9
|
+
private getTextSize;
|
|
10
|
+
private getBackground;
|
|
11
|
+
private isImage;
|
|
12
|
+
private parseRGBString;
|
|
13
|
+
private flattenColors;
|
|
14
|
+
private getContrast;
|
|
15
|
+
private getLuminance;
|
|
16
|
+
private hasValidContrastRatio;
|
|
16
17
|
private isBold;
|
|
17
|
-
|
|
18
|
-
hasValidContrastRatio(contrast: number, fontSize: string, isBold: boolean): boolean;
|
|
19
|
-
getTextSize(font: string, fontSize: number, bold: boolean, italic: boolean, text: string): number;
|
|
20
|
-
getColorInGradient(fromColor: any, toColor: any, ratio: number): any;
|
|
18
|
+
private equals;
|
|
21
19
|
}
|
|
22
20
|
export { QW_ACT_R37 };
|
|
23
21
|
//# sourceMappingURL=QW-ACT-R37.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"QW-ACT-R37.d.ts","sourceRoot":"","sources":["../../src/rules/QW-ACT-R37.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAQrD,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"QW-ACT-R37.d.ts","sourceRoot":"","sources":["../../src/rules/QW-ACT-R37.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAQrD,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAUtD,cAAM,UAAW,SAAQ,UAAU;IAKjC,OAAO,CAAC,OAAO,EAAE,SAAS,GAAG,IAAI;IAqIjC,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,gBAAgB;IA+BxB,OAAO,CAAC,mBAAmB;IAW3B,OAAO,CAAC,kBAAkB;IAS1B,OAAO,CAAC,WAAW;IAInB,OAAO,CAAC,aAAa;IAOrB,OAAO,CAAC,OAAO;IAKf,OAAO,CAAC,cAAc;IAkBtB,OAAO,CAAC,aAAa;IAUrB,OAAO,CAAC,WAAW;IAOnB,OAAO,CAAC,YAAY;IAQpB,OAAO,CAAC,qBAAqB;IAM7B,OAAO,CAAC,MAAM;IAId,OAAO,CAAC,MAAM;CAGf;AAED,OAAO,EAAE,UAAU,EAAE,CAAC"}
|
package/dist/rules/QW-ACT-R37.js
CHANGED
|
@@ -19,35 +19,33 @@ const AtomicRule_object_1 = require("../lib/AtomicRule.object");
|
|
|
19
19
|
const colorjs_io_1 = __importDefault(require("colorjs.io"));
|
|
20
20
|
class QW_ACT_R37 extends AtomicRule_object_1.AtomicRule {
|
|
21
21
|
execute(element) {
|
|
22
|
+
var _a;
|
|
22
23
|
const visible = window.DomUtils.isElementVisible(element);
|
|
23
|
-
if (!visible)
|
|
24
|
+
if (!visible)
|
|
24
25
|
return;
|
|
25
|
-
|
|
26
|
-
const
|
|
27
|
-
const elementText = element.getElementOwnText();
|
|
28
|
-
|
|
26
|
+
const nodeName = element.getElementTagName();
|
|
27
|
+
const isInputField = ['input', 'select', 'textarea'].includes(nodeName);
|
|
28
|
+
const elementText = element.getElementOwnText().trim();
|
|
29
|
+
const placeholder = (_a = element.getElementAttribute('placeholder')) === null || _a === void 0 ? void 0 : _a.trim();
|
|
30
|
+
if (elementText === '' && !isInputField && !placeholder) {
|
|
29
31
|
return;
|
|
30
32
|
}
|
|
31
|
-
|
|
32
|
-
if (!isHTML) {
|
|
33
|
+
if (!element.isElementHTMLElement())
|
|
33
34
|
return;
|
|
34
|
-
}
|
|
35
35
|
const disabledWidgets = window.disabledWidgets;
|
|
36
36
|
const elementSelectors = element.getElementSelector();
|
|
37
37
|
for (const disableWidget of disabledWidgets || []) {
|
|
38
|
-
const
|
|
39
|
-
|
|
38
|
+
const selectorsResult = window.AccessibilityUtils.getAccessibleNameSelector(disableWidget);
|
|
39
|
+
const selectors = typeof selectorsResult === 'string' ? [selectorsResult] : selectorsResult;
|
|
40
|
+
if (disableWidget && selectors && selectors.includes(elementSelectors))
|
|
40
41
|
return;
|
|
41
|
-
|
|
42
|
-
if (disableWidget.getElementSelector() === elementSelectors) {
|
|
42
|
+
if (disableWidget.getElementSelector() === elementSelectors)
|
|
43
43
|
return;
|
|
44
|
-
}
|
|
45
44
|
const children = disableWidget.getElementChildren();
|
|
46
45
|
if (children) {
|
|
47
46
|
for (const child of children) {
|
|
48
|
-
if (child.getElementSelector() === elementSelectors)
|
|
47
|
+
if (child.getElementSelector() === elementSelectors)
|
|
49
48
|
return;
|
|
50
|
-
}
|
|
51
49
|
}
|
|
52
50
|
}
|
|
53
51
|
}
|
|
@@ -55,27 +53,25 @@ class QW_ACT_R37 extends AtomicRule_object_1.AtomicRule {
|
|
|
55
53
|
if (role === 'group') {
|
|
56
54
|
const disable = element.getElementAttribute('disabled') !== null;
|
|
57
55
|
const ariaDisable = element.getElementAttribute('aria-disabled') !== null;
|
|
58
|
-
if (disable || ariaDisable)
|
|
56
|
+
if (disable || ariaDisable)
|
|
59
57
|
return;
|
|
60
|
-
}
|
|
61
58
|
}
|
|
62
59
|
const test = new evaluation_1.Test();
|
|
63
60
|
const fgColor = element.getElementStyleProperty('color', null);
|
|
64
61
|
let bgColor = this.getBackground(element);
|
|
65
|
-
const opacity = parseFloat(element.getElementStyleProperty('opacity', null));
|
|
62
|
+
const opacity = parseFloat(element.getElementStyleProperty('opacity', null) || '1');
|
|
66
63
|
const fontSize = element.getElementStyleProperty('font-size', null);
|
|
67
64
|
const fontWeight = element.getElementStyleProperty('font-weight', null);
|
|
68
65
|
const fontFamily = element.getElementStyleProperty('font-family', null);
|
|
69
66
|
const fontStyle = element.getElementStyleProperty('font-style', null);
|
|
70
67
|
const textShadow = element.getElementStyleProperty('text-shadow', null);
|
|
71
|
-
if (textShadow.trim() !== 'none') {
|
|
72
|
-
const
|
|
73
|
-
if (
|
|
74
|
-
const
|
|
75
|
-
const
|
|
76
|
-
const blur = parseInt(
|
|
77
|
-
|
|
78
|
-
if (validateTextShadow) {
|
|
68
|
+
if (textShadow && textShadow.trim() !== 'none' && textShadow.trim() !== '') {
|
|
69
|
+
const pixelValues = textShadow.match(/(-?\d+px)/g);
|
|
70
|
+
if (pixelValues && pixelValues.length >= 3) {
|
|
71
|
+
const hs = Math.abs(parseInt(pixelValues[0].replace('px', ''), 10));
|
|
72
|
+
const vs = Math.abs(parseInt(pixelValues[1].replace('px', ''), 10));
|
|
73
|
+
const blur = parseInt(pixelValues[2].replace('px', ''), 10);
|
|
74
|
+
if (blur > 0 || hs > 1 || vs > 1) {
|
|
79
75
|
test.verdict = evaluation_1.Verdict.WARNING;
|
|
80
76
|
test.resultCode = 'W1';
|
|
81
77
|
test.addElement(element);
|
|
@@ -94,9 +90,8 @@ class QW_ACT_R37 extends AtomicRule_object_1.AtomicRule {
|
|
|
94
90
|
const regexGradient = /((\w-?)*gradient.*)/gm;
|
|
95
91
|
let regexGradientMatches = bgColor.match(regexGradient);
|
|
96
92
|
if (regexGradientMatches) {
|
|
97
|
-
if (this.isHumanLanguage(elementText)) {
|
|
98
|
-
|
|
99
|
-
this.evaluateGradient(test, element, parsedGradientString, fgColor, opacity, fontSize, fontWeight, fontStyle, fontFamily, elementText);
|
|
93
|
+
if (this.isHumanLanguage(elementText || placeholder || "")) {
|
|
94
|
+
this.evaluateGradient(test, element, regexGradientMatches[0], fgColor, opacity, fontSize, fontWeight, fontStyle, fontFamily, elementText || placeholder || "");
|
|
100
95
|
}
|
|
101
96
|
else {
|
|
102
97
|
test.verdict = evaluation_1.Verdict.PASSED;
|
|
@@ -104,85 +99,40 @@ class QW_ACT_R37 extends AtomicRule_object_1.AtomicRule {
|
|
|
104
99
|
test.addElement(element);
|
|
105
100
|
this.addTestResult(test);
|
|
106
101
|
}
|
|
102
|
+
return;
|
|
107
103
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
}
|
|
132
|
-
else {
|
|
133
|
-
opacityAUX = parseFloat(parent.getElementStyleProperty('opacity', null));
|
|
134
|
-
parsedBG = this.parseRGBString(parent.getElementStyleProperty('background', null), opacityAUX);
|
|
135
|
-
elementAux = parent;
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
else {
|
|
140
|
-
break;
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
if (parsedBG === undefined ||
|
|
144
|
-
(parsedBG.red === 0 && parsedBG.green === 0 && parsedBG.blue === 0 && parsedBG.alpha === 0)) {
|
|
145
|
-
parsedBG = { red: 255, green: 255, blue: 255, alpha: 1 };
|
|
146
|
-
}
|
|
147
|
-
let secondElement = elementAux;
|
|
148
|
-
if (parsedBG.alpha !== 1) {
|
|
149
|
-
let secondOpacity = opacityAUX;
|
|
150
|
-
let parsedSecondBG = parsedBG;
|
|
151
|
-
while (parsedSecondBG && parsedSecondBG.alpha !== 1) {
|
|
152
|
-
const parent = secondElement.getElementParent();
|
|
153
|
-
if (!parent) {
|
|
154
|
-
break;
|
|
155
|
-
}
|
|
156
|
-
else {
|
|
157
|
-
secondOpacity = parseFloat(parent.getElementStyleProperty('opacity', null));
|
|
158
|
-
parsedSecondBG = this.parseRGBString(parent.getElementStyleProperty('background', null), secondOpacity);
|
|
159
|
-
secondElement = parent;
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
if (parsedSecondBG && parsedSecondBG.alpha === 1) {
|
|
163
|
-
const outputRed = Math.round(parsedBG.red * parsedBG.alpha + parsedSecondBG.red * (1.0 - parsedBG.alpha));
|
|
164
|
-
const outputGreen = Math.round(parsedBG.green * parsedBG.alpha + parsedSecondBG.green * (1.0 - parsedBG.alpha));
|
|
165
|
-
const outputBlue = Math.round(parsedBG.blue * parsedBG.alpha + parsedSecondBG.blue * (1.0 - parsedBG.alpha));
|
|
166
|
-
parsedBG = { red: outputRed, green: outputGreen, blue: outputBlue, alpha: 1 };
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
const parsedFG = this.parseRGBString(fgColor, opacity);
|
|
104
|
+
let parsedBG = this.parseRGBString(bgColor);
|
|
105
|
+
if (parsedBG)
|
|
106
|
+
parsedBG.alpha *= opacity;
|
|
107
|
+
let elementAux = element;
|
|
108
|
+
while (!parsedBG || (parsedBG.red === 0 && parsedBG.green === 0 && parsedBG.blue === 0 && parsedBG.alpha === 0)) {
|
|
109
|
+
const parent = elementAux.getElementParent();
|
|
110
|
+
if (!parent)
|
|
111
|
+
break;
|
|
112
|
+
const parentOpacity = parseFloat(parent.getElementStyleProperty('opacity', null) || '1');
|
|
113
|
+
parsedBG = this.parseRGBString(this.getBackground(parent));
|
|
114
|
+
if (parsedBG)
|
|
115
|
+
parsedBG.alpha *= parentOpacity;
|
|
116
|
+
elementAux = parent;
|
|
117
|
+
}
|
|
118
|
+
if (!parsedBG || parsedBG.alpha === 0) {
|
|
119
|
+
parsedBG = { red: 255, green: 255, blue: 255, alpha: 1 };
|
|
120
|
+
}
|
|
121
|
+
if (parsedBG.alpha < 1) {
|
|
122
|
+
parsedBG = this.flattenColors(parsedBG, { red: 255, green: 255, blue: 255, alpha: 1 });
|
|
123
|
+
}
|
|
124
|
+
const parsedFG = this.parseRGBString(fgColor);
|
|
125
|
+
if (parsedFG) {
|
|
126
|
+
parsedFG.alpha *= opacity;
|
|
170
127
|
if (!this.equals(parsedBG, parsedFG)) {
|
|
171
|
-
|
|
128
|
+
const textToVerify = elementText || placeholder || "";
|
|
129
|
+
if (this.isHumanLanguage(textToVerify)) {
|
|
172
130
|
const contrastRatio = this.getContrast(parsedBG, parsedFG);
|
|
173
131
|
const isValid = this.hasValidContrastRatio(contrastRatio, fontSize, this.isBold(fontWeight));
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
this.addTestResult(test);
|
|
179
|
-
}
|
|
180
|
-
else {
|
|
181
|
-
test.verdict = evaluation_1.Verdict.FAILED;
|
|
182
|
-
test.resultCode = 'F1';
|
|
183
|
-
test.addElement(element);
|
|
184
|
-
this.addTestResult(test);
|
|
185
|
-
}
|
|
132
|
+
test.verdict = isValid ? evaluation_1.Verdict.PASSED : evaluation_1.Verdict.FAILED;
|
|
133
|
+
test.resultCode = isValid ? 'P1' : 'F1';
|
|
134
|
+
test.addElement(element);
|
|
135
|
+
this.addTestResult(test);
|
|
186
136
|
}
|
|
187
137
|
else {
|
|
188
138
|
test.verdict = evaluation_1.Verdict.PASSED;
|
|
@@ -193,192 +143,130 @@ class QW_ACT_R37 extends AtomicRule_object_1.AtomicRule {
|
|
|
193
143
|
}
|
|
194
144
|
}
|
|
195
145
|
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
if (backgroundImage === 'none') {
|
|
199
|
-
let bg = element.getElementStyleProperty('background', null);
|
|
200
|
-
if (bg === '') {
|
|
201
|
-
bg = element.getElementStyleProperty('background-color', null);
|
|
202
|
-
}
|
|
203
|
-
return bg;
|
|
204
|
-
}
|
|
205
|
-
else {
|
|
206
|
-
return backgroundImage;
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
isImage(color) {
|
|
210
|
-
return (color.toLowerCase().includes('.jpeg') ||
|
|
211
|
-
color.toLowerCase().includes('.jpg') ||
|
|
212
|
-
color.toLowerCase().includes('.png') ||
|
|
213
|
-
color.toLowerCase().includes('.svg'));
|
|
146
|
+
isHumanLanguage(text) {
|
|
147
|
+
return window.DomUtils.isHumanLanguage(text);
|
|
214
148
|
}
|
|
215
149
|
evaluateGradient(test, element, parsedGradientString, fgColor, opacity, fontSize, fontWeight, fontStyle, fontFamily, elementText) {
|
|
216
150
|
if (parsedGradientString.startsWith('linear-gradient')) {
|
|
217
|
-
const
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
isValid = isValid && this.hasValidContrastRatio(contrastRatio, fontSize, this.isBold(fontWeight));
|
|
231
|
-
}
|
|
232
|
-
else {
|
|
233
|
-
for (const color of colors) {
|
|
234
|
-
contrastRatio = this.getContrast(color, this.parseRGBString(fgColor, opacity));
|
|
235
|
-
isValid = isValid && this.hasValidContrastRatio(contrastRatio, fontSize, this.isBold(fontWeight));
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
if (isValid) {
|
|
239
|
-
test.verdict = evaluation_1.Verdict.PASSED;
|
|
240
|
-
test.resultCode = 'P3';
|
|
241
|
-
}
|
|
242
|
-
else {
|
|
243
|
-
test.verdict = evaluation_1.Verdict.FAILED;
|
|
244
|
-
test.resultCode = 'F2';
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
else if (gradientDirection === 'to left' || gradientDirection === 'to right') {
|
|
248
|
-
test.verdict = evaluation_1.Verdict.WARNING;
|
|
249
|
-
test.resultCode = 'W3';
|
|
151
|
+
const colors = this.parseGradientString(parsedGradientString);
|
|
152
|
+
let isValid = true;
|
|
153
|
+
const parsedFG = this.parseRGBString(fgColor);
|
|
154
|
+
if (!parsedFG)
|
|
155
|
+
return false;
|
|
156
|
+
parsedFG.alpha *= opacity;
|
|
157
|
+
const textSize = this.getTextSize(fontFamily.toLowerCase().replace(/['"]+/g, ''), parseInt(fontSize.replace('px', '')), this.isBold(fontWeight), fontStyle.toLowerCase().includes('italic'), elementText);
|
|
158
|
+
if (textSize !== -1) {
|
|
159
|
+
const elementWidth = element.getElementStyleProperty('width', null);
|
|
160
|
+
const lastCharRatio = textSize / parseInt(elementWidth.replace('px', ''));
|
|
161
|
+
const lastCharBgColor = this.getColorInGradient(colors[0], colors[colors.length - 1], lastCharRatio);
|
|
162
|
+
isValid = isValid && this.hasValidContrastRatio(this.getContrast(colors[0], parsedFG), fontSize, this.isBold(fontWeight));
|
|
163
|
+
isValid = isValid && this.hasValidContrastRatio(this.getContrast(lastCharBgColor, parsedFG), fontSize, this.isBold(fontWeight));
|
|
250
164
|
}
|
|
251
165
|
else {
|
|
252
|
-
|
|
253
|
-
|
|
166
|
+
for (const color of colors) {
|
|
167
|
+
isValid = isValid && this.hasValidContrastRatio(this.getContrast(color, parsedFG), fontSize, this.isBold(fontWeight));
|
|
168
|
+
}
|
|
254
169
|
}
|
|
170
|
+
test.verdict = isValid ? evaluation_1.Verdict.PASSED : evaluation_1.Verdict.FAILED;
|
|
171
|
+
test.resultCode = isValid ? 'P3' : 'F2';
|
|
255
172
|
}
|
|
256
173
|
else {
|
|
174
|
+
test.verdict = evaluation_1.Verdict.WARNING;
|
|
257
175
|
test.resultCode = 'W3';
|
|
258
176
|
}
|
|
259
177
|
test.addElement(element);
|
|
260
178
|
this.addTestResult(test);
|
|
261
179
|
return true;
|
|
262
180
|
}
|
|
263
|
-
|
|
264
|
-
return window.DomUtils.isHumanLanguage(text);
|
|
265
|
-
}
|
|
266
|
-
equals(color1, color2) {
|
|
267
|
-
return (color1.red === color2.red &&
|
|
268
|
-
color1.green === color2.green &&
|
|
269
|
-
color1.blue === color2.blue &&
|
|
270
|
-
color1.alpha === color2.alpha);
|
|
271
|
-
}
|
|
272
|
-
getGradientDirection(gradient) {
|
|
273
|
-
const direction = gradient.replace('linear-gradient(', '').split(',')[0];
|
|
274
|
-
if (direction) {
|
|
275
|
-
if (direction === '90deg')
|
|
276
|
-
return 'to right';
|
|
277
|
-
if (direction === '-90deg')
|
|
278
|
-
return 'to left';
|
|
279
|
-
return direction;
|
|
280
|
-
}
|
|
281
|
-
return undefined;
|
|
282
|
-
}
|
|
283
|
-
parseGradientString(gradient, opacity) {
|
|
181
|
+
parseGradientString(gradient) {
|
|
284
182
|
const regex = /rgb(a?)\((\d+), (\d+), (\d+)+(, +(\d)+)?\)/gm;
|
|
285
183
|
const colorsMatch = gradient.match(regex);
|
|
286
184
|
const colors = [];
|
|
287
185
|
for (const stringColor of colorsMatch || []) {
|
|
288
|
-
|
|
186
|
+
const parsed = this.parseRGBString(stringColor);
|
|
187
|
+
if (parsed)
|
|
188
|
+
colors.push(parsed);
|
|
289
189
|
}
|
|
290
190
|
return colors;
|
|
291
191
|
}
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
192
|
+
getColorInGradient(fromColor, toColor, ratio) {
|
|
193
|
+
return {
|
|
194
|
+
red: fromColor.red + (toColor.red - fromColor.red) * ratio,
|
|
195
|
+
green: fromColor.green + (toColor.green - fromColor.green) * ratio,
|
|
196
|
+
blue: fromColor.blue + (toColor.blue - fromColor.blue) * ratio,
|
|
197
|
+
alpha: 1
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
getTextSize(font, fontSize, bold, italic, text) {
|
|
201
|
+
return window.DomUtils.getTextSize(font, fontSize, bold, italic, text);
|
|
202
|
+
}
|
|
203
|
+
getBackground(element) {
|
|
204
|
+
const bgImg = element.getElementStyleProperty('background-image', null);
|
|
205
|
+
if (bgImg && bgImg !== 'none' && bgImg !== '')
|
|
206
|
+
return bgImg;
|
|
207
|
+
const bgColor = element.getElementStyleProperty('background-color', null);
|
|
208
|
+
return (bgColor && bgColor !== '' && bgColor !== 'transparent') ? bgColor : element.getElementStyleProperty('background', null);
|
|
209
|
+
}
|
|
210
|
+
isImage(s) {
|
|
211
|
+
const lower = s.toLowerCase();
|
|
212
|
+
return lower.includes('.jpg') || lower.includes('.png') || lower.includes('.svg') || lower.includes('url(');
|
|
213
|
+
}
|
|
214
|
+
parseRGBString(colorString) {
|
|
215
|
+
var _a;
|
|
216
|
+
if (!colorString || colorString === 'transparent' || colorString === 'none')
|
|
298
217
|
return { red: 0, green: 0, blue: 0, alpha: 0 };
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
218
|
+
const rgb = colorString.match(/^rgb\((\d+), (\d+), (\d+)\)/);
|
|
219
|
+
if (rgb)
|
|
220
|
+
return { red: parseInt(rgb[1]), green: parseInt(rgb[2]), blue: parseInt(rgb[3]), alpha: 1.0 };
|
|
221
|
+
const rgba = colorString.match(/^rgba\((\d+), (\d+), (\d+), (\d*(\.\d+)?)\)/);
|
|
222
|
+
if (rgba)
|
|
223
|
+
return { red: parseInt(rgba[1]), green: parseInt(rgba[2]), blue: parseInt(rgba[3]), alpha: Math.round(parseFloat(rgba[4]) * 100) / 100 };
|
|
224
|
+
try {
|
|
225
|
+
const color = new colorjs_io_1.default(colorString);
|
|
226
|
+
const srgb = color.to('srgb');
|
|
302
227
|
return {
|
|
303
|
-
red:
|
|
304
|
-
green:
|
|
305
|
-
blue:
|
|
306
|
-
alpha:
|
|
228
|
+
red: Math.round(srgb.coords[0] * 255),
|
|
229
|
+
green: Math.round(srgb.coords[1] * 255),
|
|
230
|
+
blue: Math.round(srgb.coords[2] * 255),
|
|
231
|
+
alpha: (_a = color.alpha) !== null && _a !== void 0 ? _a : 1
|
|
307
232
|
};
|
|
308
233
|
}
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
return {
|
|
312
|
-
red: parseInt(match[1], 10),
|
|
313
|
-
green: parseInt(match[2], 10),
|
|
314
|
-
blue: parseInt(match[3], 10),
|
|
315
|
-
alpha: Math.round(parseFloat(match[4]) * 100) / 100
|
|
316
|
-
};
|
|
317
|
-
}
|
|
318
|
-
match = colorString.match(oklch2Regex);
|
|
319
|
-
if (match) {
|
|
320
|
-
const oklchColor = new colorjs_io_1.default("oklch", [parseFloat(match[1]), parseFloat(match[2]), parseFloat(match[3])]);
|
|
321
|
-
const rgba = oklchColor.to("srgb");
|
|
322
|
-
return {
|
|
323
|
-
red: rgba.srgb.red,
|
|
324
|
-
green: rgba.srgb.green,
|
|
325
|
-
blue: rgba.srgb.blue,
|
|
326
|
-
alpha: parseFloat(match[4])
|
|
327
|
-
};
|
|
328
|
-
}
|
|
329
|
-
match = colorString.match(oklchRegex);
|
|
330
|
-
if (match) {
|
|
331
|
-
const oklchColor = new colorjs_io_1.default("oklch", [parseFloat(match[1]), parseFloat(match[2]), parseFloat(match[3])]);
|
|
332
|
-
const rgba = oklchColor.to("srgb");
|
|
333
|
-
return {
|
|
334
|
-
red: rgba.srgb.red,
|
|
335
|
-
green: rgba.srgb.green,
|
|
336
|
-
blue: rgba.srgb.blue,
|
|
337
|
-
alpha: rgba.alpha
|
|
338
|
-
};
|
|
234
|
+
catch (e) {
|
|
235
|
+
return undefined;
|
|
339
236
|
}
|
|
340
237
|
}
|
|
341
|
-
|
|
342
|
-
const
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
238
|
+
flattenColors(fg, bg) {
|
|
239
|
+
const alpha = fg.alpha;
|
|
240
|
+
return {
|
|
241
|
+
red: Math.round((1 - alpha) * bg.red + alpha * fg.red),
|
|
242
|
+
green: Math.round((1 - alpha) * bg.green + alpha * fg.green),
|
|
243
|
+
blue: Math.round((1 - alpha) * bg.blue + alpha * fg.blue),
|
|
244
|
+
alpha: fg.alpha + bg.alpha * (1 - fg.alpha)
|
|
245
|
+
};
|
|
349
246
|
}
|
|
350
|
-
|
|
351
|
-
const
|
|
352
|
-
const
|
|
353
|
-
const
|
|
354
|
-
|
|
355
|
-
const alpha = fgColor['alpha'] + bgColor['alpha'] * (1 - fgColor['alpha']);
|
|
356
|
-
return { red: red, green: green, blue: blue, alpha: alpha };
|
|
247
|
+
getContrast(bg, fg) {
|
|
248
|
+
const finalFG = fg.alpha < 1 ? this.flattenColors(fg, bg) : fg;
|
|
249
|
+
const L1 = this.getLuminance(bg);
|
|
250
|
+
const L2 = this.getLuminance(finalFG);
|
|
251
|
+
return (Math.max(L1, L2) + 0.05) / (Math.min(L1, L2) + 0.05);
|
|
357
252
|
}
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
}
|
|
365
|
-
const bL = this.getRelativeLuminance(bgColor['red'], bgColor['green'], bgColor['blue']);
|
|
366
|
-
const fL = this.getRelativeLuminance(fgColor['red'], fgColor['green'], fgColor['blue']);
|
|
367
|
-
return (Math.max(fL, bL) + 0.05) / (Math.min(fL, bL) + 0.05);
|
|
253
|
+
getLuminance(c) {
|
|
254
|
+
const a = [c.red, c.green, c.blue].map(v => {
|
|
255
|
+
v /= 255;
|
|
256
|
+
return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
|
|
257
|
+
});
|
|
258
|
+
return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722;
|
|
368
259
|
}
|
|
369
260
|
hasValidContrastRatio(contrast, fontSize, isBold) {
|
|
370
|
-
const
|
|
371
|
-
const
|
|
372
|
-
return contrast >=
|
|
261
|
+
const size = parseFloat(fontSize);
|
|
262
|
+
const threshold = (isBold && size >= 18.66) || size >= 24 ? 3 : 4.5;
|
|
263
|
+
return (contrast + 0.02) >= threshold;
|
|
373
264
|
}
|
|
374
|
-
|
|
375
|
-
return
|
|
265
|
+
isBold(fontWeight) {
|
|
266
|
+
return !!fontWeight && ['bold', 'bolder', '700', '800', '900'].includes(fontWeight);
|
|
376
267
|
}
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
const green = fromColor['green'] + (toColor['green'] - fromColor['green']) * ratio;
|
|
380
|
-
const blue = fromColor['blue'] + (toColor['blue'] - fromColor['blue']) * ratio;
|
|
381
|
-
return { red: red, green: green, blue: blue, alpha: 1 };
|
|
268
|
+
equals(c1, c2) {
|
|
269
|
+
return c1.red === c2.red && c1.green === c2.green && c1.blue === c2.blue && c1.alpha === c2.alpha;
|
|
382
270
|
}
|
|
383
271
|
}
|
|
384
272
|
exports.QW_ACT_R37 = QW_ACT_R37;
|
|
@@ -387,7 +275,6 @@ __decorate([
|
|
|
387
275
|
applicability_1.ElementIsHTMLElement,
|
|
388
276
|
(0, applicability_1.ElementIsNot)(['html', 'head', 'body', 'script', 'style', 'meta']),
|
|
389
277
|
applicability_1.ElementIsVisible,
|
|
390
|
-
applicability_1.ElementHasText,
|
|
391
278
|
__metadata("design:type", Function),
|
|
392
279
|
__metadata("design:paramtypes", [Function]),
|
|
393
280
|
__metadata("design:returntype", void 0)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qualweb/act-rules",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.6",
|
|
4
4
|
"description": "ACT rules module for qualweb web accessibility evaluator",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist/*"
|
|
@@ -45,10 +45,10 @@
|
|
|
45
45
|
"author": "João Vicente",
|
|
46
46
|
"license": "ISC",
|
|
47
47
|
"devDependencies": {
|
|
48
|
-
"@qualweb/core": "^0.8.
|
|
48
|
+
"@qualweb/core": "^0.8.6",
|
|
49
49
|
"@qualweb/locale": "0.2.2",
|
|
50
50
|
"@qualweb/qw-page": "0.3.2",
|
|
51
|
-
"@qualweb/util": "0.6.
|
|
51
|
+
"@qualweb/util": "0.6.5",
|
|
52
52
|
"@tsconfig/recommended": "^1.0.3",
|
|
53
53
|
"@types/mocha": "^10.0.6",
|
|
54
54
|
"@types/node": "^16.11.11",
|