Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4)

Unified Diff: third_party/pkg/angular/lib/core_dom/selector.dart

Issue 124053002: Adding Angular and dependent packages for testing (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 12 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/pkg/angular/lib/core_dom/selector.dart
diff --git a/third_party/pkg/angular/lib/core_dom/selector.dart b/third_party/pkg/angular/lib/core_dom/selector.dart
new file mode 100644
index 0000000000000000000000000000000000000000..3491330775330f32fe330635b0d108b921196132
--- /dev/null
+++ b/third_party/pkg/angular/lib/core_dom/selector.dart
@@ -0,0 +1,318 @@
+part of angular.core.dom;
+
+/**
+ * DirectiveSelector is a function which given a node it will return a
+ * list of [DirectiveRef]s which are triggered by this node.
+ *
+ * DirectiveSelector is used by the [Compiler] during the template walking
+ * to extract the [DirectiveRef]s.
+ *
+ * DirectiveSelector can be created using the [directiveSelectorFactory]
+ * method.
+ *
+ * The DirectiveSelector supports CSS selectors which do not cross
+ * element boundaries only. The selectors can have any mix of element-name,
+ * class-names and attribute-names.
+ *
+ * Examples:
+ *
+ * <pre>
+ * element
+ * .class
+ * [attribute]
+ * [attribute=value]
+ * element[attribute1][attribute2=value]
+ * </pre>
+ *
+ *
+ */
+typedef List<DirectiveRef> DirectiveSelector(dom.Node node);
+
+class _Directive {
+ final Type type;
+ final NgAnnotation annotation;
+
+ _Directive(Type this.type, NgAnnotation this.annotation);
+
+ toString() => annotation.selector;
+}
+
+
+class _ContainsSelector {
+ NgAnnotation annotation;
+ RegExp regexp;
+
+ _ContainsSelector(this.annotation, String regexp) {
+ this.regexp = new RegExp(regexp);
+ }
+}
+
+RegExp _SELECTOR_REGEXP = new RegExp(r'^(?:([\w\-]+)|(?:\.([\w\-]+))|(?:\[([\w\-]+)(?:=([^\]]*))?\]))');
+RegExp _COMMENT_COMPONENT_REGEXP = new RegExp(r'^\[([\w\-]+)(?:\=(.*))?\]$');
+RegExp _CONTAINS_REGEXP = new RegExp(r'^:contains\(\/(.+)\/\)$'); //
+RegExp _ATTR_CONTAINS_REGEXP = new RegExp(r'^\[\*=\/(.+)\/\]$'); //
+
+class _SelectorPart {
+ final String element;
+ final String className;
+ final String attrName;
+ final String attrValue;
+
+ const _SelectorPart.fromElement(String this.element)
+ : className = null, attrName = null, attrValue = null;
+
+ const _SelectorPart.fromClass(String this.className)
+ : element = null, attrName = null, attrValue = null;
+
+
+ const _SelectorPart.fromAttribute(String this.attrName, String this.attrValue)
+ : element = null, className = null;
+
+ toString() =>
+ element == null
+ ? (className == null
+ ? (attrValue == '' ? '[$attrName]' : '[$attrName=$attrValue]')
+ : '.$className')
+ : element;
+}
+
+
+class _ElementSelector {
+ String name;
+
+ Map<String, _Directive> elementMap = new Map<String, _Directive>();
+ Map<String, _ElementSelector> elementPartialMap = new Map<String, _ElementSelector>();
+
+ Map<String, _Directive> classMap = new Map<String, _Directive>();
+ Map<String, _ElementSelector> classPartialMap = new Map<String, _ElementSelector>();
+
+ Map<String, Map<String, _Directive>> attrValueMap = new Map<String, Map<String, _Directive>>();
+ Map<String, Map<String, _ElementSelector>> attrValuePartialMap = new Map<String, Map<String, _ElementSelector>>();
+
+ _ElementSelector(this.name);
+
+ addDirective(List<_SelectorPart> selectorParts, _Directive directive) {
+ var selectorPart = selectorParts.removeAt(0);
+ var terminal = selectorParts.isEmpty;
+ var name;
+ if ((name = selectorPart.element) != null) {
+ if (terminal) {
+ elementMap[name] = directive;
+ } else {
+ elementPartialMap
+ .putIfAbsent(name, () => new _ElementSelector(name))
+ .addDirective(selectorParts, directive);
+ }
+ } else if ((name = selectorPart.className) != null) {
+ if (terminal) {
+ classMap[name] = directive;
+ } else {
+ classPartialMap
+ .putIfAbsent(name, () => new _ElementSelector(name))
+ .addDirective(selectorParts, directive);
+ }
+ } else if ((name = selectorPart.attrName) != null) {
+ if (terminal) {
+ attrValueMap
+ .putIfAbsent(name, () => new Map<String, _Directive>())
+ [selectorPart.attrValue] = directive;
+ } else {
+ attrValuePartialMap
+ .putIfAbsent(name, () => new Map<String, _ElementSelector>())
+ .putIfAbsent(selectorPart.attrValue, () => new _ElementSelector(name))
+ .addDirective(selectorParts, directive);
+ }
+ } else {
+ throw "Unknown selector part '$selectorPart'.";
+ }
+ }
+
+ List<_ElementSelector> selectNode(List<DirectiveRef> refs, List<_ElementSelector> partialSelection,
+ dom.Node node, String nodeName) {
+ if (elementMap.containsKey(nodeName)) {
+ _Directive directive = elementMap[nodeName];
+ refs.add(new DirectiveRef(node, directive.type, directive.annotation));
+ }
+ if (elementPartialMap.containsKey(nodeName)) {
+ if (partialSelection == null) partialSelection = new List<_ElementSelector>();
+ partialSelection.add(elementPartialMap[nodeName]);
+ }
+ return partialSelection;
+ }
+
+ List<_ElementSelector> selectClass(List<DirectiveRef> refs, List<_ElementSelector> partialSelection,
+ dom.Node node, String className) {
+ if (classMap.containsKey(className)) {
+ var directive = classMap[className];
+ refs.add(new DirectiveRef(node, directive.type, directive.annotation));
+ }
+ if (classPartialMap.containsKey(className)) {
+ if (partialSelection == null) partialSelection = new List<_ElementSelector>();
+ partialSelection.add(classPartialMap[className]);
+ }
+ return partialSelection;
+ }
+
+ List<_ElementSelector> selectAttr(List<DirectiveRef> refs, List<_ElementSelector> partialSelection,
+ dom.Node node, String attrName, String attrValue) {
+ if (attrValueMap.containsKey(attrName)) {
+ Map<String, _Directive> valuesMap = attrValueMap[attrName];
+ if (valuesMap.containsKey('')) {
+ _Directive directive = valuesMap[''];
+ refs.add(new DirectiveRef(node, directive.type, directive.annotation, attrValue));
+ }
+ if (attrValue != '' && valuesMap.containsKey(attrValue)) {
+ _Directive directive = valuesMap[attrValue];
+ refs.add(new DirectiveRef(node, directive.type, directive.annotation, attrValue));
+ }
+ }
+ if (attrValuePartialMap.containsKey(attrName)) {
+ Map<String, _ElementSelector> valuesPartialMap = attrValuePartialMap[attrName];
+ if (valuesPartialMap.containsKey('')) {
+ if (partialSelection == null) partialSelection = new List<_ElementSelector>();
+ partialSelection.add(valuesPartialMap['']);
+ }
+ if (attrValue != '' && valuesPartialMap.containsKey(attrValue)) {
+ if (partialSelection == null) partialSelection = new List<_ElementSelector>();
+ partialSelection.add(valuesPartialMap[attrValue]);
+ }
+ }
+ return partialSelection;
+ }
+
+ toString() => 'ElementSelector($name)';
+}
+
+List<_SelectorPart> _splitCss(String selector) {
+ List<_SelectorPart> parts = [];
+ var remainder = selector;
+ var match;
+ while (!remainder.isEmpty) {
+ if ((match = _SELECTOR_REGEXP.firstMatch(remainder)) != null) {
+ if (match[1] != null) {
+ parts.add(new _SelectorPart.fromElement(match[1].toLowerCase()));
+ } else if (match[2] != null) {
+ parts.add(new _SelectorPart.fromClass(match[2].toLowerCase()));
+ } else if (match[3] != null) {
+ var attrValue = match[4] == null ? '' : match[4].toLowerCase();
+ parts.add(new _SelectorPart.fromAttribute(match[3].toLowerCase(),
+ attrValue));
+ } else {
+ throw "Missmatched RegExp $_SELECTOR_REGEXP on $remainder";
+ }
+ } else {
+ throw "Unknown selector format '$remainder'.";
+ }
+ remainder = remainder.substring(match.end);
+ }
+ return parts;
+}
+
+/**
+ *
+ * Factory method for creating a [DirectiveSelector].
+ */
+DirectiveSelector directiveSelectorFactory(DirectiveMap directives) {
+
+ _ElementSelector elementSelector = new _ElementSelector('');
+ List<_ContainsSelector> attrSelector = [];
+ List<_ContainsSelector> textSelector = [];
+
+ directives.forEach((NgAnnotation annotation, Type type) {
+ var match;
+ var selector = annotation.selector;
+ List<_SelectorPart> selectorParts;
+
+ if ((match = _CONTAINS_REGEXP.firstMatch(selector)) != null) {
+ textSelector.add(new _ContainsSelector(annotation, match.group(1)));
+ } else if ((match = _ATTR_CONTAINS_REGEXP.firstMatch(selector)) != null) {
+ attrSelector.add(new _ContainsSelector(annotation, match[1]));
+ } else if ((selectorParts = _splitCss(selector)) != null){
+ elementSelector.addDirective(selectorParts, new _Directive(type, annotation));
+ } else {
+ throw new ArgumentError('Unsupported Selector: $selector');
+ }
+ });
+
+ return (dom.Node node) {
+ List<DirectiveRef> directiveRefs = [];
+ List<_ElementSelector> partialSelection = null;
+ Map<String, bool> classes = new Map<String, bool>();
+ Map<String, String> attrs = new Map<String, String>();
+
+ switch(node.nodeType) {
+ case 1: // Element
+ dom.Element element = node;
+ String nodeName = element.tagName.toLowerCase();
+ Map<String, String> attrs = {};
+
+ // Select node
+ partialSelection = elementSelector.selectNode(directiveRefs, partialSelection, element, nodeName);
+
+ // Select .name
+ if ((element.classes) != null) {
+ for(var name in element.classes) {
+ classes[name] = true;
+ partialSelection = elementSelector.selectClass(directiveRefs, partialSelection, element, name);
+ }
+ }
+
+ // Select [attributes]
+ element.attributes.forEach((attrName, value){
+ attrs[attrName] = value;
+ for(var k = 0, kk = attrSelector.length; k < kk; k++) {
+ _ContainsSelector selectorRegExp = attrSelector[k];
+ if (selectorRegExp.regexp.hasMatch(value)) {
+ // this directive is matched on any attribute name, and so
+ // we need to pass the name to the directive by prefixing it to the
+ // value. Yes it is a bit of a hack.
+ Type type = directives[selectorRegExp.annotation];
+ directiveRefs.add(new DirectiveRef(
+ node, type, selectorRegExp.annotation, '$attrName=$value'));
+ }
+ }
+
+ partialSelection = elementSelector.selectAttr(directiveRefs, partialSelection, node, attrName, value);
+ });
+
+ while(partialSelection != null) {
+ List<_ElementSelector> elementSelectors = partialSelection;
+ partialSelection = null;
+ elementSelectors.forEach((_ElementSelector elementSelector) {
+ classes.forEach((className, _) {
+ partialSelection = elementSelector.selectClass(directiveRefs, partialSelection, node, className);
+ });
+ attrs.forEach((attrName, value) {
+ partialSelection = elementSelector.selectAttr(directiveRefs, partialSelection, node, attrName, value);
+ });
+ });
+ }
+ break;
+ case 3: // Text Node
+ for(var value = node.nodeValue, k = 0, kk = textSelector.length; k < kk; k++) {
+ var selectorRegExp = textSelector[k];
+
+ if (selectorRegExp.regexp.hasMatch(value)) {
+ Type type = directives[selectorRegExp.annotation];
+ directiveRefs.add(new DirectiveRef(node, type, selectorRegExp.annotation, value));
+ }
+ }
+ break;
+ }
+
+ directiveRefs.sort(_priorityComparator);
+ return directiveRefs;
+ };
+}
+
+int _directivePriority(NgAnnotation annotation) {
+ if (annotation is NgDirective) {
+ return (annotation.children == NgAnnotation.TRANSCLUDE_CHILDREN) ? 2 : 1;
+ } else if (annotation is NgComponent) {
+ return 0;
+ }
+ throw "Unexpected Type: ${annotation}.";
+}
+
+int _priorityComparator(DirectiveRef a, DirectiveRef b) =>
+ _directivePriority(b.annotation) - _directivePriority(a.annotation);

Powered by Google App Engine
This is Rietveld 408576698