feat(ShadowCss): port implementation from webcomponent.js

This commit is contained in:
Victor Berchet
2015-02-19 13:42:18 -08:00
committed by Misko Hevery
parent 89b3995756
commit d67f0299cd
6 changed files with 715 additions and 1 deletions
File diff suppressed because it is too large Load Diff
+12
View File
@@ -4,6 +4,8 @@ import 'dart:html';
import 'dart:js' show JsObject, context;
export 'dart:html' show
CssRule,
CssKeyframesRule,
document,
DocumentFragment,
Element,
@@ -109,6 +111,9 @@ class DOM {
if (doc == null) doc = document;
return doc.createElement(tagName);
}
static createTextNode(String text, [HtmlDocument doc = null]) {
return new Text(text);
}
static createScriptTag(String attrName, String attrValue,
[HtmlDocument doc = null]) {
if (doc == null) doc = document;
@@ -183,3 +188,10 @@ class DOM {
static bool isElementNode(Node node) =>
node.nodeType == Node.ELEMENT_NODE;
}
class CSSRuleWrapper {
static isPageRule(CssRule rule) => rule is CssPageRule;
static isStyleRule(CssRule rule) => rule is CssStyleRule;
static isMediaRule(CssRule rule) => rule is CssMediaRule;
static isKeyframesRule(CssRule rule) => rule is CssKeyframesRule;
}
+20
View File
@@ -11,6 +11,8 @@ export var StyleElement = window.HTMLStyleElement;
export var document = window.document;
export var location = window.location;
export var gc = window.gc ? () => window.gc() : () => null;
export var CssRule = window.CSSRule;
export var CssKeyframesRule = window.CSSKeyframesRule;
export class DOM {
static query(selector) {
@@ -129,6 +131,9 @@ export class DOM {
static createElement(tagName, doc=document) {
return doc.createElement(tagName);
}
static createTextNode(text: string, doc=document) {
return doc.createTextNode(text);
}
static createScriptTag(attrName:string, attrValue:string, doc=document) {
var el = doc.createElement("SCRIPT");
el.setAttribute(attrName, attrValue);
@@ -215,3 +220,18 @@ export class DOM {
return node.nodeType === Node.ELEMENT_NODE;
}
}
export class CSSRuleWrapper {
static isPageRule(rule) {
return rule.type === CSSRule.PAGE_RULE;
}
static isStyleRule(rule) {
return rule.type === CSSRule.STYLE_RULE;
}
static isMediaRule(rule) {
return rule.type === CSSRule.MEDIA_RULE;
}
static isKeyframesRule(rule) {
return rule.type === CSSRule.KEYFRAMES_RULE;
}
}
+4
View File
@@ -59,6 +59,10 @@ class StringWrapper {
return s == s2;
}
static String replace(String s, Pattern from, String replace) {
return s.replaceFirst(from, replace);
}
static String replaceAll(String s, RegExp from, String replace) {
return s.replaceAll(from, replace);
}
+12 -1
View File
@@ -77,6 +77,14 @@ export class StringWrapper {
return s === s2;
}
static replace(s:string, from , replace:string): string {
if (typeof(from) === "string") {
return s.replace(from, replace);
} else {
return s.replace(from.single, replace);
}
}
static replaceAll(s:string, from:RegExp, replace:string):string {
return s.replace(from.multiple, replace);
}
@@ -91,6 +99,9 @@ export class StringWrapper {
static replaceAllMapped(s:string, from:RegExp, cb:Function): string {
return s.replace(from.multiple, function(...matches) {
// Remove offset & string from the result array
matches.splice(-2, 2);
// The callback receives match, p1, ..., pn
return cb(matches);
});
}
@@ -171,7 +182,7 @@ export class NumberWrapper {
}
}
var RegExp;
export var RegExp;
if (assertionsEnabled_) {
RegExp = assert.define('RegExp', function(obj) {
assert(obj).is(assert.structure({
@@ -0,0 +1,112 @@
import {describe, beforeEach, it, expect, ddescribe, iit, SpyObject, el} from 'angular2/test_lib';
import {ShadowCss} from 'angular2/src/core/compiler/shadow_dom_emulation/shadow_css';
import {RegExpWrapper, StringWrapper} from 'angular2/src/facade/lang';
export function main() {
describe('ShadowCss', function() {
function s(css: string, tag:string) {
var shadowCss = new ShadowCss();
var shim = shadowCss.shimCssText(css, tag);
var nlRegexp = RegExpWrapper.create('\\n');
return StringWrapper.replaceAll(shim, nlRegexp, '');
}
it('should handle empty string', () => {
expect(s('', 'a')).toEqual('');
});
it('should add an attribute to every rule', () => {
var css = 'one {color: red;}two {color: red;}';
var expected = 'one[a] {color: red;}two[a] {color: red;}';
expect(s(css, 'a')).toEqual(expected);
});
it('should hanlde invalid css', () => {
var css = 'one {color: red;}garbage';
var expected = 'one[a] {color: red;}';
expect(s(css, 'a')).toEqual(expected);
});
it('should add an attribute to every selector', () => {
var css = 'one, two {color: red;}';
var expected = 'one[a], two[a] {color: red;}';
expect(s(css, 'a')).toEqual(expected);
});
it('should handle media rules', () => {
var css = '@media screen and (max-width: 800px) {div {font-size: 50px;}}';
var expected = '@media screen and (max-width: 800px) {div[a] {font-size: 50px;}}';
expect(s(css, 'a')).toEqual(expected);
});
it('should handle media rules with simple rules', () => {
var css = '@media screen and (max-width: 800px) {div {font-size: 50px;}} div {}';
var expected = '@media screen and (max-width: 800px) {div[a] {font-size: 50px;}}div[a] {}';
expect(s(css, 'a')).toEqual(expected);
});
it('should handle complicated selectors', () => {
expect(s('one::before {}', 'a')).toEqual('one[a]::before {}');
expect(s('one two {}', 'a')).toEqual('one[a] two[a] {}');
expect(s('one>two {}', 'a')).toEqual('one[a] > two[a] {}');
expect(s('one+two {}', 'a')).toEqual('one[a] + two[a] {}');
expect(s('one~two {}', 'a')).toEqual('one[a] ~ two[a] {}');
expect(s('.one.two > three {}', 'a')).toEqual('.one.two[a] > three[a] {}');
expect(s('one[attr="value"] {}', 'a')).toEqual('one[attr="value"][a] {}');
expect(s('one[attr=value] {}', 'a')).toEqual('one[attr="value"][a] {}');
expect(s('one[attr^="value"] {}', 'a')).toEqual('one[attr^="value"][a] {}');
expect(s('one[attr$="value"] {}', 'a')).toEqual('one[attr$="value"][a] {}');
expect(s('one[attr*="value"] {}', 'a')).toEqual('one[attr*="value"][a] {}');
expect(s('one[attr|="value"] {}', 'a')).toEqual('one[attr|="value"][a] {}');
expect(s('one[attr] {}', 'a')).toEqual('one[attr][a] {}');
expect(s('[is="one"] {}', 'a')).toEqual('[is="one"][a] {}');
});
it('should handle :host', () => {
expect(s(':host {}', 'a')).toEqual('a {}');
expect(s(':host(.x,.y) {}', 'a')).toEqual('a.x, a.y {}');
expect(s(':host(.x,.y) > .z {}', 'a')).toEqual('a.x > .z, a.y > .z {}');
});
it('should handle :host-context', () => {
expect(s(':host-context(.x) {}', 'a')).toEqual('a.x, .x a {}');
expect(s(':host-context(.x) > .y {}', 'a')).toEqual('a.x > .y, .x a > .y {}');
});
it('should support polyfill-next-selector', () => {
var css = s("polyfill-next-selector {content: 'x > y'} z {}", 'a');
expect(css).toEqual('x[a] > y[a] {}');
css = s('polyfill-next-selector {content: "x > y"} z {}', 'a');
expect(css).toEqual('x[a] > y[a] {}');
});
it('should support polyfill-unscoped-rule', () => {
var css = s("polyfill-unscoped-rule {content: '#menu > .bar';background: blue;}", 'a');
expect(StringWrapper.contains(css, '#menu > .bar {;background: blue;}')).toBeTruthy();
css = s('polyfill-unscoped-rule {content: "#menu > .bar";background: blue;}', 'a');
expect(StringWrapper.contains(css, '#menu > .bar {;background: blue;}')).toBeTruthy();
});
it('should support polyfill-rule', () => {
var css = s("polyfill-rule {content: ':host.foo .bar';background: blue;}", 'a');
expect(css).toEqual('a.foo .bar {background: blue;}');
css = s('polyfill-rule {content: ":host.foo .bar";background: blue;}', 'a');
expect(css).toEqual('a.foo .bar {background: blue;}');
});
it('should handle ::shadow', () => {
var css = s('x::shadow > y {}', 'a');
expect(css).toEqual('x[a] > y[a] {}');
});
it('should handle /deep/', () => {
var css = s('x /deep/ y {}', 'a');
expect(css).toEqual('x[a] y[a] {}');
});
});
}