Compare commits
3 Commits
master
...
ivy-svg-sy
Author | SHA1 | Date | |
---|---|---|---|
![]() |
b1d8784f79 | ||
![]() |
6a4ad11e87 | ||
![]() |
a1a3af9e23 |
@ -17,10 +17,12 @@ export class Identifiers {
|
|||||||
static PATCH_DEPS = 'patchedDeps';
|
static PATCH_DEPS = 'patchedDeps';
|
||||||
|
|
||||||
/* Instructions */
|
/* Instructions */
|
||||||
static createElement: o.ExternalReference = {name: 'ɵE', moduleName: CORE};
|
static elementStart: o.ExternalReference = {name: 'ɵE', moduleName: CORE};
|
||||||
|
|
||||||
static elementEnd: o.ExternalReference = {name: 'ɵe', moduleName: CORE};
|
static elementEnd: o.ExternalReference = {name: 'ɵe', moduleName: CORE};
|
||||||
|
|
||||||
|
static element: o.ExternalReference = {name: 'ɵEe', moduleName: CORE};
|
||||||
|
|
||||||
static elementProperty: o.ExternalReference = {name: 'ɵp', moduleName: CORE};
|
static elementProperty: o.ExternalReference = {name: 'ɵp', moduleName: CORE};
|
||||||
|
|
||||||
static elementAttribute: o.ExternalReference = {name: 'ɵa', moduleName: CORE};
|
static elementAttribute: o.ExternalReference = {name: 'ɵa', moduleName: CORE};
|
||||||
|
@ -314,11 +314,20 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
|||||||
if (i18nMessages.length > 0) {
|
if (i18nMessages.length > 0) {
|
||||||
this._creationCode.push(...i18nMessages);
|
this._creationCode.push(...i18nMessages);
|
||||||
}
|
}
|
||||||
this.instruction(
|
|
||||||
this._creationCode, element.sourceSpan, R3.createElement, ...trimTrailingNulls(parameters));
|
let isSelfClosingElement = element.outputs.length === 0 && element.children.length === 0;
|
||||||
|
|
||||||
|
|
||||||
const implicit = o.variable(CONTEXT_NAME);
|
const implicit = o.variable(CONTEXT_NAME);
|
||||||
|
|
||||||
|
if (isSelfClosingElement) {
|
||||||
|
this.instruction(
|
||||||
|
this._creationCode, element.sourceSpan, R3.element, ...trimTrailingNulls(parameters));
|
||||||
|
} else {
|
||||||
|
this.instruction(
|
||||||
|
this._creationCode, element.sourceSpan, R3.elementStart,
|
||||||
|
...trimTrailingNulls(parameters));
|
||||||
|
|
||||||
// Generate Listeners (outputs)
|
// Generate Listeners (outputs)
|
||||||
element.outputs.forEach((outputAst: t.BoundEvent) => {
|
element.outputs.forEach((outputAst: t.BoundEvent) => {
|
||||||
const elName = sanitizeIdentifier(element.name);
|
const elName = sanitizeIdentifier(element.name);
|
||||||
@ -331,7 +340,8 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
|||||||
lhsVar.set(rhsExpression).toDeclStmt(o.INFERRED_TYPE, [o.StmtModifier.Final]));
|
lhsVar.set(rhsExpression).toDeclStmt(o.INFERRED_TYPE, [o.StmtModifier.Final]));
|
||||||
});
|
});
|
||||||
const bindingExpr = convertActionBinding(
|
const bindingExpr = convertActionBinding(
|
||||||
bindingScope, implicit, outputAst.handler, 'b', () => error('Unexpected interpolation'));
|
bindingScope, implicit, outputAst.handler, 'b',
|
||||||
|
() => error('Unexpected interpolation'));
|
||||||
const handler = o.fn(
|
const handler = o.fn(
|
||||||
[new o.FnParam('$event', o.DYNAMIC_TYPE)], [...localVars, ...bindingExpr.render3Stmts],
|
[new o.FnParam('$event', o.DYNAMIC_TYPE)], [...localVars, ...bindingExpr.render3Stmts],
|
||||||
o.INFERRED_TYPE, null, functionName);
|
o.INFERRED_TYPE, null, functionName);
|
||||||
@ -339,7 +349,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
|||||||
this._creationCode, outputAst.sourceSpan, R3.listener, o.literal(outputAst.name),
|
this._creationCode, outputAst.sourceSpan, R3.listener, o.literal(outputAst.name),
|
||||||
handler);
|
handler);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Generate element input bindings
|
// Generate element input bindings
|
||||||
element.inputs.forEach((input: t.BoundAttribute) => {
|
element.inputs.forEach((input: t.BoundAttribute) => {
|
||||||
@ -367,10 +377,11 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
|||||||
t.visitAll(this, element.children);
|
t.visitAll(this, element.children);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!isSelfClosingElement) {
|
||||||
// Finish element construction mode.
|
// Finish element construction mode.
|
||||||
this.instruction(
|
this.instruction(
|
||||||
this._creationCode, element.endSourceSpan || element.sourceSpan, R3.elementEnd);
|
this._creationCode, element.endSourceSpan || element.sourceSpan, R3.elementEnd);
|
||||||
|
}
|
||||||
// Restore the state before exiting this node
|
// Restore the state before exiting this node
|
||||||
this._inI18nSection = wasInI18nSection;
|
this._inI18nSection = wasInI18nSection;
|
||||||
}
|
}
|
||||||
|
@ -90,8 +90,7 @@ describe('compiler compliance', () => {
|
|||||||
const template = `
|
const template = `
|
||||||
template: function MyComponent_Template(rf: IDENT, ctx: IDENT) {
|
template: function MyComponent_Template(rf: IDENT, ctx: IDENT) {
|
||||||
if (rf & 1) {
|
if (rf & 1) {
|
||||||
$r3$.ɵE(0, 'div');
|
$r3$.ɵEe(0, 'div');
|
||||||
$r3$.ɵe();
|
|
||||||
}
|
}
|
||||||
if (rf & 2) {
|
if (rf & 2) {
|
||||||
$r3$.ɵp(0, 'id', $r3$.ɵb(ctx.id));
|
$r3$.ɵp(0, 'id', $r3$.ɵb(ctx.id));
|
||||||
@ -135,9 +134,8 @@ describe('compiler compliance', () => {
|
|||||||
const template = `
|
const template = `
|
||||||
template: function MyComponent_Template(rf: IDENT, ctx: IDENT) {
|
template: function MyComponent_Template(rf: IDENT, ctx: IDENT) {
|
||||||
if (rf & 1) {
|
if (rf & 1) {
|
||||||
$r3$.ɵE(0, 'div');
|
$r3$.ɵEe(0, 'div');
|
||||||
$r3$.ɵPp(1,'pipe');
|
$r3$.ɵPp(1,'pipe');
|
||||||
$r3$.ɵe();
|
|
||||||
$r3$.ɵrS(10);
|
$r3$.ɵrS(10);
|
||||||
}
|
}
|
||||||
if (rf & 2) {
|
if (rf & 2) {
|
||||||
@ -181,8 +179,7 @@ describe('compiler compliance', () => {
|
|||||||
const template = `
|
const template = `
|
||||||
template: function MyComponent_Template(rf: IDENT, ctx: IDENT) {
|
template: function MyComponent_Template(rf: IDENT, ctx: IDENT) {
|
||||||
if (rf & 1) {
|
if (rf & 1) {
|
||||||
$r3$.ɵE(0, 'div');
|
$r3$.ɵEe(0, 'div');
|
||||||
$r3$.ɵe();
|
|
||||||
}
|
}
|
||||||
if (rf & 2) {
|
if (rf & 2) {
|
||||||
$r3$.ɵkn(0, 'error', $r3$.ɵb(ctx.error));
|
$r3$.ɵkn(0, 'error', $r3$.ɵb(ctx.error));
|
||||||
@ -254,8 +251,7 @@ describe('compiler compliance', () => {
|
|||||||
factory: function MyComponent_Factory() { return new MyComponent(); },
|
factory: function MyComponent_Factory() { return new MyComponent(); },
|
||||||
template: function MyComponent_Template(rf: IDENT, ctx: IDENT) {
|
template: function MyComponent_Template(rf: IDENT, ctx: IDENT) {
|
||||||
if (rf & 1) {
|
if (rf & 1) {
|
||||||
$r3$.ɵE(0, 'child', $c1$);
|
$r3$.ɵEe(0, 'child', $c1$);
|
||||||
$r3$.ɵe();
|
|
||||||
$r3$.ɵT(1, '!');
|
$r3$.ɵT(1, '!');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -461,8 +457,7 @@ describe('compiler compliance', () => {
|
|||||||
factory: function MyApp_Factory() { return new MyApp(); },
|
factory: function MyApp_Factory() { return new MyApp(); },
|
||||||
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
|
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
|
||||||
if (rf & 1) {
|
if (rf & 1) {
|
||||||
$r3$.ɵE(0, 'my-comp');
|
$r3$.ɵEe(0, 'my-comp');
|
||||||
$r3$.ɵe();
|
|
||||||
$r3$.ɵrS(2);
|
$r3$.ɵrS(2);
|
||||||
}
|
}
|
||||||
if (rf & 2) {
|
if (rf & 2) {
|
||||||
@ -541,8 +536,7 @@ describe('compiler compliance', () => {
|
|||||||
factory: function MyApp_Factory() { return new MyApp(); },
|
factory: function MyApp_Factory() { return new MyApp(); },
|
||||||
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
|
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
|
||||||
if (rf & 1) {
|
if (rf & 1) {
|
||||||
$r3$.ɵE(0, 'my-comp');
|
$r3$.ɵEe(0, 'my-comp');
|
||||||
$r3$.ɵe();
|
|
||||||
$r3$.ɵrS(10);
|
$r3$.ɵrS(10);
|
||||||
}
|
}
|
||||||
if (rf & 2) {
|
if (rf & 2) {
|
||||||
@ -603,8 +597,7 @@ describe('compiler compliance', () => {
|
|||||||
factory: function MyApp_Factory() { return new MyApp(); },
|
factory: function MyApp_Factory() { return new MyApp(); },
|
||||||
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
|
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
|
||||||
if (rf & 1) {
|
if (rf & 1) {
|
||||||
$r3$.ɵE(0, 'object-comp');
|
$r3$.ɵEe(0, 'object-comp');
|
||||||
$r3$.ɵe();
|
|
||||||
$r3$.ɵrS(2);
|
$r3$.ɵrS(2);
|
||||||
}
|
}
|
||||||
if (rf & 2) {
|
if (rf & 2) {
|
||||||
@ -669,8 +662,7 @@ describe('compiler compliance', () => {
|
|||||||
factory: function MyApp_Factory() { return new MyApp(); },
|
factory: function MyApp_Factory() { return new MyApp(); },
|
||||||
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
|
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
|
||||||
if (rf & 1) {
|
if (rf & 1) {
|
||||||
$r3$.ɵE(0, 'nested-comp');
|
$r3$.ɵEe(0, 'nested-comp');
|
||||||
$r3$.ɵe();
|
|
||||||
$r3$.ɵrS(7);
|
$r3$.ɵrS(7);
|
||||||
}
|
}
|
||||||
if (rf & 2) {
|
if (rf & 2) {
|
||||||
@ -814,8 +806,7 @@ describe('compiler compliance', () => {
|
|||||||
var $tmp$: $any$;
|
var $tmp$: $any$;
|
||||||
if (rf & 1) {
|
if (rf & 1) {
|
||||||
$r3$.ɵQ(0, SomeDirective, true);
|
$r3$.ɵQ(0, SomeDirective, true);
|
||||||
$r3$.ɵE(1, 'div', $e0_attrs$);
|
$r3$.ɵEe(1, 'div', $e0_attrs$);
|
||||||
$r3$.ɵe();
|
|
||||||
}
|
}
|
||||||
if (rf & 2) {
|
if (rf & 2) {
|
||||||
($r3$.ɵqR(($tmp$ = $r3$.ɵld(0))) && (ctx.someDir = $tmp$.first));
|
($r3$.ɵqR(($tmp$ = $r3$.ɵld(0))) && (ctx.someDir = $tmp$.first));
|
||||||
@ -1009,8 +1000,7 @@ describe('compiler compliance', () => {
|
|||||||
factory: function MyComponent_Factory() { return new MyComponent(); },
|
factory: function MyComponent_Factory() { return new MyComponent(); },
|
||||||
template: function MyComponent_Template(rf: IDENT, ctx: IDENT) {
|
template: function MyComponent_Template(rf: IDENT, ctx: IDENT) {
|
||||||
if (rf & 1) {
|
if (rf & 1) {
|
||||||
$r3$.ɵE(0, 'input', null, $c1$);
|
$r3$.ɵEe(0, 'input', null, $c1$);
|
||||||
$r3$.ɵe();
|
|
||||||
$r3$.ɵT(2);
|
$r3$.ɵT(2);
|
||||||
}
|
}
|
||||||
const $user$ = $r3$.ɵld(1);
|
const $user$ = $r3$.ɵld(1);
|
||||||
@ -1089,10 +1079,8 @@ describe('compiler compliance', () => {
|
|||||||
factory: function SimpleLayout_Factory() { return new SimpleLayout(); },
|
factory: function SimpleLayout_Factory() { return new SimpleLayout(); },
|
||||||
template: function SimpleLayout_Template(rf: IDENT, ctx: IDENT) {
|
template: function SimpleLayout_Template(rf: IDENT, ctx: IDENT) {
|
||||||
if (rf & 1) {
|
if (rf & 1) {
|
||||||
$r3$.ɵE(0, 'lifecycle-comp');
|
$r3$.ɵEe(0, 'lifecycle-comp');
|
||||||
$r3$.ɵe();
|
$r3$.ɵEe(1, 'lifecycle-comp');
|
||||||
$r3$.ɵE(1, 'lifecycle-comp');
|
|
||||||
$r3$.ɵe();
|
|
||||||
}
|
}
|
||||||
if (rf & 2) {
|
if (rf & 2) {
|
||||||
$r3$.ɵp(0, 'name', $r3$.ɵb(ctx.name1));
|
$r3$.ɵp(0, 'name', $r3$.ɵb(ctx.name1));
|
||||||
|
@ -75,8 +75,7 @@ describe('compiler compliance: bindings', () => {
|
|||||||
const template = `
|
const template = `
|
||||||
template:function MyComponent_Template(rf: IDENT, $ctx$: IDENT){
|
template:function MyComponent_Template(rf: IDENT, $ctx$: IDENT){
|
||||||
if (rf & 1) {
|
if (rf & 1) {
|
||||||
$i0$.ɵE(0, 'a');
|
$i0$.ɵEe(0, 'a');
|
||||||
$i0$.ɵe();
|
|
||||||
}
|
}
|
||||||
if (rf & 2) {
|
if (rf & 2) {
|
||||||
$i0$.ɵp(0, 'title', $i0$.ɵb($ctx$.title));
|
$i0$.ɵp(0, 'title', $i0$.ɵb($ctx$.title));
|
||||||
@ -108,8 +107,7 @@ describe('compiler compliance: bindings', () => {
|
|||||||
const template = `
|
const template = `
|
||||||
template:function MyComponent_Template(rf: IDENT, $ctx$: IDENT){
|
template:function MyComponent_Template(rf: IDENT, $ctx$: IDENT){
|
||||||
if (rf & 1) {
|
if (rf & 1) {
|
||||||
$i0$.ɵE(0, 'a');
|
$i0$.ɵEe(0, 'a');
|
||||||
$i0$.ɵe();
|
|
||||||
}
|
}
|
||||||
if (rf & 2) {
|
if (rf & 2) {
|
||||||
$i0$.ɵp(0, 'title', $i0$.ɵi1('Hello ', $ctx$.name, ''));
|
$i0$.ɵp(0, 'title', $i0$.ɵi1('Hello ', $ctx$.name, ''));
|
||||||
|
@ -148,8 +148,7 @@ describe('i18n support in the view compiler', () => {
|
|||||||
…
|
…
|
||||||
template: function MyComponent_Template(rf: IDENT, ctx: IDENT) {
|
template: function MyComponent_Template(rf: IDENT, ctx: IDENT) {
|
||||||
if (rf & 1) {
|
if (rf & 1) {
|
||||||
$r3$.ɵE(0, 'div', $c1$);
|
$r3$.ɵEe(0, 'div', $c1$);
|
||||||
$r3$.ɵe();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
@ -109,4 +109,43 @@ describe('compiler compliance: template', () => {
|
|||||||
expectEmit(result.source, template, 'Incorrect template');
|
expectEmit(result.source, template, 'Incorrect template');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// tslint:disable-next-line:ban
|
||||||
|
describe('element with no children', () => {
|
||||||
|
it('should just use the element instruction', () => {
|
||||||
|
const files = {
|
||||||
|
app: {
|
||||||
|
'spec.ts': `
|
||||||
|
import {Component, NgModule} from '@angular/core';
|
||||||
|
import {CommonModule} from '@angular/common';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'my-component',
|
||||||
|
template: \`
|
||||||
|
<div></div>\`
|
||||||
|
})
|
||||||
|
export class MyComponent {
|
||||||
|
}
|
||||||
|
|
||||||
|
@NgModule({declarations: [MyComponent], imports: [CommonModule]})
|
||||||
|
export class MyModule {}
|
||||||
|
`
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const template = `
|
||||||
|
// ...
|
||||||
|
template:function MyComponent_Template(rf: IDENT, $ctx$: IDENT){
|
||||||
|
if (rf & 1) {
|
||||||
|
$i0$.ɵEe(0,'div');
|
||||||
|
}
|
||||||
|
}`;
|
||||||
|
|
||||||
|
debugger;
|
||||||
|
|
||||||
|
const result = compile(files, angularFiles);
|
||||||
|
|
||||||
|
expectEmit(result.source, template, 'Incorrect template');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -28,6 +28,7 @@ export {
|
|||||||
NC as ɵNC,
|
NC as ɵNC,
|
||||||
C as ɵC,
|
C as ɵC,
|
||||||
E as ɵE,
|
E as ɵE,
|
||||||
|
Ee as ɵEe,
|
||||||
L as ɵL,
|
L as ɵL,
|
||||||
T as ɵT,
|
T as ɵT,
|
||||||
V as ɵV,
|
V as ɵV,
|
||||||
|
@ -260,8 +260,11 @@ export function injectAttribute(attrNameToInject: string): string|undefined {
|
|||||||
const attrs = tElement.attrs;
|
const attrs = tElement.attrs;
|
||||||
if (attrs) {
|
if (attrs) {
|
||||||
for (let i = 0; i < attrs.length; i = i + 2) {
|
for (let i = 0; i < attrs.length; i = i + 2) {
|
||||||
const attrName = attrs[i];
|
let attrName = attrs[i];
|
||||||
if (attrName === AttributeMarker.SELECT_ONLY) break;
|
if (attrName === AttributeMarker.SELECT_ONLY) break;
|
||||||
|
if (attrName === 0) { // NS.FULL
|
||||||
|
attrName = attrs[i += 2];
|
||||||
|
}
|
||||||
if (attrName == attrNameToInject) {
|
if (attrName == attrNameToInject) {
|
||||||
return attrs[i + 1] as string;
|
return attrs[i + 1] as string;
|
||||||
}
|
}
|
||||||
|
@ -50,6 +50,7 @@ export {
|
|||||||
elementEnd as e,
|
elementEnd as e,
|
||||||
elementProperty as p,
|
elementProperty as p,
|
||||||
elementStart as E,
|
elementStart as E,
|
||||||
|
element as Ee,
|
||||||
elementStyle as s,
|
elementStyle as s,
|
||||||
elementStyleNamed as sn,
|
elementStyleNamed as sn,
|
||||||
|
|
||||||
|
@ -8,24 +8,27 @@
|
|||||||
|
|
||||||
import './ng_dev_mode';
|
import './ng_dev_mode';
|
||||||
|
|
||||||
|
import {Sanitizer} from '../sanitization/security';
|
||||||
|
|
||||||
import {assertEqual, assertLessThan, assertNotEqual, assertNotNull, assertNull, assertSame} from './assert';
|
import {assertEqual, assertLessThan, assertNotEqual, assertNotNull, assertNull, assertSame} from './assert';
|
||||||
|
import {throwCyclicDependencyError, throwErrorIfNoChangesMode, throwMultipleComponentError} from './errors';
|
||||||
|
import {executeHooks, executeInitHooks, queueInitHooks, queueLifecycleHooks} from './hooks';
|
||||||
import {LContainer} from './interfaces/container';
|
import {LContainer} from './interfaces/container';
|
||||||
|
import {ComponentDef, ComponentTemplate, DirectiveDef, DirectiveDefList, DirectiveDefListOrFactory, PipeDefList, PipeDefListOrFactory, RenderFlags} from './interfaces/definition';
|
||||||
import {LInjector} from './interfaces/injector';
|
import {LInjector} from './interfaces/injector';
|
||||||
import {CssSelectorList, LProjection, NG_PROJECT_AS_ATTR_NAME} from './interfaces/projection';
|
import {CssSelectorList, LProjection, NG_PROJECT_AS_ATTR_NAME} from './interfaces/projection';
|
||||||
import {LQueries} from './interfaces/query';
|
import {LQueries} from './interfaces/query';
|
||||||
|
import {ObjectOrientedRenderer3, ProceduralRenderer3, RElement, RText, Renderer3, RendererFactory3, RendererStyleFlags3, isProceduralRenderer} from './interfaces/renderer';
|
||||||
import {CurrentMatchesList, LView, LViewFlags, LifecycleStage, RootContext, TData, TView} from './interfaces/view';
|
import {CurrentMatchesList, LView, LViewFlags, LifecycleStage, RootContext, TData, TView} from './interfaces/view';
|
||||||
|
|
||||||
import {AttributeMarker, TAttributes, LContainerNode, LElementNode, LNode, TNodeType, TNodeFlags, LProjectionNode, LTextNode, LViewNode, TNode, TContainerNode, InitialInputData, InitialInputs, PropertyAliases, PropertyAliasValue, TElementNode,} from './interfaces/node';
|
import {AttributeMarker, TAttributes, LContainerNode, LElementNode, LNode, TNodeType, TNodeFlags, LProjectionNode, LTextNode, LViewNode, TNode, TContainerNode, InitialInputData, InitialInputs, PropertyAliases, PropertyAliasValue, TElementNode,} from './interfaces/node';
|
||||||
import {assertNodeType} from './node_assert';
|
import {assertNodeType} from './node_assert';
|
||||||
import {appendChild, insertView, appendProjectedNode, removeView, canInsertNativeNode, createTextNode, getNextLNode, getChildLNode, getParentLNode} from './node_manipulation';
|
import {appendChild, insertView, appendProjectedNode, removeView, canInsertNativeNode, createTextNode, getNextLNode, getChildLNode, getParentLNode} from './node_manipulation';
|
||||||
import {isNodeMatchingSelectorList, matchingSelectorIndex} from './node_selector_matcher';
|
import {isNodeMatchingSelectorList, matchingSelectorIndex} from './node_selector_matcher';
|
||||||
import {ComponentDef, ComponentTemplate, DirectiveDef, DirectiveDefList, DirectiveDefListOrFactory, PipeDefList, PipeDefListOrFactory, RenderFlags} from './interfaces/definition';
|
|
||||||
import {RElement, RText, Renderer3, RendererFactory3, ProceduralRenderer3, RendererStyleFlags3, isProceduralRenderer} from './interfaces/renderer';
|
|
||||||
import {isDifferent, stringify} from './util';
|
import {isDifferent, stringify} from './util';
|
||||||
import {executeHooks, queueLifecycleHooks, queueInitHooks, executeInitHooks} from './hooks';
|
|
||||||
import {ViewRef} from './view_ref';
|
import {ViewRef} from './view_ref';
|
||||||
import {throwCyclicDependencyError, throwErrorIfNoChangesMode, throwMultipleComponentError} from './errors';
|
|
||||||
import {Sanitizer} from '../sanitization/security';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Directive (D) sets a property on all component instances using this constant as a key and the
|
* Directive (D) sets a property on all component instances using this constant as a key and the
|
||||||
@ -571,6 +574,28 @@ function getRenderFlags(view: LView): RenderFlags {
|
|||||||
RenderFlags.Update;
|
RenderFlags.Update;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//////////////////////////
|
||||||
|
//// Namespace
|
||||||
|
//////////////////////////
|
||||||
|
let _currentNS: string|null = null;
|
||||||
|
|
||||||
|
export function setNS(namespace: string) {
|
||||||
|
_currentNS = namespace;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setHtmlNS() {
|
||||||
|
_currentNS = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setSvgNS() {
|
||||||
|
_currentNS = 'http://www.w3.org/2000/svg';
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setMathML() {
|
||||||
|
_currentNS = 'http://www.w3.org/1998/Math/MathML';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////
|
//////////////////////////
|
||||||
//// Element
|
//// Element
|
||||||
//////////////////////////
|
//////////////////////////
|
||||||
@ -595,7 +620,11 @@ export function elementStart(
|
|||||||
currentView.bindingStartIndex, -1, 'elements should be created before any bindings');
|
currentView.bindingStartIndex, -1, 'elements should be created before any bindings');
|
||||||
|
|
||||||
ngDevMode && ngDevMode.rendererCreateElement++;
|
ngDevMode && ngDevMode.rendererCreateElement++;
|
||||||
const native: RElement = renderer.createElement(name);
|
|
||||||
|
const native: RElement = _currentNS === null || isProceduralRenderer(renderer) ?
|
||||||
|
renderer.createElement(name) :
|
||||||
|
(renderer as ObjectOrientedRenderer3).createElementNS(_currentNS, name);
|
||||||
|
|
||||||
ngDevMode && assertDataInRange(index - 1);
|
ngDevMode && assertDataInRange(index - 1);
|
||||||
|
|
||||||
const node: LElementNode =
|
const node: LElementNode =
|
||||||
@ -823,7 +852,19 @@ export function createTView(
|
|||||||
function setUpAttributes(native: RElement, attrs: TAttributes): void {
|
function setUpAttributes(native: RElement, attrs: TAttributes): void {
|
||||||
const isProc = isProceduralRenderer(renderer);
|
const isProc = isProceduralRenderer(renderer);
|
||||||
for (let i = 0; i < attrs.length; i += 2) {
|
for (let i = 0; i < attrs.length; i += 2) {
|
||||||
const attrName = attrs[i];
|
let attrName = attrs[i];
|
||||||
|
if (attrName === 0) { // NS.FULL
|
||||||
|
// Namespaced attribute
|
||||||
|
const attrNS = attrs[i + 1] as string;
|
||||||
|
attrName = attrs[i + 2] as string;
|
||||||
|
const attrVal = attrs[i + 3] as string;
|
||||||
|
i += 2;
|
||||||
|
if (isProc) {
|
||||||
|
(renderer as ProceduralRenderer3).setAttribute(native, attrName, attrVal, attrNS);
|
||||||
|
} else {
|
||||||
|
native.setAttributeNS(attrNS, attrName, attrVal);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
if (attrName === AttributeMarker.SELECT_ONLY) break;
|
if (attrName === AttributeMarker.SELECT_ONLY) break;
|
||||||
if (attrName !== NG_PROJECT_AS_ATTR_NAME) {
|
if (attrName !== NG_PROJECT_AS_ATTR_NAME) {
|
||||||
const attrVal = attrs[i + 1];
|
const attrVal = attrs[i + 1];
|
||||||
@ -834,6 +875,7 @@ function setUpAttributes(native: RElement, attrs: TAttributes): void {
|
|||||||
native.setAttribute(attrName as string, attrVal as string);
|
native.setAttribute(attrName as string, attrVal as string);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createError(text: string, token: any) {
|
export function createError(text: string, token: any) {
|
||||||
@ -964,6 +1006,15 @@ export function elementEnd() {
|
|||||||
queueLifecycleHooks(previousOrParentNode.tNode.flags, currentView);
|
queueLifecycleHooks(previousOrParentNode.tNode.flags, currentView);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Marks the beginning and end of an element in one call. */
|
||||||
|
export function element(
|
||||||
|
index: number, name: string, attrs?: TAttributes | null | undefined,
|
||||||
|
localRefs?: string[] | null | undefined): RElement {
|
||||||
|
const relement = elementStart(index, name, attrs, localRefs);
|
||||||
|
elementEnd();
|
||||||
|
return relement;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the value of removes an attribute on an Element.
|
* Updates the value of removes an attribute on an Element.
|
||||||
*
|
*
|
||||||
@ -1440,7 +1491,8 @@ function generateInitialInputs(
|
|||||||
|
|
||||||
const attrs = tNode.attrs !;
|
const attrs = tNode.attrs !;
|
||||||
for (let i = 0; i < attrs.length; i += 2) {
|
for (let i = 0; i < attrs.length; i += 2) {
|
||||||
const attrName = attrs[i];
|
const first = attrs[i];
|
||||||
|
const attrName = first === 0 ? attrs[i += 2] : first; // 0 = NS.FULL
|
||||||
const minifiedInputName = inputs[attrName];
|
const minifiedInputName = inputs[attrName];
|
||||||
const attrValue = attrs[i + 1];
|
const attrValue = attrs[i + 1];
|
||||||
|
|
||||||
@ -1852,7 +1904,7 @@ function appendToProjectionNode(
|
|||||||
* - 1 based index of the selector from the {@link projectionDef}
|
* - 1 based index of the selector from the {@link projectionDef}
|
||||||
*/
|
*/
|
||||||
export function projection(
|
export function projection(
|
||||||
nodeIndex: number, localIndex: number, selectorIndex: number = 0, attrs?: string[]): void {
|
nodeIndex: number, localIndex: number, selectorIndex: number = 0, attrs?: TAttributes): void {
|
||||||
const node = createLNode(
|
const node = createLNode(
|
||||||
nodeIndex, TNodeType.Projection, null, null, attrs || null, {head: null, tail: null});
|
nodeIndex, TNodeType.Projection, null, null, attrs || null, {head: null, tail: null});
|
||||||
|
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
* Use of this source code is governed by an MIT-style license that can be
|
* 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
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {LContainer} from './container';
|
import {LContainer} from './container';
|
||||||
import {LInjector} from './injector';
|
import {LInjector} from './injector';
|
||||||
import {LProjection} from './projection';
|
import {LProjection} from './projection';
|
||||||
@ -14,6 +13,16 @@ import {RElement, RNode, RText} from './renderer';
|
|||||||
import {LView, TData, TView} from './view';
|
import {LView, TData, TView} from './view';
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Namespace attribute flags.
|
||||||
|
*/
|
||||||
|
export const enum NS {
|
||||||
|
/**
|
||||||
|
* Use the next value as the full namespaces URI, the values after that
|
||||||
|
* are then the name and the value, respectively.
|
||||||
|
*/
|
||||||
|
FULL = 0,
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TNodeType corresponds to the TNode.type property. It contains information
|
* TNodeType corresponds to the TNode.type property. It contains information
|
||||||
@ -179,7 +188,7 @@ export const enum AttributeMarker {
|
|||||||
* - attribute names and values
|
* - attribute names and values
|
||||||
* - special markers acting as flags to alter attributes processing.
|
* - special markers acting as flags to alter attributes processing.
|
||||||
*/
|
*/
|
||||||
export type TAttributes = (string | AttributeMarker)[];
|
export type TAttributes = (string | AttributeMarker | NS)[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* LNode binding data (flyweight) for a particular node that is shared between all templates
|
* LNode binding data (flyweight) for a particular node that is shared between all templates
|
||||||
|
@ -36,6 +36,7 @@ export type Renderer3 = ObjectOrientedRenderer3 | ProceduralRenderer3;
|
|||||||
* */
|
* */
|
||||||
export interface ObjectOrientedRenderer3 {
|
export interface ObjectOrientedRenderer3 {
|
||||||
createElement(tagName: string): RElement;
|
createElement(tagName: string): RElement;
|
||||||
|
createElementNS(namespace: string, name: string): RElement;
|
||||||
createTextNode(data: string): RText;
|
createTextNode(data: string): RText;
|
||||||
|
|
||||||
querySelector(selectors: string): RElement|null;
|
querySelector(selectors: string): RElement|null;
|
||||||
|
@ -12,6 +12,7 @@ import {assertNotNull} from './assert';
|
|||||||
import {AttributeMarker, TAttributes, TNode, unusedValueExportToPlacateAjd as unused1} from './interfaces/node';
|
import {AttributeMarker, TAttributes, TNode, unusedValueExportToPlacateAjd as unused1} from './interfaces/node';
|
||||||
import {CssSelector, CssSelectorList, NG_PROJECT_AS_ATTR_NAME, SelectorFlags, unusedValueExportToPlacateAjd as unused2} from './interfaces/projection';
|
import {CssSelector, CssSelectorList, NG_PROJECT_AS_ATTR_NAME, SelectorFlags, unusedValueExportToPlacateAjd as unused2} from './interfaces/projection';
|
||||||
|
|
||||||
|
|
||||||
const unusedValueToPlacateAjd = unused1 + unused2;
|
const unusedValueToPlacateAjd = unused1 + unused2;
|
||||||
|
|
||||||
function isCssClassMatching(nodeClassAttrVal: string, cssClassToMatch: string): boolean {
|
function isCssClassMatching(nodeClassAttrVal: string, cssClassToMatch: string): boolean {
|
||||||
@ -106,8 +107,12 @@ function findAttrIndexInNode(name: string, attrs: TAttributes | null): number {
|
|||||||
if (attrs === null) return -1;
|
if (attrs === null) return -1;
|
||||||
for (let i = 0; i < attrs.length; i += step) {
|
for (let i = 0; i < attrs.length; i += step) {
|
||||||
const attrName = attrs[i];
|
const attrName = attrs[i];
|
||||||
if (attrName === name) return i;
|
if (attrName === 0) {
|
||||||
if (attrName === AttributeMarker.SELECT_ONLY) {
|
// NS.FULL
|
||||||
|
step = 2;
|
||||||
|
} else if (attrName === name) {
|
||||||
|
return i;
|
||||||
|
} else if (attrName === AttributeMarker.SELECT_ONLY) {
|
||||||
step = 1;
|
step = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -185,6 +185,9 @@
|
|||||||
{
|
{
|
||||||
"name": "_currentInjector"
|
"name": "_currentInjector"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "_currentNS"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "_devMode"
|
"name": "_devMode"
|
||||||
},
|
},
|
||||||
|
@ -1820,7 +1820,7 @@ function declareTests({useJit}: {useJit: boolean}) {
|
|||||||
.toEqual('http://www.w3.org/2000/svg');
|
.toEqual('http://www.w3.org/2000/svg');
|
||||||
|
|
||||||
const firstAttribute = getDOM().getProperty(<Element>use, 'attributes')[0];
|
const firstAttribute = getDOM().getProperty(<Element>use, 'attributes')[0];
|
||||||
expect(firstAttribute.name).toEqual('xlink:href');
|
expect(firstAttribute.name).toEqual('href');
|
||||||
expect(firstAttribute.namespaceURI).toEqual('http://www.w3.org/1999/xlink');
|
expect(firstAttribute.namespaceURI).toEqual('http://www.w3.org/1999/xlink');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -69,8 +69,7 @@ describe('components & directives', () => {
|
|||||||
factory: () => new MyComponent(),
|
factory: () => new MyComponent(),
|
||||||
template: function(rf: $RenderFlags$, ctx: $MyComponent$) {
|
template: function(rf: $RenderFlags$, ctx: $MyComponent$) {
|
||||||
if (rf & 1) {
|
if (rf & 1) {
|
||||||
$r3$.ɵE(0, 'child', $e0_attrs$);
|
$r3$.ɵEe(0, 'child', $e0_attrs$);
|
||||||
$r3$.ɵe();
|
|
||||||
$r3$.ɵT(1, '!');
|
$r3$.ɵT(1, '!');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -455,8 +454,7 @@ describe('components & directives', () => {
|
|||||||
factory: function MyApp_Factory() { return new MyApp(); },
|
factory: function MyApp_Factory() { return new MyApp(); },
|
||||||
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
|
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
|
||||||
if (rf & 1) {
|
if (rf & 1) {
|
||||||
$r3$.ɵE(0, 'my-array-comp');
|
$r3$.ɵEe(0, 'my-array-comp');
|
||||||
$r3$.ɵe();
|
|
||||||
}
|
}
|
||||||
if (rf & 2) {
|
if (rf & 2) {
|
||||||
$r3$.ɵp(0, 'names', rf & 1 ? $e0_arr$ : $r3$.ɵNC);
|
$r3$.ɵp(0, 'names', rf & 1 ? $e0_arr$ : $r3$.ɵNC);
|
||||||
@ -500,8 +498,7 @@ describe('components & directives', () => {
|
|||||||
factory: function MyApp_Factory() { return new MyApp(); },
|
factory: function MyApp_Factory() { return new MyApp(); },
|
||||||
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
|
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
|
||||||
if (rf & 1) {
|
if (rf & 1) {
|
||||||
$r3$.ɵE(0, 'my-array-comp');
|
$r3$.ɵEe(0, 'my-array-comp');
|
||||||
$r3$.ɵe();
|
|
||||||
$r3$.ɵrS(1);
|
$r3$.ɵrS(1);
|
||||||
}
|
}
|
||||||
if (rf & 2) {
|
if (rf & 2) {
|
||||||
@ -606,8 +603,7 @@ describe('components & directives', () => {
|
|||||||
factory: function MyApp_Factory() { return new MyApp(); },
|
factory: function MyApp_Factory() { return new MyApp(); },
|
||||||
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
|
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
|
||||||
if (rf & 1) {
|
if (rf & 1) {
|
||||||
$r3$.ɵE(0, 'my-array-comp');
|
$r3$.ɵEe(0, 'my-array-comp');
|
||||||
$r3$.ɵe();
|
|
||||||
$r3$.ɵrS(2);
|
$r3$.ɵrS(2);
|
||||||
}
|
}
|
||||||
if (rf & 2) {
|
if (rf & 2) {
|
||||||
@ -717,8 +713,7 @@ describe('components & directives', () => {
|
|||||||
factory: function MyApp_Factory() { return new MyApp(); },
|
factory: function MyApp_Factory() { return new MyApp(); },
|
||||||
template: function MyApp_Template(rf: $RenderFlags$, c: $any$) {
|
template: function MyApp_Template(rf: $RenderFlags$, c: $any$) {
|
||||||
if (rf & 1) {
|
if (rf & 1) {
|
||||||
$r3$.ɵE(0, 'my-comp');
|
$r3$.ɵEe(0, 'my-comp');
|
||||||
$r3$.ɵe();
|
|
||||||
$r3$.ɵrS(10);
|
$r3$.ɵrS(10);
|
||||||
}
|
}
|
||||||
if (rf & 2) {
|
if (rf & 2) {
|
||||||
|
@ -58,8 +58,7 @@ describe('queries', () => {
|
|||||||
if (rf & 1) {
|
if (rf & 1) {
|
||||||
$r3$.ɵQ(0, SomeDirective, false);
|
$r3$.ɵQ(0, SomeDirective, false);
|
||||||
$r3$.ɵQ(1, SomeDirective, false);
|
$r3$.ɵQ(1, SomeDirective, false);
|
||||||
$r3$.ɵE(2, 'div', $e1_attrs$);
|
$r3$.ɵEe(2, 'div', $e1_attrs$);
|
||||||
$r3$.ɵe();
|
|
||||||
}
|
}
|
||||||
if (rf & 2) {
|
if (rf & 2) {
|
||||||
$r3$.ɵqR($tmp$ = $r3$.ɵld<QueryList<any>>(0)) && (ctx.someDir = $tmp$.first);
|
$r3$.ɵqR($tmp$ = $r3$.ɵld<QueryList<any>>(0)) && (ctx.someDir = $tmp$.first);
|
||||||
|
@ -10,14 +10,14 @@ import {NgForOfContext} from '@angular/common';
|
|||||||
|
|
||||||
import {RenderFlags, directiveInject} from '../../src/render3';
|
import {RenderFlags, directiveInject} from '../../src/render3';
|
||||||
import {defineComponent} from '../../src/render3/definition';
|
import {defineComponent} from '../../src/render3/definition';
|
||||||
import {bind, container, elementAttribute, elementClass, elementEnd, elementProperty, elementStart, elementStyle, elementStyleNamed, interpolation1, renderTemplate, text, textBinding} from '../../src/render3/instructions';
|
import {bind, container, element, elementAttribute, elementClass, elementEnd, elementProperty, elementStart, elementStyle, elementStyleNamed, interpolation1, renderTemplate, setHtmlNS, setSvgNS, text, textBinding} from '../../src/render3/instructions';
|
||||||
import {LElementNode, LNode} from '../../src/render3/interfaces/node';
|
import {LElementNode, LNode, NS} from '../../src/render3/interfaces/node';
|
||||||
import {RElement, domRendererFactory3} from '../../src/render3/interfaces/renderer';
|
import {RElement, domRendererFactory3} from '../../src/render3/interfaces/renderer';
|
||||||
import {TrustedString, bypassSanitizationTrustHtml, bypassSanitizationTrustResourceUrl, bypassSanitizationTrustScript, bypassSanitizationTrustStyle, bypassSanitizationTrustUrl, sanitizeHtml, sanitizeResourceUrl, sanitizeScript, sanitizeStyle, sanitizeUrl} from '../../src/sanitization/sanitization';
|
import {TrustedString, bypassSanitizationTrustHtml, bypassSanitizationTrustResourceUrl, bypassSanitizationTrustScript, bypassSanitizationTrustStyle, bypassSanitizationTrustUrl, sanitizeHtml, sanitizeResourceUrl, sanitizeScript, sanitizeStyle, sanitizeUrl} from '../../src/sanitization/sanitization';
|
||||||
import {Sanitizer, SecurityContext} from '../../src/sanitization/security';
|
import {Sanitizer, SecurityContext} from '../../src/sanitization/security';
|
||||||
|
|
||||||
import {NgForOf} from './common_with_def';
|
import {NgForOf} from './common_with_def';
|
||||||
import {ComponentFixture, TemplateFixture} from './render_util';
|
import {ComponentFixture, TemplateFixture, toHtml} from './render_util';
|
||||||
|
|
||||||
describe('instructions', () => {
|
describe('instructions', () => {
|
||||||
function createAnchor() {
|
function createAnchor() {
|
||||||
@ -54,6 +54,42 @@ describe('instructions', () => {
|
|||||||
rendererSetAttribute: 2
|
rendererSetAttribute: 2
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should use sanitizer function even on elements with namespaced attributes', () => {
|
||||||
|
const t = new TemplateFixture(() => {
|
||||||
|
element(0, 'div', [
|
||||||
|
NS.FULL,
|
||||||
|
'http://www.example.com/2004/test',
|
||||||
|
'whatever',
|
||||||
|
'abc',
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
t.update(() => elementAttribute(0, 'title', 'javascript:true', sanitizeUrl));
|
||||||
|
|
||||||
|
|
||||||
|
let standardHTML = '<div whatever="abc" title="unsafe:javascript:true"></div>';
|
||||||
|
let ieHTML = '<div title="unsafe:javascript:true" whatever="abc"></div>';
|
||||||
|
|
||||||
|
expect([standardHTML, ieHTML]).toContain(t.html);
|
||||||
|
|
||||||
|
t.update(
|
||||||
|
() => elementAttribute(
|
||||||
|
0, 'title', bypassSanitizationTrustUrl('javascript:true'), sanitizeUrl));
|
||||||
|
|
||||||
|
standardHTML = '<div whatever="abc" title="javascript:true"></div>';
|
||||||
|
ieHTML = '<div title="javascript:true" whatever="abc"></div>';
|
||||||
|
|
||||||
|
expect([standardHTML, ieHTML]).toContain(t.html);
|
||||||
|
|
||||||
|
expect(ngDevMode).toHaveProperties({
|
||||||
|
firstTemplatePass: 1,
|
||||||
|
tNode: 2,
|
||||||
|
tView: 1,
|
||||||
|
rendererCreateElement: 1,
|
||||||
|
rendererSetAttribute: 2
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('elementProperty', () => {
|
describe('elementProperty', () => {
|
||||||
@ -355,6 +391,101 @@ describe('instructions', () => {
|
|||||||
expect(s.lastSanitizedValue).toBeFalsy();
|
expect(s.lastSanitizedValue).toBeFalsy();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('namespace', () => {
|
||||||
|
it('should render SVG', () => {
|
||||||
|
const t = new TemplateFixture(() => {
|
||||||
|
elementStart(0, 'div', ['id', 'container']);
|
||||||
|
setSvgNS();
|
||||||
|
elementStart(1, 'svg', [
|
||||||
|
// id="display"
|
||||||
|
'id',
|
||||||
|
'display',
|
||||||
|
// width="400"
|
||||||
|
'width',
|
||||||
|
'400',
|
||||||
|
// height="300"
|
||||||
|
'height',
|
||||||
|
'300',
|
||||||
|
// test:title="abc"
|
||||||
|
NS.FULL,
|
||||||
|
'http://www.example.com/2014/test',
|
||||||
|
'title',
|
||||||
|
'abc',
|
||||||
|
]);
|
||||||
|
element(2, 'circle', ['cx', '200', 'cy', '150', 'fill', '#0000ff']);
|
||||||
|
elementEnd();
|
||||||
|
setHtmlNS();
|
||||||
|
elementEnd();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// Most browsers will print <circle></circle>, some will print <circle />, both are valid
|
||||||
|
const standardHTML =
|
||||||
|
'<div id="container"><svg id="display" width="400" height="300" title="abc"><circle cx="200" cy="150" fill="#0000ff"></circle></svg></div>';
|
||||||
|
const ie11HTML =
|
||||||
|
'<div id="container"><svg xmlns="http://www.w3.org/2000/svg" xmlns:NS1="http://www.example.com/2014/test" NS1:title="abc" id="display" width="400" height="300"><circle fill="#0000ff" cx="200" cy="150" /></svg></div>';
|
||||||
|
|
||||||
|
expect([standardHTML, ie11HTML]).toContain(t.html);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set an attribute with a namespace', () => {
|
||||||
|
const t = new TemplateFixture(() => {
|
||||||
|
element(0, 'div', [
|
||||||
|
'id',
|
||||||
|
'container',
|
||||||
|
// test:title="abc"
|
||||||
|
NS.FULL,
|
||||||
|
'http://www.example.com/2014/test',
|
||||||
|
'title',
|
||||||
|
'abc',
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
const standardHTML = '<div id="container" title="abc"></div>';
|
||||||
|
const ie11HTML =
|
||||||
|
'<div id="container" xmlns:NS1="https://www.example.com/2014/test" NS1:title="abc"></div>';
|
||||||
|
expect([standardHTML, ie11HTML]).toContain(t.html);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set attributes including more than one namespaced attribute', () => {
|
||||||
|
const t = new TemplateFixture(() => {
|
||||||
|
element(0, 'div', [
|
||||||
|
'id',
|
||||||
|
'container',
|
||||||
|
|
||||||
|
// NS1:title="abc"
|
||||||
|
NS.FULL,
|
||||||
|
'http://www.example.com/2014/test',
|
||||||
|
'title',
|
||||||
|
'abc',
|
||||||
|
|
||||||
|
// style="background: #dead11"
|
||||||
|
'style',
|
||||||
|
'background: #dead11',
|
||||||
|
|
||||||
|
// NS1:whatever="wee"
|
||||||
|
NS.FULL,
|
||||||
|
'http://www.example.com/2014/test',
|
||||||
|
'whatever',
|
||||||
|
'wee',
|
||||||
|
|
||||||
|
// NS2:shazbot="wocka wocka"
|
||||||
|
NS.FULL,
|
||||||
|
'http://www.whatever.com/2016/blah',
|
||||||
|
'shazbot',
|
||||||
|
'wocka wocka',
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
const standardHTML =
|
||||||
|
'<div id="container" title="abc" style="background: #dead11" whatever="wee" shazbot="wocka wocka"></div>';
|
||||||
|
const ieHTML =
|
||||||
|
'<div id="container" style="background: rgb(222, 173, 17);" title="abc" whatever="wee" shazbot="wocka wocka"></div>';
|
||||||
|
|
||||||
|
expect([standardHTML, ieHTML]).toContain(t.html);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
class LocalSanitizedValue {
|
class LocalSanitizedValue {
|
||||||
|
@ -70,7 +70,7 @@ describe('render3 integration test', () => {
|
|||||||
expect(renderToHtml(Template, undefined)).toEqual('');
|
expect(renderToHtml(Template, undefined)).toEqual('');
|
||||||
expect(ngDevMode).toHaveProperties({
|
expect(ngDevMode).toHaveProperties({
|
||||||
firstTemplatePass: 0,
|
firstTemplatePass: 0,
|
||||||
tNode: 0,
|
tNode: 2,
|
||||||
tView: 1,
|
tView: 1,
|
||||||
rendererSetText: 2,
|
rendererSetText: 2,
|
||||||
});
|
});
|
||||||
@ -90,7 +90,7 @@ describe('render3 integration test', () => {
|
|||||||
expect(renderToHtml(Template, null)).toEqual('');
|
expect(renderToHtml(Template, null)).toEqual('');
|
||||||
expect(ngDevMode).toHaveProperties({
|
expect(ngDevMode).toHaveProperties({
|
||||||
firstTemplatePass: 0,
|
firstTemplatePass: 0,
|
||||||
tNode: 0,
|
tNode: 2,
|
||||||
tView: 1,
|
tView: 1,
|
||||||
rendererSetText: 2,
|
rendererSetText: 2,
|
||||||
});
|
});
|
||||||
@ -109,7 +109,7 @@ describe('render3 integration test', () => {
|
|||||||
expect(renderToHtml(Template, 'twice')).toEqual('once');
|
expect(renderToHtml(Template, 'twice')).toEqual('once');
|
||||||
expect(ngDevMode).toHaveProperties({
|
expect(ngDevMode).toHaveProperties({
|
||||||
firstTemplatePass: 0,
|
firstTemplatePass: 0,
|
||||||
tNode: 0,
|
tNode: 2,
|
||||||
tView: 1,
|
tView: 1,
|
||||||
rendererSetText: 1,
|
rendererSetText: 1,
|
||||||
});
|
});
|
||||||
|
@ -110,7 +110,7 @@ class DefaultDomRenderer2 implements Renderer2 {
|
|||||||
|
|
||||||
createElement(name: string, namespace?: string): any {
|
createElement(name: string, namespace?: string): any {
|
||||||
if (namespace) {
|
if (namespace) {
|
||||||
return document.createElementNS(NAMESPACE_URIS[namespace], name);
|
return document.createElementNS(NAMESPACE_URIS[namespace] || namespace, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
return document.createElement(name);
|
return document.createElement(name);
|
||||||
@ -150,26 +150,17 @@ class DefaultDomRenderer2 implements Renderer2 {
|
|||||||
|
|
||||||
setAttribute(el: any, name: string, value: string, namespace?: string): void {
|
setAttribute(el: any, name: string, value: string, namespace?: string): void {
|
||||||
if (namespace) {
|
if (namespace) {
|
||||||
name = `${namespace}:${name}`;
|
const namespaceUri = NAMESPACE_URIS[namespace] || namespace;
|
||||||
const namespaceUri = NAMESPACE_URIS[namespace];
|
|
||||||
if (namespaceUri) {
|
|
||||||
el.setAttributeNS(namespaceUri, name, value);
|
el.setAttributeNS(namespaceUri, name, value);
|
||||||
} else {
|
} else {
|
||||||
el.setAttribute(name, value);
|
el.setAttribute(name, value);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
el.setAttribute(name, value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
removeAttribute(el: any, name: string, namespace?: string): void {
|
removeAttribute(el: any, name: string, namespace?: string): void {
|
||||||
if (namespace) {
|
if (namespace) {
|
||||||
const namespaceUri = NAMESPACE_URIS[namespace];
|
const namespaceUri = NAMESPACE_URIS[namespace] || namespace;
|
||||||
if (namespaceUri) {
|
|
||||||
el.removeAttributeNS(namespaceUri, name);
|
el.removeAttributeNS(namespaceUri, name);
|
||||||
} else {
|
|
||||||
el.removeAttribute(`${namespace}:${name}`);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
el.removeAttribute(name);
|
el.removeAttribute(name);
|
||||||
}
|
}
|
||||||
|
@ -28,23 +28,14 @@ import {NAMESPACE_URIS} from '../../src/dom/dom_renderer';
|
|||||||
|
|
||||||
describe('setAttribute', () => {
|
describe('setAttribute', () => {
|
||||||
describe('with namespace', () => {
|
describe('with namespace', () => {
|
||||||
it('xmlns', () => shouldSetAttributeWithNs('xmlns'));
|
|
||||||
it('xml', () => shouldSetAttributeWithNs('xml'));
|
it('xml', () => shouldSetAttributeWithNs('xml'));
|
||||||
it('svg', () => shouldSetAttributeWithNs('svg'));
|
it('svg', () => shouldSetAttributeWithNs('svg'));
|
||||||
it('xhtml', () => shouldSetAttributeWithNs('xhtml'));
|
it('xhtml', () => shouldSetAttributeWithNs('xhtml'));
|
||||||
it('xlink', () => shouldSetAttributeWithNs('xlink'));
|
it('xlink', () => shouldSetAttributeWithNs('xlink'));
|
||||||
|
it('custom', () => shouldSetAttributeWithNs('custom'));
|
||||||
it('unknown', () => {
|
|
||||||
const div = document.createElement('div');
|
|
||||||
expect(div.hasAttribute('unknown:name')).toBe(false);
|
|
||||||
|
|
||||||
renderer.setAttribute(div, 'name', 'value', 'unknown');
|
|
||||||
|
|
||||||
expect(div.getAttribute('unknown:name')).toBe('value');
|
|
||||||
});
|
|
||||||
|
|
||||||
function shouldSetAttributeWithNs(namespace: string): void {
|
function shouldSetAttributeWithNs(namespace: string): void {
|
||||||
const namespaceUri = NAMESPACE_URIS[namespace];
|
const namespaceUri = NAMESPACE_URIS[namespace] || namespace;
|
||||||
const div = document.createElement('div');
|
const div = document.createElement('div');
|
||||||
expect(div.hasAttributeNS(namespaceUri, 'name')).toBe(false);
|
expect(div.hasAttributeNS(namespaceUri, 'name')).toBe(false);
|
||||||
|
|
||||||
@ -57,26 +48,16 @@ import {NAMESPACE_URIS} from '../../src/dom/dom_renderer';
|
|||||||
|
|
||||||
describe('removeAttribute', () => {
|
describe('removeAttribute', () => {
|
||||||
describe('with namespace', () => {
|
describe('with namespace', () => {
|
||||||
it('xmlns', () => shouldRemoveAttributeWithNs('xmlns'));
|
|
||||||
it('xml', () => shouldRemoveAttributeWithNs('xml'));
|
it('xml', () => shouldRemoveAttributeWithNs('xml'));
|
||||||
it('svg', () => shouldRemoveAttributeWithNs('svg'));
|
it('svg', () => shouldRemoveAttributeWithNs('svg'));
|
||||||
it('xhtml', () => shouldRemoveAttributeWithNs('xhtml'));
|
it('xhtml', () => shouldRemoveAttributeWithNs('xhtml'));
|
||||||
it('xlink', () => shouldRemoveAttributeWithNs('xlink'));
|
it('xlink', () => shouldRemoveAttributeWithNs('xlink'));
|
||||||
|
it('custom', () => shouldRemoveAttributeWithNs('custom'));
|
||||||
it('unknown', () => {
|
|
||||||
const div = document.createElement('div');
|
|
||||||
div.setAttribute('unknown:name', 'value');
|
|
||||||
expect(div.hasAttribute('unknown:name')).toBe(true);
|
|
||||||
|
|
||||||
renderer.removeAttribute(div, 'name', 'unknown');
|
|
||||||
|
|
||||||
expect(div.hasAttribute('unknown:name')).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
function shouldRemoveAttributeWithNs(namespace: string): void {
|
function shouldRemoveAttributeWithNs(namespace: string): void {
|
||||||
const namespaceUri = NAMESPACE_URIS[namespace];
|
const namespaceUri = NAMESPACE_URIS[namespace] || namespace;
|
||||||
const div = document.createElement('div');
|
const div = document.createElement('div');
|
||||||
div.setAttributeNS(namespaceUri, `${namespace}:name`, 'value');
|
div.setAttributeNS(namespaceUri, 'name', 'value');
|
||||||
expect(div.hasAttributeNS(namespaceUri, 'name')).toBe(true);
|
expect(div.hasAttributeNS(namespaceUri, 'name')).toBe(true);
|
||||||
|
|
||||||
renderer.removeAttribute(div, 'name', namespace);
|
renderer.removeAttribute(div, 'name', namespace);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user