Skip to content

Commit 29e7e2a

Browse files
authored
revert(color-contrast): revert upgrade to colorjs.io v0.5.0 to work with prototype.js (#4429)
This [puts back the v0.4.3 code](#4366) in `color.js` to handle colorjs.io not handling rad and turn values in hsl. I also decided to use core-js `Array.from` polyfill rather than our own internal one since I needed to bring it in outside of the `polyfill.js` file and could then add it as an import and reuse it in both places. Closes: #4428
1 parent 61cbf30 commit 29e7e2a

File tree

9 files changed

+8210
-100
lines changed

9 files changed

+8210
-100
lines changed

lib/commons/color/color.js

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
import { Colorjs } from '../../core/imports';
1+
import { Colorjs, ArrayFrom } from '../../core/imports';
22

33
const hexRegex = /^#[0-9a-f]{3,8}$/i;
4+
const hslRegex = /hsl\(\s*([-\d.]+)(rad|turn)/;
45

56
/**
67
* @class Color
@@ -129,9 +130,37 @@ export default class Color {
129130
* @instance
130131
*/
131132
parseString(colorString) {
133+
// Colorjs <v0.5.0 does not support rad or turn angle values
134+
// @see https://github.com/LeaVerou/color.js/issues/311
135+
colorString = colorString.replace(hslRegex, (match, angle, unit) => {
136+
const value = angle + unit;
137+
138+
switch (unit) {
139+
case 'rad':
140+
return match.replace(value, radToDeg(angle));
141+
case 'turn':
142+
return match.replace(value, turnToDeg(angle));
143+
}
144+
});
145+
132146
try {
147+
// revert prototype.js override of Array.from
148+
// in order to get color-contrast working
149+
// @see https://github.com/dequelabs/axe-core/issues/4428
150+
let prototypeArrayFrom;
151+
if ('Prototype' in window && 'Version' in window.Prototype) {
152+
prototypeArrayFrom = Array.from;
153+
Array.from = ArrayFrom;
154+
}
155+
133156
// srgb values are between 0 and 1
134157
const color = new Colorjs(colorString).to('srgb');
158+
159+
if (prototypeArrayFrom) {
160+
Array.from = prototypeArrayFrom;
161+
prototypeArrayFrom = null;
162+
}
163+
135164
this.r = color.r;
136165
this.g = color.g;
137166
this.b = color.b;
@@ -328,3 +357,13 @@ export default class Color {
328357
function clamp(value, min, max) {
329358
return Math.min(Math.max(min, value), max);
330359
}
360+
361+
// convert radians to degrees
362+
function radToDeg(rad) {
363+
return (rad * 180) / Math.PI;
364+
}
365+
366+
// convert turn to degrees
367+
function turnToDeg(turn) {
368+
return turn * 360;
369+
}

lib/core/imports/index.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import doT from '@deque/dot';
66
import emojiRegexText from 'emoji-regex';
77
import memoize from 'memoizee';
88
import Color from 'colorjs.io';
9+
import ArrayFrom from 'core-js-pure/actual/array/from';
910

1011
// prevent striping newline characters from strings (e.g. failure
1112
// summaries). value must be synced with build/configure.js
@@ -17,4 +18,11 @@ doT.templateSettings.strip = false;
1718
* @namespace imports
1819
* @memberof axe
1920
*/
20-
export { CssSelectorParser, doT, emojiRegexText, memoize, Color as Colorjs };
21+
export {
22+
CssSelectorParser,
23+
doT,
24+
emojiRegexText,
25+
memoize,
26+
Color as Colorjs,
27+
ArrayFrom
28+
};

lib/core/imports/polyfills.js

Lines changed: 2 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { Uint32Array } from 'typedarray';
33
import 'weakmap-polyfill';
44
import hasOwn from 'core-js-pure/actual/object/has-own';
55
import values from 'core-js-pure/actual/object/values';
6+
import ArrayFrom from 'core-js-pure/actual/array/from';
67

78
if (!('hasOwn' in Object)) {
89
Object.hasOwn = hasOwn;
@@ -177,95 +178,7 @@ if (!Array.prototype.some) {
177178
}
178179

179180
if (!Array.from) {
180-
Object.defineProperty(Array, 'from', {
181-
value: (function () {
182-
var toStr = Object.prototype.toString;
183-
var isCallable = function (fn) {
184-
return (
185-
typeof fn === 'function' || toStr.call(fn) === '[object Function]'
186-
);
187-
};
188-
var toInteger = function (value) {
189-
var number = Number(value);
190-
if (isNaN(number)) {
191-
return 0;
192-
}
193-
if (number === 0 || !isFinite(number)) {
194-
return number;
195-
}
196-
return (number > 0 ? 1 : -1) * Math.floor(Math.abs(number));
197-
};
198-
var maxSafeInteger = Math.pow(2, 53) - 1;
199-
var toLength = function (value) {
200-
var len = toInteger(value);
201-
return Math.min(Math.max(len, 0), maxSafeInteger);
202-
};
203-
204-
// The length property of the from method is 1.
205-
return function from(arrayLike /*, mapFn, thisArg */) {
206-
// 1. Let C be the this value.
207-
var C = this;
208-
209-
// 2. Let items be ToObject(arrayLike).
210-
var items = Object(arrayLike);
211-
212-
// 3. ReturnIfAbrupt(items).
213-
if (arrayLike == null) {
214-
throw new TypeError(
215-
'Array.from requires an array-like object - not null or undefined'
216-
);
217-
}
218-
219-
// 4. If mapfn is undefined, then let mapping be false.
220-
var mapFn = arguments.length > 1 ? arguments[1] : void undefined;
221-
var T;
222-
if (typeof mapFn !== 'undefined') {
223-
// 5. else
224-
// 5. a If IsCallable(mapfn) is false, throw a TypeError exception.
225-
if (!isCallable(mapFn)) {
226-
throw new TypeError(
227-
'Array.from: when provided, the second argument must be a function'
228-
);
229-
}
230-
231-
// 5. b. If thisArg was supplied, let T be thisArg; else let T be undefined.
232-
if (arguments.length > 2) {
233-
T = arguments[2];
234-
}
235-
}
236-
237-
// 10. Let lenValue be Get(items, "length").
238-
// 11. Let len be ToLength(lenValue).
239-
var len = toLength(items.length);
240-
241-
// 13. If IsConstructor(C) is true, then
242-
// 13. a. Let A be the result of calling the [[Construct]] internal method of C with an argument list containing the single item len.
243-
// 14. a. Else, Let A be ArrayCreate(len).
244-
var A = isCallable(C) ? Object(new C(len)) : new Array(len);
245-
246-
// 16. Let k be 0.
247-
var k = 0;
248-
// 17. Repeat, while k < len… (also steps a - h)
249-
var kValue;
250-
while (k < len) {
251-
kValue = items[k];
252-
if (mapFn) {
253-
A[k] =
254-
typeof T === 'undefined'
255-
? mapFn(kValue, k)
256-
: mapFn.call(T, kValue, k);
257-
} else {
258-
A[k] = kValue;
259-
}
260-
k += 1;
261-
}
262-
// 18. Let putStatus be Put(A, "length", len, true).
263-
A.length = len;
264-
// 20. Return A.
265-
return A;
266-
};
267-
})()
268-
});
181+
Array.from = ArrayFrom;
269182
}
270183

271184
if (!String.prototype.includes) {

package-lock.json

Lines changed: 8 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@
130130
"chromedriver": "latest",
131131
"clean-jsdoc-theme": "^4.2.17",
132132
"clone": "^2.1.2",
133-
"colorjs.io": "^0.5.0",
133+
"colorjs.io": "^0.4.3",
134134
"conventional-commits-parser": "^5.0.0",
135135
"core-js": "^3.27.1",
136136
"css-selector-parser": "^1.4.1",

test/commons/color/color.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,15 @@ describe('color.Color', () => {
166166
assert.equal(c.alpha, 1);
167167
});
168168

169+
it('supports negative rad on hue', () => {
170+
const c = new Color();
171+
c.parseColorFnString('hsl(-3.49rad, 40%, 50%)');
172+
assert.equal(c.red, 77);
173+
assert.equal(c.green, 179);
174+
assert.equal(c.blue, 145);
175+
assert.equal(c.alpha, 1);
176+
});
177+
169178
it('supports turn on hue', () => {
170179
const c = new Color();
171180
c.parseColorFnString('hsl(0.444turn, 40%, 50%)');
@@ -174,6 +183,15 @@ describe('color.Color', () => {
174183
assert.equal(c.blue, 144);
175184
assert.equal(c.alpha, 1);
176185
});
186+
187+
it('supports negative turn on hue', () => {
188+
const c = new Color();
189+
c.parseColorFnString('hsl(-0.556turn, 40%, 50%)');
190+
assert.equal(c.red, 77);
191+
assert.equal(c.green, 179);
192+
assert.equal(c.blue, 144);
193+
assert.equal(c.alpha, 1);
194+
});
177195
});
178196

179197
describe('with hwb()', () => {

0 commit comments

Comments
 (0)