Skip to content
This repository was archived by the owner on Feb 9, 2018. It is now read-only.

Commit 7e45ed1

Browse files
authored
Merge pull request #151 from samthor/css-escape
implement CSS.escape
2 parents 69f31ac + 4ff38e0 commit 7e45ed1

File tree

2 files changed

+73
-5
lines changed

2 files changed

+73
-5
lines changed

src/polyfills.js

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,49 @@
3636
* @return {string} escaped string
3737
*/
3838
function escape(str) {
39-
// TODO(samthor): Implement escape().
40-
return '' + str;
39+
if (str === undefined) {
40+
throw new TypeError("Failed to execute 'escape' on 'CSS': 1 argument required, " +
41+
"but only 0 present.");
42+
}
43+
44+
str = '' + str;
45+
var len = str.length;
46+
var escaped = '';
47+
48+
// This follows the algorithm at-
49+
// https://drafts.csswg.org/cssom/#serialize-an-identifier
50+
51+
if (str == '-') {
52+
return '\\-'; // special-case single dash
53+
}
54+
55+
for (var i = 0; i < len; ++i) {
56+
var code = str.charCodeAt(i);
57+
if (code == 0) {
58+
escaped += '\uFFFD';
59+
} else if (code == 0x007f || (code >= 0x001 && code <= 0x001f)) {
60+
// https://drafts.csswg.org/cssom/#escape-a-character-as-code-point
61+
excaped += '\\' + code.toString(16) + ' ';
62+
} else if (code >= 0x0080 || code == 0x002d || code == 0x005f ||
63+
(code >= 0x0041 && code <= 0x005a) ||
64+
(code >= 0x0061 && code <= 0x007a)) {
65+
// the character itself
66+
escaped += str.charAt(i);
67+
} else if (code >= 0x0030 && code <= 0x0039) {
68+
if (i == 0) {
69+
escaped += '\\' + code.toString(16) + ' '; // initial number as code point
70+
} else if (i == 1 && str.charCodeAt(0) == 0x002d) {
71+
escaped += '\\' + code.toString(16) + ' '; // dash (0x002d) then number as code point
72+
} else {
73+
escaped += str.charAt(i); // the character itself
74+
}
75+
} else {
76+
// https://drafts.csswg.org/cssom/#escape-a-character
77+
escaped += '\\' + str.charAt(i);
78+
}
79+
}
80+
81+
return escaped;
4182
}
4283

4384
if (!scope.CSS) {

test/js/escape.js

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,34 @@
1515
suite('CSS.escape polyfill', function() {
1616
var escape = typedOM.internal.escape;
1717

18-
test('Test simple escapes', function() {
19-
assert.equal('test', escape('test'));
18+
test('Test invalid usage', function() {
19+
assert.throws(function() {
20+
CSS.escape();
21+
}, TypeError);
22+
assert.equal('null', CSS.escape(null));
23+
assert.equal('\\[object\\ Object\\]', CSS.escape({}));
2024
});
21-
});
25+
26+
test('Test escaping', function() {
27+
assert.equal('', escape(''));
28+
29+
assert.equal('\\-', escape('-'), 'escaped single dash');
30+
assert.equal('-\\30 ', escape('-0'), 'escaped number after dash');
31+
assert.equal('-\\31 abc', escape('-1abc'), 'escaped number and string after dash');
32+
assert.equal('\\32 abc', escape('2abc'), 'escaped initial number');
33+
assert.equal('abc3', escape('abc3'), 'trailing number not escaped');
34+
35+
assert.equal('abc\\ def', escape('abc def'), 'escaped space');
36+
37+
assert.equal('long\\`string', escape('long`string'), 'escaped non-word char');
38+
39+
assert.equal('√π', escape('√π'), 'high code point not escaped');
40+
});
41+
42+
test('Test CSS strings', function() {
43+
assert.equal('border-radius', escape('border-radius'));
44+
assert.equal('-webkit-transform', escape('-webkit-transform'));
45+
assert.equal('\\30 \\ 4px\\ 8px\\ rgba\\(255\\,\\ 255\\,\\ 255\\,\\ 0\\.25\\)',
46+
escape('0 4px 8px rgba(255, 255, 255, 0.25)'));
47+
});
48+
});

0 commit comments

Comments
 (0)