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

Commit

Permalink
fix(selector): Allow two directives with the same selector
Browse files Browse the repository at this point in the history
Fixes #471
Closes #481
  • Loading branch information
jbdeboer committed Feb 5, 2014
1 parent 5bcea64 commit 467b935
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 19 deletions.
2 changes: 1 addition & 1 deletion lib/core_dom/common.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class DirectiveRef {

String toString() {
var html = element is dom.Element ? (element as dom.Element).outerHtml : element.nodeValue;
return '{ element: $html, selector: ${annotation.selector}, value: $value }';
return '{ element: $html, selector: ${annotation.selector}, value: $value, type: $type }';
}
}

38 changes: 22 additions & 16 deletions lib/core_dom/selector.dart
Original file line number Diff line number Diff line change
Expand Up @@ -78,13 +78,13 @@ class _SelectorPart {
class _ElementSelector {
String name;

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

Map<String, _Directive> classMap = new Map<String, _Directive>();
Map<String, List<_Directive>> classMap = new Map<String, List<_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, List<_Directive>>> attrValueMap = new Map<String, Map<String, List<_Directive>>>();
Map<String, Map<String, _ElementSelector>> attrValuePartialMap = new Map<String, Map<String, _ElementSelector>>();

_ElementSelector(this.name);
Expand All @@ -95,15 +95,19 @@ class _ElementSelector {
var name;
if ((name = selectorPart.element) != null) {
if (terminal) {
elementMap[name] = directive;
elementMap
.putIfAbsent(name, () => [])
.add(directive);
} else {
elementPartialMap
.putIfAbsent(name, () => new _ElementSelector(name))
.addDirective(selectorParts, directive);
}
} else if ((name = selectorPart.className) != null) {
if (terminal) {
classMap[name] = directive;
classMap
.putIfAbsent(name, () => [])
.add(directive);
} else {
classPartialMap
.putIfAbsent(name, () => new _ElementSelector(name))
Expand All @@ -112,8 +116,9 @@ class _ElementSelector {
} else if ((name = selectorPart.attrName) != null) {
if (terminal) {
attrValueMap
.putIfAbsent(name, () => new Map<String, _Directive>())
[selectorPart.attrValue] = directive;
.putIfAbsent(name, () => new Map<String, List<_Directive>>())
.putIfAbsent(selectorPart.attrValue, () => [])
.add(directive);
} else {
attrValuePartialMap
.putIfAbsent(name, () => new Map<String, _ElementSelector>())
Expand All @@ -125,11 +130,15 @@ class _ElementSelector {
}
}

_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)));
}

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));
_addRefs(refs, elementMap[nodeName], node);
}
if (elementPartialMap.containsKey(nodeName)) {
if (partialSelection == null) partialSelection = new List<_ElementSelector>();
Expand All @@ -141,8 +150,7 @@ class _ElementSelector {
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));
_addRefs(refs, classMap[className], node);
}
if (classPartialMap.containsKey(className)) {
if (partialSelection == null) partialSelection = new List<_ElementSelector>();
Expand All @@ -157,14 +165,12 @@ class _ElementSelector {
String matchingKey = _matchingKey(attrValueMap.keys, attrName);

if (matchingKey != null) {
Map<String, _Directive> valuesMap = attrValueMap[matchingKey];
Map<String, List<_Directive>> valuesMap = attrValueMap[matchingKey];
if (valuesMap.containsKey('')) {
_Directive directive = valuesMap[''];
refs.add(new DirectiveRef(node, directive.type, directive.annotation, attrValue));
_addRefs(refs, valuesMap[''], node, attrValue);
}
if (attrValue != '' && valuesMap.containsKey(attrValue)) {
_Directive directive = valuesMap[attrValue];
refs.add(new DirectiveRef(node, directive.type, directive.annotation, attrValue));
_addRefs(refs, valuesMap[attrValue], node, attrValue);
}
}
if (attrValuePartialMap.containsKey(attrName)) {
Expand Down
27 changes: 27 additions & 0 deletions test/core_dom/compiler_spec.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ main() => describe('dte.compiler', () {
..type(SimpleTranscludeInAttachAttrDirective)
..type(IncludeTranscludeAttrDirective)
..type(LocalAttrDirective)
..type(OneOfTwoDirectives)
..type(TwoOfTwoDirectives)
..type(MyController);
return (Injector _injector) {
injector = _injector;
Expand Down Expand Up @@ -125,6 +127,17 @@ main() => describe('dte.compiler', () {
expect(element.text()).toEqual('Ab');
}));

it('should compile two directives with the same selector', inject((Logger log) {
var element = $('<div two-directives></div>');
var template = $compile(element, directives);

template(injector, element);
$rootScope.$digest();

expect(log).toEqual(['OneOfTwo', 'TwoOfTwo']);
}));



describe("interpolation", () {
it('should interpolate attribute nodes', inject(() {
Expand Down Expand Up @@ -562,6 +575,20 @@ class IncludeTranscludeAttrDirective {
}
}

@NgDirective(selector: '[two-directives]')
class OneOfTwoDirectives {
OneOfTwoDirectives(Logger log) {
log('OneOfTwo');
}
}

@NgDirective(selector: '[two-directives]')
class TwoOfTwoDirectives {
TwoOfTwoDirectives(Logger log) {
log('TwoOfTwo');
}
}

class PublishTypesDirectiveSuperType {
}

Expand Down
15 changes: 14 additions & 1 deletion test/core_dom/selector_spec.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ import '../_specs.dart';
@NgDirective(selector: '[my-model][my-required]')
class _TwoDirectives {}

@NgDirective(selector: '[two-directives]') class _OneOfTwoDirectives {}
@NgDirective(selector: '[two-directives]') class _TwoOfTwoDirectives {}


main() {
describe('Selector', () {
Expand Down Expand Up @@ -55,7 +58,9 @@ main() {
..type(_Attribute)
..type(_Structural)
..type(_IgnoreChildren)
..type(_TwoDirectives);
..type(_TwoDirectives)
..type(_OneOfTwoDirectives)
..type(_TwoOfTwoDirectives);
}));
beforeEach(inject((DirectiveMap directives) {
selector = directiveSelectorFactory(directives);
Expand Down Expand Up @@ -182,6 +187,14 @@ main() {
{ "selector": '[my-model][my-required]', "value": '', "element": element}
]));
});

it('should match an two directives with the same selector', () {
expect(selector(element = e('<div two-directives></div>')),
toEqualsDirectiveInfos([
{ "selector": '[two-directives]', "value": '', "element": element},
{ "selector": '[two-directives]', "value": '', "element": element}
]));
});
});
}

Expand Down
18 changes: 17 additions & 1 deletion test/directive/ng_model_spec.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ describe('ng-model', () {

beforeEach(inject((TestBed tb) => _ = tb));

describe('type="text"', () {
describe('type="text" like', () {
it('should update input value from model', inject(() {
_.compile('<input type="text" ng-model="model">');
_.rootScope.$digest();
Expand Down Expand Up @@ -46,6 +46,22 @@ describe('ng-model', () {
expect(_.rootScope.model).toEqual('def');
}));

it('should update model from the input value for type=number', inject(() {
_.compile('<input type="number" ng-model="model" probe="p">');
Probe probe = _.rootScope.p;
var ngModel = probe.directive(NgModel);
InputElement inputElement = probe.element;

inputElement.value = '12';
_.triggerEvent(inputElement, 'change');
expect(_.rootScope.model).toEqual('12');

inputElement.value = '14';
var input = probe.directive(InputTextLikeDirective);
input.processValue();
expect(_.rootScope.model).toEqual('14');
}));

it('should write to input only if value is different', inject(() {
var scope = _.rootScope;
var element = new dom.InputElement();
Expand Down

0 comments on commit 467b935

Please sign in to comment.