Skip to content
This repository has been archived by the owner on Feb 22, 2018. It is now read-only.

Commit

Permalink
style(Selector): Move public API on top of the file
Browse files Browse the repository at this point in the history
Closes #939
  • Loading branch information
vicb authored and [email protected] committed Apr 22, 2014
1 parent 0c797cc commit c6be443
Showing 1 changed file with 145 additions and 155 deletions.
300 changes: 145 additions & 155 deletions lib/core_dom/selector.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,159 @@ part of angular.core.dom_internal;
* DirectiveSelector is used by the [Compiler] during the template walking
* to extract the [DirectiveRef]s.
*
* DirectiveSelector can be created using the [directiveSelectorFactory]
* method.
* DirectiveSelector can be created using the [DirectiveSelectorFactory].
*
* 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]
* :contains(/abc/)
* </pre>
*
*
* * element
* * .class
* * [attribute]
* * [attribute=value]
* * element[attribute1][attribute2=value]
* * :contains(/abc/)
*/
class DirectiveSelector {
ElementBinderFactory _binderFactory;
DirectiveMap _directives;
var elementSelector;
var attrSelector;
var textSelector;

DirectiveSelector(this._directives, this._binderFactory) {
elementSelector = new _ElementSelector('');
attrSelector = <_ContainsSelector>[];
textSelector = <_ContainsSelector>[];
_directives.forEach((Directive annotation, Type type) {
var match;
var selector = annotation.selector;
List<_SelectorPart> selectorParts;
if (selector == null) {
throw new ArgumentError('Missing selector annotation for $type');
}

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, type)) != null){
elementSelector.addDirective(selectorParts,
new _Directive(type, annotation));
} else {
throw new ArgumentError('Unsupported Selector: $selector');
}
});
}

ElementBinder matchElement(dom.Node node) {
assert(node is dom.Element);

ElementBinderBuilder builder = _binderFactory.builder();
List<_ElementSelector> partialSelection;
var classes = <String, bool>{};
Map<String, String> attrs = {};

dom.Element element = node;
String nodeName = element.tagName.toLowerCase();

// Set default attribute
if (nodeName == 'input' && !element.attributes.containsKey('type')) {
element.attributes['type'] = 'text';
}

// Select node
partialSelection = elementSelector.selectNode(builder,
partialSelection, element, nodeName);

// Select .name
if ((element.classes) != null) {
for (var name in element.classes) {
classes[name] = true;
partialSelection = elementSelector.selectClass(builder,
partialSelection, element, name);
}
}

// Select [attributes]
element.attributes.forEach((attrName, value) {

if (attrName.startsWith("on-")) {
builder.onEvents[attrName] = value;
} else if (attrName.startsWith("bind-")) {
builder.bindAttrs[attrName] = value;
}

attrs[attrName] = value;
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.
_directives[selectorRegExp.annotation].forEach((type) {
builder.addDirective(new DirectiveRef(
node, type, selectorRegExp.annotation, '$attrName=$value'));
});
}
}

partialSelection = elementSelector.selectAttr(builder,
partialSelection, node, attrName, value);
});

while (partialSelection != null) {
List<_ElementSelector> elementSelectors = partialSelection;
partialSelection = null;
elementSelectors.forEach((_ElementSelector elementSelector) {
classes.forEach((className, _) {
partialSelection = elementSelector.selectClass(builder,
partialSelection, node, className);
});
attrs.forEach((attrName, value) {
partialSelection = elementSelector.selectAttr(builder,
partialSelection, node, attrName, value);
});
});
}
return builder.binder;
}

ElementBinder matchText(dom.Node node) {
ElementBinderBuilder builder = _binderFactory.builder();

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) {
builder.addDirective(new DirectiveRef(node, type,
selectorRegExp.annotation, value));
});
}
}
return builder.binder;
}

ElementBinder matchComment(dom.Node node) =>
_binderFactory.builder().binder;
}

/**
* Factory for creating a [DirectiveSelector].
*/
@Injectable()
class DirectiveSelectorFactory {
ElementBinderFactory _binderFactory;

DirectiveSelectorFactory(this._binderFactory);

DirectiveSelector selector(DirectiveMap directives) =>
new DirectiveSelector(directives, _binderFactory);
}

class _Directive {
final Type type;
final Directive annotation;
Expand All @@ -36,7 +169,6 @@ class _Directive {
toString() => annotation.selector;
}


class _ContainsSelector {
final Directive annotation;
final RegExp regexp;
Expand Down Expand Up @@ -239,145 +371,3 @@ List<_SelectorPart> _splitCss(String selector, Type type) {
}
return parts;
}


class DirectiveSelector {
ElementBinderFactory _binderFactory;
DirectiveMap _directives;
var elementSelector;
var attrSelector;
var textSelector;

DirectiveSelector(this._directives, this._binderFactory) {
elementSelector = new _ElementSelector('');
attrSelector = <_ContainsSelector>[];
textSelector = <_ContainsSelector>[];
_directives.forEach((Directive annotation, Type type) {
var match;
var selector = annotation.selector;
List<_SelectorPart> selectorParts;
if (selector == null) {
throw new ArgumentError('Missing selector annotation for $type');
}

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, type)) != null){
elementSelector.addDirective(selectorParts,
new _Directive(type, annotation));
} else {
throw new ArgumentError('Unsupported Selector: $selector');
}
});
}

ElementBinder matchElement(dom.Node node) {
assert(node is dom.Element);

ElementBinderBuilder builder = _binderFactory.builder();
List<_ElementSelector> partialSelection;
var classes = <String, bool>{};
Map<String, String> attrs = {};

dom.Element element = node;
String nodeName = element.tagName.toLowerCase();

// Set default attribute
if (nodeName == 'input' && !element.attributes.containsKey('type')) {
element.attributes['type'] = 'text';
}

// Select node
partialSelection = elementSelector.selectNode(builder,
partialSelection, element, nodeName);

// Select .name
if ((element.classes) != null) {
for (var name in element.classes) {
classes[name] = true;
partialSelection = elementSelector.selectClass(builder,
partialSelection, element, name);
}
}

// Select [attributes]
element.attributes.forEach((attrName, value) {

if (attrName.startsWith("on-")) {
builder.onEvents[attrName] = value;
}

if (attrName.startsWith("bind-")) {
builder.bindAttrs[attrName] = value;
}

attrs[attrName] = value;
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.
_directives[selectorRegExp.annotation].forEach((type) {
builder.addDirective(new DirectiveRef(
node, type, selectorRegExp.annotation, '$attrName=$value'));
});
}
}

partialSelection = elementSelector.selectAttr(builder,
partialSelection, node, attrName, value);
});

while (partialSelection != null) {
List<_ElementSelector> elementSelectors = partialSelection;
partialSelection = null;
elementSelectors.forEach((_ElementSelector elementSelector) {
classes.forEach((className, _) {
partialSelection = elementSelector.selectClass(builder,
partialSelection, node, className);
});
attrs.forEach((attrName, value) {
partialSelection = elementSelector.selectAttr(builder,
partialSelection, node, attrName, value);
});
});
}
return builder.binder;
}

ElementBinder matchText(dom.Node node) {
ElementBinderBuilder builder = _binderFactory.builder();

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) {
builder.addDirective(new DirectiveRef(node, type,
selectorRegExp.annotation, value));
});
}
}
return builder.binder;
}

ElementBinder matchComment(dom.Node node) {
return _binderFactory.builder().binder;
}
}
/**
* Factory for creating a [DirectiveSelector].
*/
@Injectable()
class DirectiveSelectorFactory {
ElementBinderFactory _binderFactory;

DirectiveSelectorFactory(this._binderFactory);

DirectiveSelector selector(DirectiveMap directives) {
return new DirectiveSelector(directives, _binderFactory);
}
}

0 comments on commit c6be443

Please sign in to comment.