diff --git a/src/style.js b/src/style.js index 4441f4f5d..12edc5a5b 100644 --- a/src/style.js +++ b/src/style.js @@ -1,50 +1,53 @@ -import Omi from './omi.js' - -//many thanks to https://github.com/thomaspark/scoper/ -function scoper(css, prefix) { - let re = new RegExp("([^\r\n,{}]+)(,(?=[^}]*{)|\s*{)", "g") - css = css.replace(re, function(g0, g1, g2) { - - if (g1.match(/^\s*(@media|@keyframes|to|from|@font-face)/)) { - return g1 + g2 - } - - if (g1.match(/:scope/)) { - g1 = g1.replace(/([^\s]*):scope/, function (h0, h1) { - if (h1 === "") { - return "> *" - } else { - return "> " + h1 - } - }) - } - - g1 = g1.replace(/^(\s*)/, g1.trim() + prefix + "," + "$1" + prefix + " ").replace(/\s+/g, ' ') - return g1 + g2 - }) - - return css -} - -function addStyle(cssText, id) { - let ele = document.getElementById(Omi.STYLEPREFIX + id), - head = document.getElementsByTagName('head')[0] - if (ele && ele.parentNode === head) { - head.removeChild(ele) - } - - let someThingStyles = document.createElement('style') - head.appendChild(someThingStyles) - someThingStyles.setAttribute('type', 'text/css') - someThingStyles.setAttribute('id',Omi.STYLEPREFIX + id) - if (!!window.ActiveXObject) { - someThingStyles.styleSheet.cssText = cssText - } else { - someThingStyles.textContent = cssText - } -} - -export default { - scoper:scoper, - addStyle:addStyle +import Omi from './omi.js' + +//many thanks to https://github.com/thomaspark/scoper/ +function scoper(css, prefix) { + let re = new RegExp("([^\r\n,{}:]+)(:[^\r\n,{}]+)?(,(?=[^{]*{)|\s*{)", "g") + /** + * Example: + * + * .classname::pesudo { color:red } + * + * g1 is normal selector `.classname` + * g2 is pesudo class or pesudo element + * g3 is the suffix + */ + css = css.replace(re, function(g0, g1, g2, g3) { + if (typeof g2 === "undefined") { + g2 = ""; + } + + if (g1.match(/^\s*(@media|@keyframes|to|from|@font-face)/)) { + return g1 + g2 + g3 + } + + var appendClass = g1.replace(/(\s*)$/, "") + prefix + g2 + var prependClass = prefix + " " + g1.trim() + g2; + return appendClass + "," + prependClass + g3 + }) + + return css +} + +function addStyle(cssText, id) { + let ele = document.getElementById(Omi.STYLEPREFIX + id), + head = document.getElementsByTagName('head')[0] + if (ele && ele.parentNode === head) { + head.removeChild(ele) + } + + let someThingStyles = document.createElement('style') + head.appendChild(someThingStyles) + someThingStyles.setAttribute('type', 'text/css') + someThingStyles.setAttribute('id',Omi.STYLEPREFIX + id) + if (!!window.ActiveXObject) { + someThingStyles.styleSheet.cssText = cssText + } else { + someThingStyles.textContent = cssText + } +} + +export default { + scoper:scoper, + addStyle:addStyle } \ No newline at end of file diff --git a/test/js/style.js b/test/js/style.js index 703e53c7d..52d5d1b15 100644 --- a/test/js/style.js +++ b/test/js/style.js @@ -1,29 +1,76 @@ +import assert from 'assert'; import style from '../../src/style.js'; describe("scoper", function() { + describe("Attribute selector as prefix", function() { + var result = style.scoper(".active{ color:red};","[attribute]"); + it("expect attribute selector prefix works well", function() { + expect(result).toBe(".active[attribute],[attribute] .active{ color:red};"); + }); + }); - var result = style.scoper(".active{ color:red};","[ab12]") - it("and so is a spec", function() { - expect(result).toBe(".active[ab12],[ab12] .active{ color:red};"); - }); -}); - -describe("scoper-ml", function() { - - var result = style.scoper(".active{ " + - "color:red" + - "};","#test") - it("and so is a spec", function() { - expect(result).toBe(".active#test,#test .active{ " + - "color:red" + - "};"); - }); -}); - -describe("scoper3", function() { - - var result = style.scoper(".active,.xx{ color:red};","#ab12") - it("and so is a spec", function() { - expect(result).toBe(".active#ab12,#ab12 .active,.xx#ab12,#ab12 .xx{ color:red};"); + describe("Id selector as prefix", function() { + var result = style.scoper(".active{ color:red};","#id"); + it("expect id selector prefix works well", function() { + expect(result).toBe(".active#id,#id .active{ color:red};"); + }); + }); + + describe("Two classes", function() { + var result = style.scoper(".active,.xx{ color:red};","#id"); + it("expect id selector prefix works well with two class selector", function() { + expect(result).toBe(".active#id,#id .active,.xx#id,#id .xx{ color:red};"); + }); + }); + + describe("Pseudo class", function() { + var result = style.scoper(".active:hover{ color:red};","[attribute]"); + it("expect pseudo class works well", function() { + expect(result).toBe(".active[attribute]:hover,[attribute] .active:hover{ color:red};"); + }); + }); + + describe("Pseudo element", function() { + var result = style.scoper(".active::after{ color:red};","[attribute]"); + it("expect pseudo element works well", function() { + expect(result).toBe(".active[attribute]::after,[attribute] .active::after{ color:red};"); + }); + }); + + describe("Quoted values", function() { + var result = style.scoper(".active { font-family: \"Helvetica Neue\"};","[attribute]"); + it("expect quoted values works well", function() { + expect(result).toBe(".active[attribute],[attribute] .active{ font-family: \"Helvetica Neue\"};"); + }); + }); + + describe("Media queries", function() { + var rule = "@media (max-width: 600px) {\n" + + " h1 {\n" + + " font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n" + + " }" + + "}"; + var expected = "@media (max-width: 600px) {\n" + + " h1#scoper-1,#scoper-1 h1{\n" + + " font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n" + + " }" + + "}"; + var actual = style.scoper(rule, "#scoper-1"); + it("expect media queries works well", function() { + expect(actual).toBe(expected); + }); + }); + + describe("Font faces", function() { + var rule = "@font-face {\n" + + " font-family: 'MyWebFont';\n" + + " src: url('myfont.woff2') format('woff2');\n" + + " url('myfont.woff') format('woff');\n" + + "}"; + var expected = rule; + var actual = style.scoper(rule, "#scoper-1"); + it("expect font faces works well", function() { + expect(actual).toBe(expected); + }); }); });