@aurelia/jit
Advanced tools
Comparing version 0.2.0-dev.20180926 to 0.2.0-dev.20180927
@@ -21,5 +21,6 @@ import { INode } from '@aurelia/runtime'; | ||
readonly $content: ElementSyntax | null; | ||
readonly $children: ElementSyntax[]; | ||
readonly $children: ReadonlyArray<ElementSyntax>; | ||
readonly $attributes: ReadonlyArray<AttrSyntax>; | ||
constructor(node: Node, name: string, $content: ElementSyntax | null, $children: ElementSyntax[], $attributes: ReadonlyArray<AttrSyntax>); | ||
constructor(node: Node, name: string, $content: ElementSyntax | null, $children: ReadonlyArray<ElementSyntax>, $attributes: ReadonlyArray<AttrSyntax>); | ||
static createMarker(): ElementSyntax; | ||
} | ||
@@ -26,0 +27,0 @@ export interface IElementParser { |
@@ -1,15 +0,20 @@ | ||
import { Immutable } from '@aurelia/kernel'; | ||
import { BindingMode, IBindableDescription, ICustomAttributeSource, IResourceDescriptions, ITemplateSource, TargetedInstruction } from '@aurelia/runtime'; | ||
import { Immutable, IServiceLocator } from '@aurelia/kernel'; | ||
import { BindingMode, IBindableDescription, ICustomAttributeSource, IExpressionParser, IResourceDescriptions, ITemplateSource, TargetedInstruction } from '@aurelia/runtime'; | ||
import { AttrSyntax, IAttributeParser } from './attribute-parser'; | ||
import { IBindingCommand } from './binding-command'; | ||
import { ElementSyntax } from './element-parser'; | ||
import { ElementSyntax, IElementParser } from './element-parser'; | ||
import { HydrateTemplateController } from './template-compiler'; | ||
export declare class SemanticModel { | ||
resources: IResourceDescriptions; | ||
attrParser: IAttributeParser; | ||
syntaxRoot: ElementSyntax; | ||
resources: IResourceDescriptions; | ||
elParser: IElementParser; | ||
exprParser: IExpressionParser; | ||
readonly isSemanticModel: true; | ||
readonly root: ElementSymbol; | ||
private readonly attrDefCache; | ||
private readonly elDefCache; | ||
private readonly commandCache; | ||
constructor(attrParser: IAttributeParser, syntaxRoot: ElementSyntax, resources: IResourceDescriptions); | ||
private constructor(); | ||
static create(definition: ITemplateSource, resources: IResourceDescriptions, attrParser: IAttributeParser, elParser: IElementParser, exprParser: IExpressionParser): SemanticModel; | ||
static create(definition: ITemplateSource, resources: IResourceDescriptions, locator: IServiceLocator): SemanticModel; | ||
getAttributeDefinition(name: string): ICustomAttributeSource; | ||
@@ -20,4 +25,4 @@ getElementDefinition(name: string): ITemplateSource; | ||
getMultiAttrBindingSymbol(syntax: AttrSyntax, parent: AttributeSymbol): MultiAttributeBindingSymbol; | ||
getElementSymbol(syntax: ElementSyntax, parent: ElementSymbol, definition?: ITemplateSource): ElementSymbol; | ||
getElementSymbolRoot(definition: ITemplateSource): ElementSymbol; | ||
getElementSymbol(syntax: ElementSyntax, parent: ElementSymbol): ElementSymbol; | ||
getTemplateElementSymbol(syntax: ElementSyntax, parent: ElementSymbol, definition: ITemplateSource, definitionRoot: ElementSymbol): ElementSymbol; | ||
} | ||
@@ -27,2 +32,3 @@ export interface IAttributeSymbol { | ||
readonly target: string; | ||
readonly res: string | null; | ||
readonly rawName: string; | ||
@@ -53,2 +59,3 @@ readonly rawValue: string; | ||
readonly target: string; | ||
readonly res: string; | ||
readonly rawName: string; | ||
@@ -106,7 +113,8 @@ readonly rawValue: string; | ||
readonly $parent: ElementSymbol; | ||
readonly syntax: ElementSyntax; | ||
readonly definition: ITemplateSource | null; | ||
readonly $attributes: ReadonlyArray<AttributeSymbol>; | ||
readonly $children: ReadonlyArray<ElementSymbol>; | ||
readonly $liftedChildren: ReadonlyArray<ElementSymbol>; | ||
readonly $content: ElementSymbol; | ||
readonly isMarker: boolean; | ||
readonly isTemplate: boolean; | ||
@@ -116,2 +124,3 @@ readonly isSlot: boolean; | ||
readonly node: Node; | ||
readonly syntax: ElementSyntax; | ||
readonly name: string; | ||
@@ -121,6 +130,22 @@ readonly isCustomElement: boolean; | ||
readonly firstChild: ElementSymbol; | ||
readonly componentRoot: ElementSymbol; | ||
readonly isLifted: boolean; | ||
private _$content; | ||
private _isMarker; | ||
private _isTemplate; | ||
private _isSlot; | ||
private _isLet; | ||
private _node; | ||
private _syntax; | ||
private _name; | ||
private _isCustomElement; | ||
private _isLifted; | ||
constructor(semanticModel: SemanticModel, isRoot: boolean, $root: ElementSymbol, $parent: ElementSymbol, syntax: ElementSyntax, definition: ITemplateSource | null); | ||
makeTarget(): void; | ||
replaceTextNodeWithMarker(): void; | ||
replaceNodeWithMarker(): void; | ||
lift(instruction: HydrateTemplateController): ElementSymbol; | ||
addInstructions(instructions: TargetedInstruction[]): void; | ||
private setToMarker; | ||
} | ||
//# sourceMappingURL=semantic-model.d.ts.map |
import { BindingMode, DelegationStrategy, ICallBindingInstruction, IExpression, IExpressionParser, IHydrateAttributeInstruction, IHydrateElementInstruction, IHydrateTemplateController, ILetBindingInstruction, ILetElementInstruction, IListenerBindingInstruction, INode, IPropertyBindingInstruction, IRefBindingInstruction, IResourceDescriptions, ISetPropertyInstruction, IStylePropertyBindingInstruction, ITargetedInstruction, ITemplateCompiler, ITemplateSource, ITextBindingInstruction, TargetedInstruction, TargetedInstructionType, TemplateDefinition, ViewCompileFlags } from '@aurelia/runtime'; | ||
import { IAttributeParser } from './attribute-parser'; | ||
import { IElementParser } from './element-parser'; | ||
import { ElementSymbol } from './semantic-model'; | ||
export declare class TemplateCompiler implements ITemplateCompiler { | ||
@@ -12,3 +11,9 @@ exprParser: IExpressionParser; | ||
compile(definition: ITemplateSource, resources: IResourceDescriptions, flags?: ViewCompileFlags): TemplateDefinition; | ||
compileLetElement($el: ElementSymbol): void; | ||
private compileNode; | ||
private compileSurrogate; | ||
private compileElementNode; | ||
private compileCustomElement; | ||
private compileCustomAttribute; | ||
private compileLetElement; | ||
private compileAttribute; | ||
} | ||
@@ -15,0 +20,0 @@ export declare class TextBindingInstruction implements ITextBindingInstruction { |
{ | ||
"name": "@aurelia/jit", | ||
"version": "0.2.0-dev.20180926", | ||
"version": "0.2.0-dev.20180927", | ||
"main": "dist/index.umd.js", | ||
@@ -46,4 +46,4 @@ "module": "dist/index.es6.js", | ||
"dependencies": { | ||
"@aurelia/kernel": "0.2.0-dev.20180926", | ||
"@aurelia/runtime": "^0.2.0-dev.20180926" | ||
"@aurelia/kernel": "0.2.0-dev.20180927", | ||
"@aurelia/runtime": "^0.2.0-dev.20180927" | ||
}, | ||
@@ -89,3 +89,3 @@ "devDependencies": { | ||
}, | ||
"gitHead": "ad6eeb42a81e32b0c67cb4ebb65a46b608bc7397" | ||
"gitHead": "9eb0764711f930d4b5ff930bffac2501508b8d5e" | ||
} |
@@ -22,2 +22,6 @@ import { DI, inject, PLATFORM } from '@aurelia/kernel'; | ||
const marker = DOM.createElement('au-marker') as Element; | ||
marker.classList.add('au'); | ||
const createMarker: () => HTMLElement = marker.cloneNode.bind(marker, false); | ||
export class ElementSyntax { | ||
@@ -28,5 +32,9 @@ constructor( | ||
public readonly $content: ElementSyntax | null, | ||
public readonly $children: ElementSyntax[], | ||
public readonly $children: ReadonlyArray<ElementSyntax>, | ||
public readonly $attributes: ReadonlyArray<AttrSyntax>) { | ||
} | ||
public static createMarker(): ElementSyntax { | ||
return new ElementSyntax(createMarker(), 'au-marker', null, PLATFORM.emptyArray, PLATFORM.emptyArray) | ||
} | ||
} | ||
@@ -33,0 +41,0 @@ |
@@ -1,10 +0,13 @@ | ||
import { Immutable, PLATFORM } from '@aurelia/kernel'; | ||
import { BindingMode, CustomAttributeResource, CustomElementResource, IBindableDescription, ICustomAttributeSource, IResourceDescriptions, ITemplateSource, TargetedInstruction } from '@aurelia/runtime'; | ||
import { Immutable, IServiceLocator, PLATFORM } from '@aurelia/kernel'; | ||
import { BindingMode, CustomAttributeResource, CustomElementResource, DOM, IBindableDescription, ICustomAttributeSource, IExpressionParser, IResourceDescriptions, ITemplateSource, TargetedInstruction } from '@aurelia/runtime'; | ||
import { Char } from '../binding/expression-parser'; | ||
import { AttrSyntax, IAttributeParser } from './attribute-parser'; | ||
import { BindingCommandResource, IBindingCommand } from './binding-command'; | ||
import { ElementSyntax, NodeType } from './element-parser'; | ||
import { ElementSyntax, IElementParser, NodeType } from './element-parser'; | ||
import { HydrateTemplateController } from './template-compiler'; | ||
export class SemanticModel { | ||
public readonly isSemanticModel: true = true; | ||
public readonly root: ElementSymbol; | ||
private readonly attrDefCache: Record<string, ICustomAttributeSource>; | ||
@@ -14,6 +17,8 @@ private readonly elDefCache: Record<string, ITemplateSource>; | ||
constructor( | ||
private constructor( | ||
definition: ITemplateSource, | ||
public resources: IResourceDescriptions, | ||
public attrParser: IAttributeParser, | ||
public syntaxRoot: ElementSyntax, | ||
public resources: IResourceDescriptions | ||
public elParser: IElementParser, | ||
public exprParser: IExpressionParser | ||
) { | ||
@@ -23,4 +28,41 @@ this.attrDefCache = {}; | ||
this.commandCache = {}; | ||
const syntax = this.elParser.parse(definition.templateOrNode); | ||
definition.templateOrNode = syntax.node; | ||
this.root = new ElementSymbol( | ||
/* semanticModel*/this, | ||
/*isDefinitionRoot*/true, | ||
/* $definitionRoot*/null, | ||
/* $parent*/null, | ||
/* syntax*/syntax, | ||
/* definition*/definition | ||
); | ||
} | ||
public static create( | ||
definition: ITemplateSource, | ||
resources: IResourceDescriptions, | ||
attrParser: IAttributeParser, | ||
elParser: IElementParser, | ||
exprParser: IExpressionParser): SemanticModel; | ||
public static create( | ||
definition: ITemplateSource, | ||
resources: IResourceDescriptions, | ||
locator: IServiceLocator): SemanticModel; | ||
public static create( | ||
definition: ITemplateSource, | ||
resources: IResourceDescriptions, | ||
attrParser: IServiceLocator | IAttributeParser, | ||
elParser?: IElementParser, | ||
exprParser?: IExpressionParser): SemanticModel { | ||
if ('get' in attrParser) { | ||
const locator = attrParser as IServiceLocator; | ||
attrParser = locator.get<IAttributeParser>(IAttributeParser); | ||
elParser = locator.get<IElementParser>(IElementParser); | ||
exprParser = locator.get<IExpressionParser>(IExpressionParser); | ||
} | ||
return new SemanticModel(definition, resources, attrParser, elParser, exprParser); | ||
} | ||
public getAttributeDefinition(name: string): ICustomAttributeSource { | ||
@@ -64,5 +106,6 @@ const existing = this.attrDefCache[name]; | ||
public getElementSymbol(syntax: ElementSyntax, parent: ElementSymbol, definition?: ITemplateSource): ElementSymbol { | ||
public getElementSymbol(syntax: ElementSyntax, parent: ElementSymbol): ElementSymbol { | ||
const node = syntax.node as Element; | ||
if (definition === undefined && node.nodeType === NodeType.Element) { | ||
let definition: ITemplateSource; | ||
if (node.nodeType === NodeType.Element) { | ||
const resourceKey = (node.getAttribute('as-element') || node.nodeName).toLowerCase(); | ||
@@ -72,9 +115,21 @@ definition = this.getElementDefinition(resourceKey); | ||
return new ElementSymbol(this, false, parent.$root, parent, syntax, definition); | ||
return new ElementSymbol( | ||
/* semanticModel*/this, | ||
/*isDefinitionRoot*/false, | ||
/* $definitionRoot*/parent.$root, | ||
/* $parent*/parent, | ||
/* syntax*/syntax, | ||
/* definition*/definition | ||
); | ||
} | ||
public getElementSymbolRoot(definition: ITemplateSource): ElementSymbol { | ||
const $el = new ElementSymbol(this, true, null, null, this.syntaxRoot, definition); | ||
$el.definition.templateOrNode = $el.node; | ||
return $el; | ||
public getTemplateElementSymbol(syntax: ElementSyntax, parent: ElementSymbol, definition: ITemplateSource, definitionRoot: ElementSymbol): ElementSymbol { | ||
return new ElementSymbol( | ||
/* semanticModel*/this, | ||
/*isDefinitionRoot*/true, | ||
/* $definitionRoot*/definitionRoot, | ||
/* $parent*/parent, | ||
/* syntax*/syntax, | ||
/* definition*/definition | ||
); | ||
} | ||
@@ -86,2 +141,3 @@ } | ||
readonly target: string; | ||
readonly res: string | null; | ||
readonly rawName: string; | ||
@@ -109,2 +165,3 @@ readonly rawValue: string; | ||
public readonly target: string; | ||
public readonly res: string = null; | ||
public readonly rawName: string; | ||
@@ -274,9 +331,30 @@ public readonly rawValue: string; | ||
public readonly $children: ReadonlyArray<ElementSymbol>; | ||
public readonly $content: ElementSymbol = null; | ||
public readonly isTemplate: boolean = false; | ||
public readonly isSlot: boolean = false; | ||
public readonly isLet: boolean = false; | ||
public readonly node: Node; | ||
public readonly name: string; | ||
public readonly isCustomElement: boolean; | ||
public readonly $liftedChildren: ReadonlyArray<ElementSymbol>; | ||
public get $content(): ElementSymbol { | ||
return this._$content; | ||
} | ||
public get isMarker(): boolean { | ||
return this._isMarker; | ||
} | ||
public get isTemplate(): boolean { | ||
return this._isTemplate; | ||
} | ||
public get isSlot(): boolean { | ||
return this._isSlot; | ||
} | ||
public get isLet(): boolean { | ||
return this._isLet; | ||
} | ||
public get node(): Node { | ||
return this._node; | ||
} | ||
public get syntax(): ElementSyntax { | ||
return this._syntax; | ||
} | ||
public get name(): string { | ||
return this._name; | ||
} | ||
public get isCustomElement(): boolean { | ||
return this._isCustomElement; | ||
} | ||
public get nextSibling(): ElementSymbol { | ||
@@ -297,2 +375,18 @@ if (!this.$parent) { | ||
} | ||
public get componentRoot(): ElementSymbol { | ||
return this.semanticModel.root; | ||
} | ||
public get isLifted(): boolean { | ||
return this._isLifted; | ||
} | ||
private _$content: ElementSymbol = null; | ||
private _isMarker: boolean = false; | ||
private _isTemplate: boolean = false; | ||
private _isSlot: boolean = false; | ||
private _isLet: boolean = false; | ||
private _node: Node; | ||
private _syntax: ElementSyntax; | ||
private _name: string; | ||
private _isCustomElement: boolean; | ||
private _isLifted: boolean = false; | ||
@@ -304,20 +398,21 @@ constructor( | ||
public readonly $parent: ElementSymbol, | ||
public readonly syntax: ElementSyntax, | ||
syntax: ElementSyntax, | ||
public readonly definition: ITemplateSource | null | ||
) { | ||
this.$root = isRoot ? this : $root; | ||
this.node = syntax.node; | ||
this.name = this.node.nodeName; | ||
this._node = syntax.node; | ||
this._syntax = syntax; | ||
this._name = this.node.nodeName; | ||
switch (this.name) { | ||
case 'TEMPLATE': | ||
this.isTemplate = true; | ||
this.$content = this.semanticModel.getElementSymbol(syntax.$content, this, definition); | ||
this._isTemplate = true; | ||
this._$content = this.semanticModel.getTemplateElementSymbol(syntax.$content, this, definition, this); | ||
break; | ||
case 'SLOT': | ||
this.isSlot = true; | ||
this._isSlot = true; | ||
break; | ||
case 'LET': | ||
this.isLet = true; | ||
this._isLet = true; | ||
} | ||
this.isCustomElement = !isRoot && !!definition; | ||
this._isCustomElement = !isRoot && !!definition; | ||
@@ -353,5 +448,60 @@ const attributes = syntax.$attributes; | ||
public replaceTextNodeWithMarker(): void { | ||
const marker = ElementSyntax.createMarker(); | ||
const node = this.node; | ||
node.parentNode.insertBefore(marker.node, node); | ||
node.textContent = ' '; | ||
while (node.nextSibling && node.nextSibling.nodeType === NodeType.Text) { | ||
node.parentNode.removeChild(node.nextSibling); | ||
} | ||
this.setToMarker(marker); | ||
} | ||
public replaceNodeWithMarker(): void { | ||
const marker = ElementSyntax.createMarker(); | ||
const node = this.node; | ||
if (node.parentNode) { | ||
node.parentNode.replaceChild(marker.node, node); | ||
} else if (this.isTemplate) { | ||
(<HTMLTemplateElement>node).content.appendChild(marker.node); | ||
} | ||
this.setToMarker(marker); | ||
} | ||
public lift(instruction: HydrateTemplateController): ElementSymbol { | ||
const template = instruction.src.templateOrNode = DOM.createTemplate() as HTMLTemplateElement; | ||
const node = this.node as HTMLTemplateElement; | ||
if (this.isTemplate) { | ||
// copy remaining attributes over to the newly created template | ||
const attributes = node.attributes; | ||
while (attributes.length) { | ||
const attr = attributes[0]; | ||
template.setAttribute(attr.name, attr.value); | ||
node.removeAttribute(attr.name); | ||
} | ||
template.content.appendChild(node.content); | ||
this.replaceNodeWithMarker(); | ||
} else { | ||
this.replaceNodeWithMarker(); | ||
template.content.appendChild(node); | ||
} | ||
this.addInstructions([instruction]); | ||
this._isLifted = true; | ||
return this.semanticModel.getTemplateElementSymbol( | ||
this.semanticModel.elParser.parse(template), this, instruction.src, null | ||
); | ||
} | ||
public addInstructions(instructions: TargetedInstruction[]): void { | ||
this.$root.definition.instructions.push(instructions); | ||
} | ||
private setToMarker(marker: ElementSyntax): void { | ||
this._$content = null; | ||
this._isCustomElement = this._isLet = this._isSlot = this._isTemplate = false; | ||
this._isMarker = true; | ||
this._name = 'AU-MARKER'; | ||
this._node = marker.node; | ||
this._syntax = marker; | ||
} | ||
} |
@@ -37,10 +37,4 @@ import { inject, PLATFORM } from '@aurelia/kernel'; | ||
import { IElementParser, NodeType } from './element-parser'; | ||
import { ElementSymbol, IAttributeSymbol, SemanticModel } from './semantic-model'; | ||
import { AttributeSymbol, ElementSymbol, IAttributeSymbol, SemanticModel } from './semantic-model'; | ||
// tslint:disable:no-inner-html | ||
const marker = DOM.createElement('au-marker') as Element; | ||
marker.classList.add('au'); | ||
const createMarker: () => HTMLElement = marker.cloneNode.bind(marker, false); | ||
@inject(IExpressionParser, IElementParser, IAttributeParser) | ||
@@ -55,9 +49,9 @@ export class TemplateCompiler implements ITemplateCompiler { | ||
public compile(definition: ITemplateSource, resources: IResourceDescriptions, flags?: ViewCompileFlags): TemplateDefinition { | ||
let $el = new SemanticModel(this.attrParser, this.elParser.parse(definition.templateOrNode), resources).getElementSymbolRoot(definition); | ||
const $root = $el; | ||
while ($el = this.compileNode($el.$content || $el)); | ||
const model = SemanticModel.create(definition, resources, this.attrParser, this.elParser, this.exprParser); | ||
let $el = model.root; | ||
while ($el = this.compileNode($el)); | ||
// ideally the flag should be passed correctly from rendering engine | ||
if ($root.isTemplate && (flags & ViewCompileFlags.surrogate)) { | ||
this.compileSurrogate($root); | ||
// the flag should be passed correctly from rendering engine | ||
if (model.root.isTemplate && (flags & ViewCompileFlags.surrogate)) { | ||
this.compileSurrogate(model.root); | ||
} | ||
@@ -68,4 +62,3 @@ | ||
/*@internal*/ | ||
public compileNode($el: ElementSymbol): ElementSymbol { | ||
private compileNode($el: ElementSymbol): ElementSymbol { | ||
const node = $el.node; | ||
@@ -75,9 +68,26 @@ const nextSibling = $el.nextSibling; | ||
case NodeType.Element: | ||
this.compileElementNode($el); | ||
if ($el.isSlot) { | ||
$el.$parent.definition.hasSlots = true; | ||
} else if ($el.isLet) { | ||
this.compileLetElement($el); | ||
} else if ($el.isCustomElement) { | ||
this.compileCustomElement($el); | ||
} else { | ||
this.compileElementNode($el); | ||
} | ||
if (!$el.isLifted) { | ||
let $child = $el.firstChild || $el.$content; | ||
while ($child) { | ||
$child = this.compileNode($child); | ||
} | ||
} | ||
return nextSibling; | ||
case NodeType.Text: | ||
if (!this.compileTextNode($el)) { | ||
const expression = this.exprParser.parse((<Text>$el.node).wholeText, BindingType.Interpolation); | ||
if (expression === null) { | ||
while (($el = $el.nextSibling) && $el.node.nodeType === NodeType.Text); | ||
return $el; | ||
} | ||
$el.replaceTextNodeWithMarker(); | ||
$el.addInstructions([new TextBindingInstruction(expression)]); | ||
return nextSibling; | ||
@@ -95,4 +105,3 @@ case NodeType.Comment: | ||
/*@internal*/ | ||
public compileSurrogate($el: ElementSymbol): void { | ||
private compileSurrogate($el: ElementSymbol): void { | ||
const attributes = $el.$attributes; | ||
@@ -128,16 +137,47 @@ for (let i = 0, ii = attributes.length; i < ii; ++i) { | ||
/*@internal*/ | ||
public compileElementNode($el: ElementSymbol): void { | ||
if ($el.isSlot) { | ||
$el.$parent.definition.hasSlots = true; | ||
private compileElementNode($el: ElementSymbol): void { | ||
if ($el.$attributes.length === 0) { | ||
return; | ||
} else if ($el.isLet) { | ||
this.compileLetElement($el); | ||
} | ||
const attributes = $el.$attributes; | ||
const attributeInstructions: TargetedInstruction[] = []; | ||
for (let i = 0, ii = attributes.length; i < ii; ++i) { | ||
const $attr = attributes[i]; | ||
if ($attr.isProcessed) continue; | ||
$attr.markAsProcessed(); | ||
if ($attr.isTemplateController) { | ||
let instruction = this.compileAttribute($attr); | ||
// compileAttribute will return a HydrateTemplateController if there is a binding command registered that produces one (in our case only "for") | ||
if (instruction.type !== TargetedInstructionType.hydrateTemplateController) { | ||
const name = $attr.res; | ||
instruction = new HydrateTemplateController({ name, instructions: [] }, name, [instruction], name === 'else'); | ||
} | ||
// all attribute instructions preceding the template controller become children of the hydrate instruction | ||
instruction.instructions.push(...attributeInstructions); | ||
this.compileNode($el.lift(instruction)); | ||
return; | ||
} else if ($attr.isCustomAttribute) { | ||
attributeInstructions.push(this.compileCustomAttribute($attr)); | ||
} else { | ||
const instruction = this.compileAttribute($attr); | ||
if (instruction !== null) { | ||
attributeInstructions.push(instruction); | ||
} | ||
} | ||
} | ||
if (attributeInstructions.length) { | ||
$el.addInstructions(attributeInstructions); | ||
$el.makeTarget(); | ||
} | ||
} | ||
private compileCustomElement($el: ElementSymbol): void { | ||
if ($el.$attributes.length === 0) { | ||
$el.addInstructions([new HydrateElementInstruction($el.definition.name, <any>PLATFORM.emptyArray)]); | ||
$el.makeTarget(); | ||
return; | ||
} | ||
// if there is a template controller, then all attribute instructions become children of the hydrate instruction | ||
const attributeInstructions: TargetedInstruction[] = []; | ||
// if there is a custom element, then only the attributes that map to bindables become children of the hydrate instruction, | ||
// otherwise they become sibling instructions | ||
const attributeInstructions: TargetedInstruction[] = []; | ||
// otherwise they become sibling instructions; if there is no custom element, then sibling instructions are never appended to | ||
const siblingInstructions: TargetedInstruction[] = []; | ||
@@ -147,42 +187,20 @@ const attributes = $el.$attributes; | ||
const $attr = attributes[i]; | ||
if ($attr.isProcessed) { | ||
continue; | ||
} | ||
if ($attr.isProcessed) continue; | ||
$attr.markAsProcessed(); | ||
if ($attr.isCustomAttribute) { | ||
if ($attr.isTemplateController) { | ||
let instruction = this.compileAttribute($attr); | ||
// compileAttribute will return a HydrateTemplateController if there is a binding command registered that produces one (in our case only "for") | ||
if (instruction.type !== TargetedInstructionType.hydrateTemplateController) { | ||
const src: ITemplateSource = { | ||
name: $attr.res, | ||
templateOrNode: $attr.$element.node, | ||
instructions: [] | ||
}; | ||
instruction = new HydrateTemplateController(src, $attr.res, [instruction], $attr.res === 'else'); | ||
} | ||
($attr.$element.node.parentNode || $attr.$element.$parent.node).replaceChild(createMarker(), $attr.$element.node); | ||
const template = DOM.createTemplate() as HTMLTemplateElement; | ||
template.content.appendChild($attr.$element.node); | ||
instruction.src.templateOrNode = template; | ||
instruction.instructions.push(...attributeInstructions); | ||
this.compile(<any>instruction.src, $el.semanticModel.resources); | ||
$el.addInstructions([instruction]); | ||
return; | ||
if ($attr.isTemplateController) { | ||
let instruction = this.compileAttribute($attr); | ||
// compileAttribute will return a HydrateTemplateController if there is a binding command registered that produces one (in our case only "for") | ||
if (instruction.type !== TargetedInstructionType.hydrateTemplateController) { | ||
const name = $attr.res; | ||
instruction = new HydrateTemplateController({ name, instructions: [] }, name, [instruction], name === 'else'); | ||
} | ||
// all attribute instructions preceding the template controller become children of the hydrate instruction | ||
instruction.instructions.push(...attributeInstructions); | ||
this.compileNode($el.lift(instruction)); | ||
return; | ||
} else if ($attr.isCustomAttribute) { | ||
if ($attr.isAttributeBindable) { | ||
siblingInstructions.push(this.compileCustomAttribute($attr)); | ||
} else { | ||
const childInstructions = []; | ||
if ($attr.isMultiAttrBinding) { | ||
const mBindings = $attr.$multiAttrBindings; | ||
for (let j = 0, jj = mBindings.length; j < jj; ++j) { | ||
childInstructions.push(this.compileAttribute(mBindings[j])); | ||
} | ||
} else { | ||
childInstructions.push(this.compileAttribute($attr)); | ||
} | ||
if (!$attr.onCustomElement || !$attr.isAttributeBindable) { | ||
attributeInstructions.push(new HydrateAttributeInstruction($attr.res, childInstructions)); | ||
} else { | ||
siblingInstructions.push(new HydrateAttributeInstruction($attr.res, childInstructions)); | ||
} | ||
attributeInstructions.push(this.compileCustomAttribute($attr)); | ||
} | ||
@@ -192,6 +210,6 @@ } else { | ||
if (instruction !== null) { | ||
if (!$attr.onCustomElement || $attr.isElementBindable) { | ||
if (!$attr.isElementBindable) { | ||
siblingInstructions.push(instruction); | ||
} else { | ||
attributeInstructions.push(instruction); | ||
} else { | ||
siblingInstructions.push(instruction); | ||
} | ||
@@ -201,16 +219,20 @@ } | ||
} | ||
// no template controller; see if there's a custom element | ||
if ($el.isCustomElement) { | ||
// custom element takes the attributes as children | ||
$el.addInstructions([new HydrateElementInstruction($el.definition.name, attributeInstructions), ...siblingInstructions]); | ||
$el.makeTarget(); | ||
} else if (attributeInstructions.length) { | ||
// no custom element or template controller, add the attributes directly | ||
$el.addInstructions(attributeInstructions); | ||
$el.makeTarget(); | ||
$el.addInstructions([new HydrateElementInstruction($el.definition.name, attributeInstructions), ...siblingInstructions]); | ||
$el.makeTarget(); | ||
} | ||
private compileCustomAttribute($attr: AttributeSymbol): HydrateAttributeInstruction { | ||
const childInstructions = []; | ||
if ($attr.isMultiAttrBinding) { | ||
const mBindings = $attr.$multiAttrBindings; | ||
for (let j = 0, jj = mBindings.length; j < jj; ++j) { | ||
childInstructions.push(this.compileAttribute(mBindings[j])); | ||
} | ||
} else { | ||
childInstructions.push(this.compileAttribute($attr)); | ||
} | ||
for (let $child = $el.firstChild; !!$child; $child = this.compileNode($child)); | ||
return new HydrateAttributeInstruction($attr.res, childInstructions); | ||
} | ||
public compileLetElement($el: ElementSymbol): void { | ||
private compileLetElement($el: ElementSymbol): void { | ||
const letInstructions: ILetBindingInstruction[] = []; | ||
@@ -239,23 +261,6 @@ const attributes = $el.$attributes; | ||
// theoretically there's no need to replace, but to keep it consistent | ||
DOM.replaceNode(createMarker(), $el.node); | ||
$el.replaceNodeWithMarker(); | ||
} | ||
/*@internal*/ | ||
public compileTextNode($el: ElementSymbol): boolean { | ||
const node = $el.node as Text; | ||
const expression = this.exprParser.parse(node.wholeText, BindingType.Interpolation); | ||
if (expression === null) { | ||
return false; | ||
} | ||
node.parentNode.insertBefore(createMarker(), node); | ||
node.textContent = ' '; | ||
while (node.nextSibling && node.nextSibling.nodeType === NodeType.Text) { | ||
node.parentNode.removeChild(node.nextSibling); | ||
} | ||
$el.addInstructions([new TextBindingInstruction(expression)]); | ||
return true; | ||
} | ||
/*@internal*/ | ||
public compileAttribute($attr: IAttributeSymbol): TargetedInstruction { | ||
private compileAttribute($attr: IAttributeSymbol): TargetedInstruction { | ||
// binding commands get priority over all; they may override default behaviors | ||
@@ -262,0 +267,0 @@ // it is the responsibility of the implementor to ensure they filter out stuff they shouldn't override |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
626851
7058
+ Added@aurelia/kernel@0.2.0-dev.20180927(transitive)
- Removed@aurelia/kernel@0.2.0-dev.20180926(transitive)