Skip to content
This repository was archived by the owner on Feb 22, 2018. It is now read-only.
Closed
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
17 changes: 10 additions & 7 deletions lib/bootstrap.dart
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,11 @@ Injector _defaultInjectorFactory(List<Module> modules) =>
* Injector injector = ngBootstrap(module: myAppModule);
*/
Injector ngBootstrap({
Module module: null,
List<Module> modules: null,
dom.Element element: null,
String selector: '[ng-app]',
Injector injectorFactory(List<Module> modules): _defaultInjectorFactory}) {
Module module: null,
List<Module> modules: null,
dom.Element element: null,
String selector: '[ng-app]',
Injector injectorFactory(List<Module> modules): _defaultInjectorFactory}) {
_publishToJavaScript();

var ngModules = [new AngularModule()];
Expand All @@ -74,7 +74,9 @@ Injector ngBootstrap({
if (element == null) {
element = dom.querySelector(selector);
var document = dom.window.document;
if (element == null) element = document.childNodes.firstWhere((e) => e is dom.Element);
if (element == null) {
element = document.childNodes.firstWhere((e) => e is dom.Element);
}
}

// The injector must be created inside the zone, so we create the
Expand All @@ -87,7 +89,8 @@ Injector ngBootstrap({
return zone.run(() {
var rootElements = [element];
Injector injector = injectorFactory(ngModules);
injector.get(Compiler)(rootElements, injector.get(DirectiveMap))(injector, rootElements);
injector.get(Compiler)(rootElements, injector.get(DirectiveMap))
(injector, rootElements);
return injector;
});
}
Expand Down
149 changes: 87 additions & 62 deletions lib/core_dom/selector.dart
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class _Directive {
final Type type;
final NgAnnotation annotation;

_Directive(Type this.type, NgAnnotation this.annotation);
_Directive(this.type, this.annotation);

toString() => annotation.selector;
}
Expand All @@ -42,28 +42,30 @@ class _ContainsSelector {
final NgAnnotation annotation;
final RegExp regexp;

_ContainsSelector(this.annotation, String regexp) : regexp = new RegExp(regexp);
_ContainsSelector(this.annotation, String regexp)
: 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'^\[\*=\/(.+)\/\]$'); //
var _SELECTOR_REGEXP = new RegExp(r'^(?:([\w\-]+)|(?:\.([\w\-]+))|'
r'(?:\[([\w\-\*]+)(?:=([^\]]*))?\]))');
var _COMMENT_COMPONENT_REGEXP = new RegExp(r'^\[([\w\-]+)(?:\=(.*))?\]$');
var _CONTAINS_REGEXP = new RegExp(r'^:contains\(\/(.+)\/\)$'); //
var _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)
const _SelectorPart.fromElement(this.element)
: className = null, attrName = null, attrValue = null;

const _SelectorPart.fromClass(String this.className)
const _SelectorPart.fromClass(this.className)
: element = null, attrName = null, attrValue = null;


const _SelectorPart.fromAttribute(String this.attrName, String this.attrValue)
const _SelectorPart.fromAttribute(this.attrName, this.attrValue)
: element = null, className = null;

toString() =>
Expand All @@ -76,16 +78,16 @@ class _SelectorPart {


class _ElementSelector {
String name;
final String name;

Map<String, List<_Directive>> elementMap = new Map<String, List<_Directive>>();
Map<String, _ElementSelector> elementPartialMap = new Map<String, _ElementSelector>();
var elementMap = <String, List<_Directive>>{};
var elementPartialMap = <String, _ElementSelector>{};

Map<String, List<_Directive>> classMap = new Map<String, List<_Directive>>();
Map<String, _ElementSelector> classPartialMap = new Map<String, _ElementSelector>();
var classMap = <String, List<_Directive>>{};
var classPartialMap = <String, _ElementSelector>{};

Map<String, Map<String, List<_Directive>>> attrValueMap = new Map<String, Map<String, List<_Directive>>>();
Map<String, Map<String, _ElementSelector>> attrValuePartialMap = new Map<String, Map<String, _ElementSelector>>();
var attrValueMap = <String, Map<String, List<_Directive>>>{};
var attrValuePartialMap = <String, Map<String, _ElementSelector>>{};

_ElementSelector(this.name);

Expand All @@ -96,8 +98,8 @@ class _ElementSelector {
if ((name = selectorPart.element) != null) {
if (terminal) {
elementMap
.putIfAbsent(name, () => [])
.add(directive);
.putIfAbsent(name, () => [])
.add(directive);
} else {
elementPartialMap
.putIfAbsent(name, () => new _ElementSelector(name))
Expand All @@ -106,8 +108,8 @@ class _ElementSelector {
} else if ((name = selectorPart.className) != null) {
if (terminal) {
classMap
.putIfAbsent(name, () => [])
.add(directive);
.putIfAbsent(name, () => [])
.add(directive);
} else {
classPartialMap
.putIfAbsent(name, () => new _ElementSelector(name))
Expand All @@ -116,51 +118,62 @@ class _ElementSelector {
} else if ((name = selectorPart.attrName) != null) {
if (terminal) {
attrValueMap
.putIfAbsent(name, () => new Map<String, List<_Directive>>())
.putIfAbsent(name, () => <String, List<_Directive>>{})
.putIfAbsent(selectorPart.attrValue, () => [])
.add(directive);
} else {
attrValuePartialMap
.putIfAbsent(name, () => new Map<String, _ElementSelector>())
.putIfAbsent(selectorPart.attrValue, () => new _ElementSelector(name))
.putIfAbsent(name, () => <String, _ElementSelector>{})
.putIfAbsent(selectorPart.attrValue, () =>
new _ElementSelector(name))
.addDirective(selectorParts, directive);
}
} else {
throw "Unknown selector part '$selectorPart'.";
}
}

_addRefs(List<DirectiveRef> refs, List<_Directive> directives, dom.Node node, [String attrValue]) {
_addRefs(List<DirectiveRef> refs, List<_Directive> directives, dom.Node node,
[String attrValue]) {
directives.forEach((directive) =>
refs.add(new DirectiveRef(node, directive.type, directive.annotation, attrValue)));
refs.add(new DirectiveRef(node, directive.type, directive.annotation,
attrValue)));
}

List<_ElementSelector> selectNode(List<DirectiveRef> refs, List<_ElementSelector> partialSelection,
dom.Node node, String nodeName) {
List<_ElementSelector> selectNode(List<DirectiveRef> refs,
List<_ElementSelector> partialSelection,
dom.Node node, String nodeName) {
if (elementMap.containsKey(nodeName)) {
_addRefs(refs, elementMap[nodeName], node);
}
if (elementPartialMap.containsKey(nodeName)) {
if (partialSelection == null) partialSelection = new List<_ElementSelector>();
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) {
List<_ElementSelector> selectClass(List<DirectiveRef> refs,
List<_ElementSelector> partialSelection,
dom.Node node, String className) {
if (classMap.containsKey(className)) {
_addRefs(refs, classMap[className], node);
}
if (classPartialMap.containsKey(className)) {
if (partialSelection == null) partialSelection = new List<_ElementSelector>();
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) {
List<_ElementSelector> selectAttr(List<DirectiveRef> refs,
List<_ElementSelector> partialSelection,
dom.Node node, String attrName,
String attrValue) {

String matchingKey = _matchingKey(attrValueMap.keys, attrName);

Expand All @@ -174,30 +187,34 @@ class _ElementSelector {
}
}
if (attrValuePartialMap.containsKey(attrName)) {
Map<String, _ElementSelector> valuesPartialMap = attrValuePartialMap[attrName];
Map<String, _ElementSelector> valuesPartialMap =
attrValuePartialMap[attrName];
if (valuesPartialMap.containsKey('')) {
if (partialSelection == null) partialSelection = new List<_ElementSelector>();
if (partialSelection == null) {
partialSelection = new List<_ElementSelector>();
}
partialSelection.add(valuesPartialMap['']);
}
if (attrValue != '' && valuesPartialMap.containsKey(attrValue)) {
if (partialSelection == null) partialSelection = new List<_ElementSelector>();
if (partialSelection == null) {
partialSelection = new List<_ElementSelector>();
}
partialSelection.add(valuesPartialMap[attrValue]);
}
}
return partialSelection;
}

String _matchingKey(Iterable<String> keys, String attrName) {
return keys.firstWhere(
(key) => new RegExp('^${key.replaceAll('*', r'[\w\-]+')}\$').hasMatch(attrName),
orElse: () => null);
}
String _matchingKey(Iterable<String> keys, String attrName) =>
keys.firstWhere((key) =>
new RegExp('^${key.replaceAll('*', r'[\w\-]+')}\$')
.hasMatch(attrName), orElse: () => null);

toString() => 'ElementSelector($name)';
}

List<_SelectorPart> _splitCss(String selector, Type type) {
List<_SelectorPart> parts = [];
var parts = <_SelectorPart>[];
var remainder = selector;
var match;
while (!remainder.isEmpty) {
Expand Down Expand Up @@ -226,9 +243,9 @@ List<_SelectorPart> _splitCss(String selector, Type type) {
*/
DirectiveSelector directiveSelectorFactory(DirectiveMap directives) {

_ElementSelector elementSelector = new _ElementSelector('');
List<_ContainsSelector> attrSelector = [];
List<_ContainsSelector> textSelector = [];
var elementSelector = new _ElementSelector('');
var attrSelector = <_ContainsSelector>[];
var textSelector = <_ContainsSelector>[];
directives.forEach((NgAnnotation annotation, Type type) {
var match;
var selector = annotation.selector;
Expand All @@ -242,17 +259,18 @@ DirectiveSelector directiveSelectorFactory(DirectiveMap directives) {
} else if ((match = _ATTR_CONTAINS_REGEXP.firstMatch(selector)) != null) {
attrSelector.add(new _ContainsSelector(annotation, match[1]));
} else if ((selectorParts = _splitCss(selector, type)) != null){
elementSelector.addDirective(selectorParts, new _Directive(type, annotation));
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>();
var directiveRefs = <DirectiveRef>[];
List<_ElementSelector> partialSelection;
var classes = <String, bool>{};
var attrs = <String, String>{};

switch(node.nodeType) {
case 1: // Element
Expand All @@ -266,55 +284,62 @@ DirectiveSelector directiveSelectorFactory(DirectiveMap directives) {
}

// Select node
partialSelection = elementSelector.selectNode(directiveRefs, partialSelection, element, nodeName);
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);
partialSelection = elementSelector.selectClass(directiveRefs,
partialSelection, element, name);
}
}

// Select [attributes]
element.attributes.forEach((attrName, value){
element.attributes.forEach((attrName, value) {
attrs[attrName] = value;
for(var k = 0, kk = attrSelector.length; k < kk; k++) {
for(var k = 0; k < attrSelector.length; 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.
// we need to pass the name to the directive by prefixing it to
// the value. Yes it is a bit of a hack.
directives[selectorRegExp.annotation].forEach((type) {
directiveRefs.add(new DirectiveRef(
node, type, selectorRegExp.annotation, '$attrName=$value'));
});
}
}

partialSelection = elementSelector.selectAttr(directiveRefs, partialSelection, node, 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);
partialSelection = elementSelector.selectClass(directiveRefs,
partialSelection, node, className);
});
attrs.forEach((attrName, value) {
partialSelection = elementSelector.selectAttr(directiveRefs, partialSelection, node, 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];
var value = node.nodeValue;
for(var k = 0; k < textSelector.length; k++) {
var selectorRegExp = textSelector[k];

if (selectorRegExp.regexp.hasMatch(value)) {
directives[selectorRegExp.annotation].forEach((type) {
directiveRefs.add(new DirectiveRef(node, type, selectorRegExp.annotation, value));
directiveRefs.add(new DirectiveRef(node, type,
selectorRegExp.annotation, value));
});
}
}
Expand Down
Loading