Skip to content
Merged
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
12 changes: 6 additions & 6 deletions modules/@angular/compiler/src/selector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@
import {getHtmlTagDefinition} from './ml_parser/html_tags';

const _SELECTOR_REGEXP = new RegExp(
'(\\:not\\()|' + //":not("
'([-\\w]+)|' + // "tag"
'(?:\\.([-\\w]+))|' + // ".class"
'(?:\\[([-\\w*]+)(?:=([^\\]]*))?\\])|' + // "[name]", "[name=value]"
'(\\))|' + // ")"
'(\\s*,\\s*)', // ","
'(\\:not\\()|' + //":not("
'([-\\w]+)|' + // "tag"
'(?:\\.([-\\w]+))|' + // ".class"
'(?:\\[([.-\\w*]+)(?:=([^\\]]*))?\\])|' + // "[name]", "[name=value]"
'(\\))|' + // ")"
'(\\s*,\\s*)', // ","
'g');

/**
Expand Down
36 changes: 21 additions & 15 deletions modules/@angular/compiler/src/template_parser/template_parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ export class TemplateParser {
return new TemplateParseResult(result, errors);
}

if (isPresent(this.transforms)) {
if (this.transforms) {
this.transforms.forEach(
(transform: TemplateAstVisitor) => { result = templateVisitAll(transform, result); });
}
Expand Down Expand Up @@ -218,7 +218,7 @@ class TemplateParseVisitor implements html.Visitor {
visitText(text: html.Text, parent: ElementContext): any {
const ngContentIndex = parent.findNgContentIndex(TEXT_CSS_SELECTOR);
const expr = this._bindingParser.parseInterpolation(text.value, text.sourceSpan);
if (isPresent(expr)) {
if (expr) {
return new BoundTextAst(expr, ngContentIndex, text.sourceSpan);
} else {
return new TextAst(text.value, ngContentIndex, text.sourceSpan);
Expand Down Expand Up @@ -248,14 +248,14 @@ class TemplateParseVisitor implements html.Visitor {
return null;
}

const matchableAttrs: string[][] = [];
const matchableAttrs: [string, string][] = [];
const elementOrDirectiveProps: BoundProperty[] = [];
const elementOrDirectiveRefs: ElementOrDirectiveRef[] = [];
const elementVars: VariableAst[] = [];
const events: BoundEventAst[] = [];

const templateElementOrDirectiveProps: BoundProperty[] = [];
const templateMatchableAttrs: string[][] = [];
const templateMatchableAttrs: [string, string][] = [];
const templateElementVars: VariableAst[] = [];

let hasInlineTemplates = false;
Expand All @@ -268,14 +268,17 @@ class TemplateParseVisitor implements html.Visitor {
isTemplateElement, attr, matchableAttrs, elementOrDirectiveProps, events,
elementOrDirectiveRefs, elementVars);

let templateBindingsSource: string|undefined = undefined;
let prefixToken: string|undefined = undefined;
if (this._normalizeAttributeName(attr.name) == TEMPLATE_ATTR) {
let templateBindingsSource: string|undefined;
let prefixToken: string|undefined;
let normalizedName = this._normalizeAttributeName(attr.name);

if (normalizedName == TEMPLATE_ATTR) {
templateBindingsSource = attr.value;
} else if (attr.name.startsWith(TEMPLATE_ATTR_PREFIX)) {
} else if (normalizedName.startsWith(TEMPLATE_ATTR_PREFIX)) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a test?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

templateBindingsSource = attr.value;
prefixToken = attr.name.substring(TEMPLATE_ATTR_PREFIX.length); // remove the star
prefixToken = normalizedName.substring(TEMPLATE_ATTR_PREFIX.length);
}

const hasTemplateBinding = isPresent(templateBindingsSource);
if (hasTemplateBinding) {
if (hasInlineTemplates) {
Expand Down Expand Up @@ -541,10 +544,12 @@ class TemplateParseVisitor implements html.Visitor {
elementSourceSpan: ParseSourceSpan, targetReferences: ReferenceAst[]): DirectiveAst[] {
const matchedReferences = new Set<string>();
let component: CompileDirectiveSummary = null;

const directiveAsts = directives.map((directive) => {
const sourceSpan = new ParseSourceSpan(
elementSourceSpan.start, elementSourceSpan.end,
`Directive ${identifierName(directive.type)}`);

if (directive.isComponent) {
component = directive;
}
Expand All @@ -567,6 +572,7 @@ class TemplateParseVisitor implements html.Visitor {
return new DirectiveAst(
directive, directiveProperties, hostProperties, hostEvents, sourceSpan);
});

elementOrDirectiveRefs.forEach((elOrDirRef) => {
if (elOrDirRef.value.length > 0) {
if (!matchedReferences.has(elOrDirRef.name)) {
Expand All @@ -581,7 +587,7 @@ class TemplateParseVisitor implements html.Visitor {
}
targetReferences.push(new ReferenceAst(elOrDirRef.name, refToken, elOrDirRef.sourceSpan));
}
}); // fix syntax highlighting issue: `
});
return directiveAsts;
}

Expand Down Expand Up @@ -742,7 +748,7 @@ class NonBindableVisitor implements html.Visitor {
return null;
}

const attrNameAndValues = ast.attrs.map(attrAst => [attrAst.name, attrAst.value]);
const attrNameAndValues = ast.attrs.map((attr): [string, string] => [attr.name, attr.value]);
const selector = createElementCssSelector(ast.name, attrNameAndValues);
const ngContentIndex = parent.findNgContentIndex(selector);
const children = html.visitAll(this, ast.children, EMPTY_ELEMENT_CONTEXT);
Expand Down Expand Up @@ -811,16 +817,16 @@ class ElementContext {
}

export function createElementCssSelector(
elementName: string, matchableAttrs: string[][]): CssSelector {
elementName: string, attributes: [string, string][]): CssSelector {
const cssSelector = new CssSelector();
const elNameNoNs = splitNsName(elementName)[1];

cssSelector.setElement(elNameNoNs);

for (let i = 0; i < matchableAttrs.length; i++) {
const attrName = matchableAttrs[i][0];
for (let i = 0; i < attributes.length; i++) {
const attrName = attributes[i][0];
const attrNameNoNs = splitNsName(attrName)[1];
const attrValue = matchableAttrs[i][1];
const attrValue = attributes[i][1];

cssSelector.addAttribute(attrNameNoNs, attrValue);
if (attrName.toLowerCase() == CLASS_ATTR) {
Expand Down
51 changes: 51 additions & 0 deletions modules/@angular/compiler/test/integration_spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/

import {Component, Directive, Input} from '@angular/core';
import {ComponentFixture, TestBed, async} from '@angular/core/testing';
import {By} from '@angular/platform-browser/src/dom/debug/by';
import {expect} from '@angular/platform-browser/testing/matchers';

export function main() {
describe('integration tests', () => {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really glad to see this test. Makes it very clear. Thx.

let fixture: ComponentFixture<TestComponent>;


describe('directives', () => {
it('should support dotted selectors', async(() => {
@Directive({selector: '[dot.name]'})
class MyDir {
@Input('dot.name') value: string;
}

TestBed.configureTestingModule({
declarations: [
MyDir,
TestComponent,
],
});

const template = `<div [dot.name]="'foo'"></div>`;
fixture = createTestComponent(template);
fixture.detectChanges();
const myDir = fixture.debugElement.query(By.directive(MyDir)).injector.get(MyDir);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did not know you could do this! Cool technique.

expect(myDir.value).toEqual('foo');
}));
});

});
}

@Component({selector: 'test-cmp', template: ''})
class TestComponent {
}

function createTestComponent(template: string): ComponentFixture<TestComponent> {
return TestBed.overrideComponent(TestComponent, {set: {template: template}})
.createComponent(TestComponent);
}
Loading