Skip to content
This repository has been archived by the owner on Sep 6, 2021. It is now read-only.

- Fix for Issue #391 #1509

Merged
merged 3 commits into from
Sep 4, 2012
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 21 additions & 2 deletions src/language/CSSUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,9 @@ define(function (require, exports, module) {
var selectorStartChar = -1, selectorStartLine = -1;
var selectorGroupStartLine = -1, selectorGroupStartChar = -1;
var declListStartLine = -1, declListStartChar = -1;

var escapePattern = new RegExp("\\\\[^\\\\]+", "g");
var validationPattern = new RegExp("\\\\([a-f0-9]{6}|[a-f0-9]{4}(\\s|\\\\|$)|[a-f0-9]{2}(\\s|\\\\|$)|.)", "i");

// implement _firstToken()/_nextToken() methods to
// provide a single stream of tokens

Expand Down Expand Up @@ -183,7 +185,24 @@ define(function (require, exports, module) {
break;
}
}


// Unicode character replacement as defined in http://www.w3.org/TR/CSS21/syndata.html#characters
if (/\\/.test(currentSelector)) {
// Double replace in case of pattern overlapping (regex improvement?)
currentSelector = currentSelector.replace(escapePattern, function (escapedToken) {
return escapedToken.replace(validationPattern, function (unicodeChar) {
unicodeChar = unicodeChar.substr(1);
if (unicodeChar.length === 1) {
return unicodeChar;
} else {
if (parseInt(unicodeChar, 16) < 0x10FFFF) {
return String.fromCharCode(parseInt(unicodeChar, 16));
} else { return String.fromCharCode(0xFFFD); }
}
});
});
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor nit: I'd like to see an empty line between this block and the next one for readability.


currentSelector = currentSelector.trim();
if (currentSelector !== "") {
selectors.push({selector: currentSelector,
Expand Down
61 changes: 61 additions & 0 deletions test/spec/CSSUtils-test-files/escaped-identifiers.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/* Test ".si\mple" (simple) */
.si\mple {}

/* Test ".not\\so\|simple\?" (not\so|simple?) */
.not\\so\|simple\? {}

/* Test ".\74 wodigi\74 s" (.twodigits)*/
.\74 wodigi\74 s {}

/* Test ".fourdigi\0074 s" (.fourdigits)*/
.fourdigi\0074 s {}

/* Test ".sixdigi\000074s" (.sixdigits) */
.sixdigi\000074s {}

/* Test ".two-digit-endspac\65 " (.two-digit-endspace) */
.two-digit-endspac\65 {}

/* Test ".four-digit-endspac\0065 " (.four-digit-endspace) */
.four-digit-endspac\0065 {}

/* Test ".six-digit-endspace\000065" (.six-digit-endspace) */
.six-digit-endspac\000065 {}

/* Test ".mi\78 in\002D it\2D a\00006C\006C" (.mixin-it-all) */
.mi\78 in\002D it\2D a\00006C\006C{}

/* Test ".\74 wo-wi\74out-space" (.two-wi74out-space) */
.\74 wo-wi\74out-space {}

/* Test ".four-n\0085-space" (.four-n0085-space) */
.four-n\0085-space {}

/* Test "" Out of range unicode char, uses replace instead */
.\110000\0075\74\cc6699frange {}

.escape\|random\|char {
color: red;
}

.mixin\!tUp {
font-weight: bold;
}

.\34 04 {
background: red;
}

.\34 04 strong {
color: #ff00ff;
font-weight: bold;
}

.trailingTest\+ {
color: red;
}

/* This hideous test of hideousness checks for the selector "blockquote" with various permutations of hex escapes */
\62\6c\6f \63 \6B \0071 \000075o\74 e {
color: silver;
}
77 changes: 76 additions & 1 deletion test/spec/CSSUtils-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ define(function (require, exports, module) {
universalCssFileEntry = new NativeFileSystem.FileEntry(testPath + "/universal.css"),
groupsFileEntry = new NativeFileSystem.FileEntry(testPath + "/groups.css"),
offsetsCssFileEntry = new NativeFileSystem.FileEntry(testPath + "/offsets.css"),
bootstrapCssFileEntry = new NativeFileSystem.FileEntry(testPath + "/bootstrap.css");
bootstrapCssFileEntry = new NativeFileSystem.FileEntry(testPath + "/bootstrap.css"),
escapesCssFileEntry = new NativeFileSystem.FileEntry(testPath + "/escaped-identifiers.css");


/**
Expand Down Expand Up @@ -251,6 +252,80 @@ define(function (require, exports, module) {
});
});


describe("escapes", function() {

beforeEach(function () {
init(this, escapesCssFileEntry);
});

it("should remove simple backslashes for simple characters", function() {
var selectors = CSSUtils.extractAllSelectors(this.fileCssContent);
expect(selectors[0].selector).toEqual(".simple");
});

it("should remove simple backslashes with escaped characters", function() {
var selectors = CSSUtils.extractAllSelectors(this.fileCssContent);
expect(selectors[1].selector).toEqual(".not\\so|simple?");
});

it("should parse '\\XX ' as a single character", function() {
var selectors = CSSUtils.extractAllSelectors(this.fileCssContent);
expect(selectors[2].selector).toEqual(".twodigits");
});

it("should parse '\\XXXX ' as a single character", function() {
var selectors = CSSUtils.extractAllSelectors(this.fileCssContent);
expect(selectors[3].selector).toEqual(".fourdigits");
});

it("should parse '\\XXXXXX' as a single character", function() {
var selectors = CSSUtils.extractAllSelectors(this.fileCssContent);
expect(selectors[4].selector).toEqual(".sixdigits");
});

it("should not trim end spaces", function() {
var selectors = CSSUtils.extractAllSelectors(this.fileCssContent);
expect(selectors[5].selector).toEqual(".two-digit-endspace");

selectors = CSSUtils.extractAllSelectors(this.fileCssContent);
expect(selectors[6].selector).toEqual(".four-digit-endspace");

selectors = CSSUtils.extractAllSelectors(this.fileCssContent);
expect(selectors[7].selector).toEqual(".six-digit-endspace");
});

it("should detect all combinations", function() {
var selectors = CSSUtils.extractAllSelectors(this.fileCssContent);
expect(selectors[8].selector).toEqual(".mixin-it-all");
});

it("should parse '\\AX' as AX", function() {
var selectors = CSSUtils.extractAllSelectors(this.fileCssContent);
expect(selectors[9].selector).toEqual(".two-wi74out-space");
});

it("should parse '\\AXXX' as AXXX", function() {
var selectors = CSSUtils.extractAllSelectors(this.fileCssContent);
expect(selectors[10].selector).toEqual(".four-n0085-space");
});

it("should replace out of range characters with �", function() {
var selectors = CSSUtils.extractAllSelectors(this.fileCssContent);
expect(selectors[11].selector).toEqual(".�ut�frange");
});

it("should parse everything less does", function() {
var selectors = CSSUtils.extractAllSelectors(this.fileCssContent);
expect(selectors[12].selector).toEqual(".escape|random|char");
expect(selectors[13].selector).toEqual(".mixin!tUp");
expect(selectors[14].selector).toEqual(".404");
expect(selectors[15].selector).toEqual(".404 strong");
expect(selectors[16].selector).toEqual(".trailingTest+");
expect(selectors[17].selector).toEqual("blockquote");
});
});

}); // describe("CSSUtils")


Expand Down