diff --git a/test-utils/domMock.js b/test-utils/domMock.js index cde58a24..d6821aec 100644 --- a/test-utils/domMock.js +++ b/test-utils/domMock.js @@ -75,11 +75,69 @@ module.exports = function() { function removeAttribute(name) { delete this.attributes[name] } + var declListTokenizer = /;|"(?:\\.|[^"\n])*"|'(?:\\.|[^'\n])*'/g + /** + * This will split a semicolon-separated CSS declaration list into an array of + * individual declarations, ignoring semicolons in strings. + * + * Comments are also stripped. + * + * @param {string} declList + * @return {string[]} + */ + function splitDeclList(declList) { + var indices = [], res = [], inParen = 0, match + + // remove comments, preserving comments in strings. + declList = declList.replace( + /("(?:\\.|[^"\n])*"|'(?:\\.|[^'\n])*')|\/\*[\s\S]*?\*\//g, + function(m, str){ + return str || '' + } + ) + /*eslint-disable no-cond-assign*/ + while (match = declListTokenizer.exec(declList)) { + if (match[0] === ";") indices.push(match.index) + } + /*eslint-enable no-cond-assign*/ + for (var i = indices.length; i--;){ + res.unshift(declList.slice(indices[i] + 1)) + declList = declList.slice(0, indices[i]) + } + res.unshift(declList) + return res + } + var activeElement var $window = { document: { createElement: function(tag, is) { + var cssText = "" var style = {} + Object.defineProperty(style, "cssText", { + get: function() {return cssText}, + set: function (value) { + var buf = [] + if (typeof value === "string") { + for (var key in style) style[key] = "" + var rules = splitDeclList(value) + for (var i = 0; i < rules.length; i++) { + var rule = rules[i] + var colonIndex = rule.indexOf(":") + if (colonIndex > -1) { + var rawKey = rule.slice(0, colonIndex).trim() + var key = rawKey.replace(/-\D/g, function(match) {return match[1].toUpperCase()}) + var value = rule.slice(colonIndex + 1).trim() + if (key !== "cssText") { + style[key] = value + buf.push(rawKey + ": " + value + ";") + } + } + } + cssText = buf.join(" ") + } + } + }) var events = {} var element = { nodeType: 1, @@ -140,21 +198,6 @@ module.exports = function() { // https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/style#Setting_style throw new Error("setting element.style is not portable") }, - set cssText(value) { - if (typeof value === "string") { - for (var key in style) style[key] = "" - var rules = value.split(";") - for (var i = 0; i < rules.length; i++) { - var rule = rules[i] - var colonIndex = rule.indexOf(":") - if (colonIndex > -1) { - var key = rule.slice(0, colonIndex).trim().replace(/-\D/g, function(match) {return match[1].toUpperCase()}) - var value = rule.slice(colonIndex + 1).trim() - style[key] = value - } - } - } - }, get className() { return this.attributes["class"] ? this.attributes["class"].nodeValue : "" }, diff --git a/test-utils/tests/test-domMock.js b/test-utils/tests/test-domMock.js index 2b589673..b08df230 100644 --- a/test-utils/tests/test-domMock.js +++ b/test-utils/tests/test-domMock.js @@ -474,20 +474,56 @@ o.spec("domMock", function() { o(typeof div.style).equals("object") }) - o("setting cssText string works", function() { + o("setting style.cssText string works", function() { var div = $document.createElement("div") - div.cssText = "background-color: red; border-bottom: 1px solid red;" + div.style.cssText = "background-color: red; border-bottom: 1px solid red;" o(div.style.backgroundColor).equals("red") o(div.style.borderBottom).equals("1px solid red") }) - o("removing via setting cssText string works", function() { + o("removing via setting style.cssText string works", function() { var div = $document.createElement("div") - div.cssText = "background: red;" - div.cssText = "" + div.style.cssText = "background: red;" + div.style.cssText = "" o(div.style.background).equals("") }) + o("the final semicolon is optional when setting style.cssText", function() { + var div = $document.createElement("div") + div.style.cssText = "background: red" + + o(div.style.background).equals("red") + o(div.style.cssText).equals("background: red;") + }) + o("'cssText' as a property name is ignored when setting style.cssText", function(){ + var div = $document.createElement("div") + div.style.cssText = "cssText: red;" + + o(div.style.cssText).equals("") + }) + o("setting style.cssText that has a semi-colon in a strings", function(){ + var div = $document.createElement("div") + div.style.cssText = "background: url(';'); font-family: \";\"" + + o(div.style.background).equals("url(';')") + o(div.style.fontFamily).equals("\";\"") + o(div.style.cssText).equals("background: url(';'); font-family: \";\";") + }) + o("comments in style.cssText are stripped", function(){ + var div = $document.createElement("div") + div.style.cssText = "/**/background/*:*/: /*>;)*/red/**/;/**/" + + o(div.style.background).equals("red") + o(div.style.cssText).equals("background: red;") + + }) + o("comments in strings in style.cssText are preserved", function(){ + var div = $document.createElement("div") + div.style.cssText = "background: url('/*foo*/')" + + o(div.style.background).equals("url('/*foo*/')") + + }) o("setting style throws", function () { var err = false try {