diff --git a/bower.json b/bower.json index 4c723034..98eb1659 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "aurelia-templating", - "version": "1.0.0-beta.1.0.3", + "version": "1.0.0-beta.1.1.0", "description": "An extensible HTML templating engine supporting databinding, custom elements, attached behaviors and more.", "keywords": [ "aurelia", diff --git a/dist/amd/aurelia-templating.d.ts b/dist/amd/aurelia-templating.d.ts index 775de511..2c2f9ae1 100644 --- a/dist/amd/aurelia-templating.d.ts +++ b/dist/amd/aurelia-templating.d.ts @@ -880,6 +880,7 @@ declare module 'aurelia-templating' { */ constructor(parentContainer: Container, viewFactory: ViewFactory, partReplacements?: Object); + // This is referenced internally in the controller's bind method. /** * Creates a view or returns one from the internal cache, if available. * @return The created view. @@ -1363,12 +1364,12 @@ declare module 'aurelia-templating' { } /** - * Creates a behavior property that references an array of immediate content child elememnts that matches the provided selector. + * Creates a behavior property that references an array of immediate content child elements that matches the provided selector. */ export function children(selectorOrConfig: string | Object): any; /** - * Creates a behavior property that references an immediate content child elememnt that matches the provided selector. + * Creates a behavior property that references an immediate content child element that matches the provided selector. */ export function child(selectorOrConfig: string | Object): any; class ChildObserver { diff --git a/dist/amd/aurelia-templating.js b/dist/amd/aurelia-templating.js index c6858241..6916e34b 100644 --- a/dist/amd/aurelia-templating.js +++ b/dist/amd/aurelia-templating.js @@ -187,6 +187,7 @@ define(['exports', 'core-js', 'aurelia-logging', 'aurelia-metadata', 'aurelia-pa instruction.host = host; instruction.viewModel = viewModel; instruction.viewFactory = viewFactory; + instruction.inheritBindingContext = true; return instruction; }; @@ -212,6 +213,7 @@ define(['exports', 'core-js', 'aurelia-logging', 'aurelia-metadata', 'aurelia-pa this.attributes = null; this.type = null; this.attrName = null; + this.inheritBindingContext = false; } return BehaviorInstruction; @@ -2674,7 +2676,7 @@ define(['exports', 'core-js', 'aurelia-logging', 'aurelia-metadata', 'aurelia-pa this.isAttached = false; this.view = null; this.isBound = false; - this.bindingContext = null; + this.scope = null; var observerLookup = behavior.observerLocator.getOrCreateObserversLookup(viewModel); var handlesBind = behavior.handlesBind; @@ -2717,10 +2719,9 @@ define(['exports', 'core-js', 'aurelia-logging', 'aurelia-metadata', 'aurelia-pa var x = undefined; var observer = undefined; var selfSubscriber = undefined; - var context = scope.bindingContext; if (this.isBound) { - if (this.bindingContext === context) { + if (this.scope === scope) { return; } @@ -2728,7 +2729,7 @@ define(['exports', 'core-js', 'aurelia-logging', 'aurelia-metadata', 'aurelia-pa } this.isBound = true; - this.bindingContext = context; + this.scope = scope; for (i = 0, ii = boundProperties.length; i < ii; ++i) { x = boundProperties[i]; @@ -2747,14 +2748,29 @@ define(['exports', 'core-js', 'aurelia-logging', 'aurelia-metadata', 'aurelia-pa observer.selfSubscriber = selfSubscriber; } + var overrideContext = undefined; if (this.view !== null) { if (skipSelfSubscriber) { this.view.viewModelScope = scope; } - this.view.bind(this.viewModel, _aureliaBinding.createOverrideContext(this.viewModel, scope.overrideContext)); + if (this.viewModel === scope.overrideContext.bindingContext) { + overrideContext = scope.overrideContext; + } else if (this.instruction.inheritBindingContext) { + overrideContext = _aureliaBinding.createOverrideContext(this.viewModel, scope.overrideContext); + } else { + overrideContext = _aureliaBinding.createOverrideContext(this.viewModel); + overrideContext.__parentOverrideContext = scope.overrideContext; + } + this.view.bind(this.viewModel, overrideContext); } else if (skipSelfSubscriber) { - this.viewModel.bind(context, scope.overrideContext); + overrideContext = scope.overrideContext; + + if (scope.overrideContext.__parentOverrideContext !== undefined && this.viewModel.viewFactory && this.viewModel.viewFactory.factoryCreateInstruction.partReplacements) { + overrideContext = Object.assign({}, scope.overrideContext); + overrideContext.parentOverrideContext = scope.overrideContext.__parentOverrideContext; + } + this.viewModel.bind(scope.bindingContext, overrideContext); } }; @@ -3279,7 +3295,7 @@ define(['exports', 'core-js', 'aurelia-logging', 'aurelia-metadata', 'aurelia-pa node = template; } } else if (this.elementName !== null) { - var _partReplacements2 = instruction.partReplacements = {}; + var _partReplacements2 = {}; if (this.processContent(compiler, resources, node, instruction) && node.hasChildNodes()) { if (this.usesShadowDOM) { @@ -3293,6 +3309,7 @@ define(['exports', 'core-js', 'aurelia-logging', 'aurelia-metadata', 'aurelia-pa if (currentChild.tagName === 'TEMPLATE' && (toReplace = currentChild.getAttribute('replace-part'))) { _partReplacements2[toReplace] = compiler.compile(currentChild, resources); _aureliaPal.DOM.removeNode(currentChild, parentNode); + instruction.partReplacements = _partReplacements2; } currentChild = nextSibling; @@ -3311,6 +3328,7 @@ define(['exports', 'core-js', 'aurelia-logging', 'aurelia-metadata', 'aurelia-pa if (currentChild.tagName === 'TEMPLATE' && (toReplace = currentChild.getAttribute('replace-part'))) { _partReplacements2[toReplace] = compiler.compile(currentChild, resources); _aureliaPal.DOM.removeNode(currentChild, parentNode); + instruction.partReplacements = _partReplacements2; } else { fragment.appendChild(currentChild); } diff --git a/dist/aurelia-templating.d.ts b/dist/aurelia-templating.d.ts index 775de511..2c2f9ae1 100644 --- a/dist/aurelia-templating.d.ts +++ b/dist/aurelia-templating.d.ts @@ -880,6 +880,7 @@ declare module 'aurelia-templating' { */ constructor(parentContainer: Container, viewFactory: ViewFactory, partReplacements?: Object); + // This is referenced internally in the controller's bind method. /** * Creates a view or returns one from the internal cache, if available. * @return The created view. @@ -1363,12 +1364,12 @@ declare module 'aurelia-templating' { } /** - * Creates a behavior property that references an array of immediate content child elememnts that matches the provided selector. + * Creates a behavior property that references an array of immediate content child elements that matches the provided selector. */ export function children(selectorOrConfig: string | Object): any; /** - * Creates a behavior property that references an immediate content child elememnt that matches the provided selector. + * Creates a behavior property that references an immediate content child element that matches the provided selector. */ export function child(selectorOrConfig: string | Object): any; class ChildObserver { diff --git a/dist/aurelia-templating.js b/dist/aurelia-templating.js index 6c691f06..8402b587 100644 --- a/dist/aurelia-templating.js +++ b/dist/aurelia-templating.js @@ -266,6 +266,7 @@ export class BehaviorInstruction { instruction.host = host; instruction.viewModel = viewModel; instruction.viewFactory = viewFactory; + instruction.inheritBindingContext = true; return instruction; } @@ -286,6 +287,7 @@ export class BehaviorInstruction { this.attributes = null; this.type = null; this.attrName = null; + this.inheritBindingContext = false; } } @@ -2086,7 +2088,7 @@ export class BoundViewFactory { constructor(parentContainer: Container, viewFactory: ViewFactory, partReplacements?: Object) { this.parentContainer = parentContainer; this.viewFactory = viewFactory; - this.factoryCreateInstruction = { partReplacements: partReplacements }; + this.factoryCreateInstruction = { partReplacements: partReplacements }; //This is referenced internally in the controller's bind method. } /** @@ -3226,7 +3228,7 @@ export class Controller { this.isAttached = false; this.view = null; this.isBound = false; - this.bindingContext = null; + this.scope = null; let observerLookup = behavior.observerLocator.getOrCreateObserversLookup(viewModel); let handlesBind = behavior.handlesBind; @@ -3264,7 +3266,7 @@ export class Controller { this.view.overrideContext = overrideContext || createOverrideContext(this.viewModel); this.view._isUserControlled = true; - if(this.behavior.handlesCreated) { + if (this.behavior.handlesCreated) { this.viewModel.created(owningView || null, this.view); } @@ -3283,10 +3285,9 @@ export class Controller { let x; let observer; let selfSubscriber; - let context = scope.bindingContext; if (this.isBound) { - if (this.bindingContext === context) { + if (this.scope === scope) { return; } @@ -3294,7 +3295,7 @@ export class Controller { } this.isBound = true; - this.bindingContext = context; + this.scope = scope; for (i = 0, ii = boundProperties.length; i < ii; ++i) { x = boundProperties[i]; @@ -3313,14 +3314,40 @@ export class Controller { observer.selfSubscriber = selfSubscriber; } + let overrideContext; if (this.view !== null) { if (skipSelfSubscriber) { this.view.viewModelScope = scope; } - - this.view.bind(this.viewModel, createOverrideContext(this.viewModel, scope.overrideContext)); + // do we need to create an overrideContext or is the scope's overrideContext + // valid for this viewModel? + if (this.viewModel === scope.overrideContext.bindingContext) { + overrideContext = scope.overrideContext; + // should we inherit the parent scope? (eg compose / router) + } else if (this.instruction.inheritBindingContext) { + overrideContext = createOverrideContext(this.viewModel, scope.overrideContext); + // create the overrideContext and capture the parent without making it + // available to AccessScope. We may need it later for template-part replacements. + } else { + overrideContext = createOverrideContext(this.viewModel); + overrideContext.__parentOverrideContext = scope.overrideContext; + } + this.view.bind(this.viewModel, overrideContext); } else if (skipSelfSubscriber) { - this.viewModel.bind(context, scope.overrideContext); + overrideContext = scope.overrideContext; + // the factoryCreateInstruction's partReplacements will either be null or an object + // containing the replacements. If there are partReplacements we need to preserve the parent + // context to allow replacement parts to bind to both the custom element scope and the ambient scope. + // Note that factoryCreateInstruction is a property defined on BoundViewFactory. The code below assumes the + // behavior stores a the BoundViewFactory on its viewModel under the name of viewFactory. This is implemented + // by the replaceable custom attribute. + if (scope.overrideContext.__parentOverrideContext !== undefined + && this.viewModel.viewFactory && this.viewModel.viewFactory.factoryCreateInstruction.partReplacements) { + // clone the overrideContext and connect the ambient context. + overrideContext = Object.assign({}, scope.overrideContext); + overrideContext.parentOverrideContext = scope.overrideContext.__parentOverrideContext; + } + this.viewModel.bind(scope.bindingContext, overrideContext); } } @@ -3932,7 +3959,7 @@ export class HtmlBehaviorResource { node = template; } } else if (this.elementName !== null) { //custom element - let partReplacements = instruction.partReplacements = {}; + let partReplacements = {}; if (this.processContent(compiler, resources, node, instruction) && node.hasChildNodes()) { if (this.usesShadowDOM) { @@ -3946,6 +3973,7 @@ export class HtmlBehaviorResource { if (currentChild.tagName === 'TEMPLATE' && (toReplace = currentChild.getAttribute('replace-part'))) { partReplacements[toReplace] = compiler.compile(currentChild, resources); DOM.removeNode(currentChild, parentNode); + instruction.partReplacements = partReplacements; } currentChild = nextSibling; @@ -3964,6 +3992,7 @@ export class HtmlBehaviorResource { if (currentChild.tagName === 'TEMPLATE' && (toReplace = currentChild.getAttribute('replace-part'))) { partReplacements[toReplace] = compiler.compile(currentChild, resources); DOM.removeNode(currentChild, parentNode); + instruction.partReplacements = partReplacements; } else { fragment.appendChild(currentChild); } @@ -4144,14 +4173,14 @@ function createChildObserverDecorator(selectorOrConfig, all) { } /** -* Creates a behavior property that references an array of immediate content child elememnts that matches the provided selector. +* Creates a behavior property that references an array of immediate content child elements that matches the provided selector. */ export function children(selectorOrConfig: string | Object): any { return createChildObserverDecorator(selectorOrConfig, true); } /** -* Creates a behavior property that references an immediate content child elememnt that matches the provided selector. +* Creates a behavior property that references an immediate content child element that matches the provided selector. */ export function child(selectorOrConfig: string | Object): any { return createChildObserverDecorator(selectorOrConfig, false); diff --git a/dist/commonjs/aurelia-templating.d.ts b/dist/commonjs/aurelia-templating.d.ts index 775de511..2c2f9ae1 100644 --- a/dist/commonjs/aurelia-templating.d.ts +++ b/dist/commonjs/aurelia-templating.d.ts @@ -880,6 +880,7 @@ declare module 'aurelia-templating' { */ constructor(parentContainer: Container, viewFactory: ViewFactory, partReplacements?: Object); + // This is referenced internally in the controller's bind method. /** * Creates a view or returns one from the internal cache, if available. * @return The created view. @@ -1363,12 +1364,12 @@ declare module 'aurelia-templating' { } /** - * Creates a behavior property that references an array of immediate content child elememnts that matches the provided selector. + * Creates a behavior property that references an array of immediate content child elements that matches the provided selector. */ export function children(selectorOrConfig: string | Object): any; /** - * Creates a behavior property that references an immediate content child elememnt that matches the provided selector. + * Creates a behavior property that references an immediate content child element that matches the provided selector. */ export function child(selectorOrConfig: string | Object): any; class ChildObserver { diff --git a/dist/commonjs/aurelia-templating.js b/dist/commonjs/aurelia-templating.js index 57e532d1..6daf0b52 100644 --- a/dist/commonjs/aurelia-templating.js +++ b/dist/commonjs/aurelia-templating.js @@ -208,6 +208,7 @@ var BehaviorInstruction = (function () { instruction.host = host; instruction.viewModel = viewModel; instruction.viewFactory = viewFactory; + instruction.inheritBindingContext = true; return instruction; }; @@ -233,6 +234,7 @@ var BehaviorInstruction = (function () { this.attributes = null; this.type = null; this.attrName = null; + this.inheritBindingContext = false; } return BehaviorInstruction; @@ -2695,7 +2697,7 @@ var Controller = (function () { this.isAttached = false; this.view = null; this.isBound = false; - this.bindingContext = null; + this.scope = null; var observerLookup = behavior.observerLocator.getOrCreateObserversLookup(viewModel); var handlesBind = behavior.handlesBind; @@ -2738,10 +2740,9 @@ var Controller = (function () { var x = undefined; var observer = undefined; var selfSubscriber = undefined; - var context = scope.bindingContext; if (this.isBound) { - if (this.bindingContext === context) { + if (this.scope === scope) { return; } @@ -2749,7 +2750,7 @@ var Controller = (function () { } this.isBound = true; - this.bindingContext = context; + this.scope = scope; for (i = 0, ii = boundProperties.length; i < ii; ++i) { x = boundProperties[i]; @@ -2768,14 +2769,29 @@ var Controller = (function () { observer.selfSubscriber = selfSubscriber; } + var overrideContext = undefined; if (this.view !== null) { if (skipSelfSubscriber) { this.view.viewModelScope = scope; } - this.view.bind(this.viewModel, _aureliaBinding.createOverrideContext(this.viewModel, scope.overrideContext)); + if (this.viewModel === scope.overrideContext.bindingContext) { + overrideContext = scope.overrideContext; + } else if (this.instruction.inheritBindingContext) { + overrideContext = _aureliaBinding.createOverrideContext(this.viewModel, scope.overrideContext); + } else { + overrideContext = _aureliaBinding.createOverrideContext(this.viewModel); + overrideContext.__parentOverrideContext = scope.overrideContext; + } + this.view.bind(this.viewModel, overrideContext); } else if (skipSelfSubscriber) { - this.viewModel.bind(context, scope.overrideContext); + overrideContext = scope.overrideContext; + + if (scope.overrideContext.__parentOverrideContext !== undefined && this.viewModel.viewFactory && this.viewModel.viewFactory.factoryCreateInstruction.partReplacements) { + overrideContext = Object.assign({}, scope.overrideContext); + overrideContext.parentOverrideContext = scope.overrideContext.__parentOverrideContext; + } + this.viewModel.bind(scope.bindingContext, overrideContext); } }; @@ -3300,7 +3316,7 @@ var HtmlBehaviorResource = (function () { node = template; } } else if (this.elementName !== null) { - var _partReplacements2 = instruction.partReplacements = {}; + var _partReplacements2 = {}; if (this.processContent(compiler, resources, node, instruction) && node.hasChildNodes()) { if (this.usesShadowDOM) { @@ -3314,6 +3330,7 @@ var HtmlBehaviorResource = (function () { if (currentChild.tagName === 'TEMPLATE' && (toReplace = currentChild.getAttribute('replace-part'))) { _partReplacements2[toReplace] = compiler.compile(currentChild, resources); _aureliaPal.DOM.removeNode(currentChild, parentNode); + instruction.partReplacements = _partReplacements2; } currentChild = nextSibling; @@ -3332,6 +3349,7 @@ var HtmlBehaviorResource = (function () { if (currentChild.tagName === 'TEMPLATE' && (toReplace = currentChild.getAttribute('replace-part'))) { _partReplacements2[toReplace] = compiler.compile(currentChild, resources); _aureliaPal.DOM.removeNode(currentChild, parentNode); + instruction.partReplacements = _partReplacements2; } else { fragment.appendChild(currentChild); } diff --git a/dist/es6/aurelia-templating.d.ts b/dist/es6/aurelia-templating.d.ts index 775de511..2c2f9ae1 100644 --- a/dist/es6/aurelia-templating.d.ts +++ b/dist/es6/aurelia-templating.d.ts @@ -880,6 +880,7 @@ declare module 'aurelia-templating' { */ constructor(parentContainer: Container, viewFactory: ViewFactory, partReplacements?: Object); + // This is referenced internally in the controller's bind method. /** * Creates a view or returns one from the internal cache, if available. * @return The created view. @@ -1363,12 +1364,12 @@ declare module 'aurelia-templating' { } /** - * Creates a behavior property that references an array of immediate content child elememnts that matches the provided selector. + * Creates a behavior property that references an array of immediate content child elements that matches the provided selector. */ export function children(selectorOrConfig: string | Object): any; /** - * Creates a behavior property that references an immediate content child elememnt that matches the provided selector. + * Creates a behavior property that references an immediate content child element that matches the provided selector. */ export function child(selectorOrConfig: string | Object): any; class ChildObserver { diff --git a/dist/es6/aurelia-templating.js b/dist/es6/aurelia-templating.js index 6c691f06..8402b587 100644 --- a/dist/es6/aurelia-templating.js +++ b/dist/es6/aurelia-templating.js @@ -266,6 +266,7 @@ export class BehaviorInstruction { instruction.host = host; instruction.viewModel = viewModel; instruction.viewFactory = viewFactory; + instruction.inheritBindingContext = true; return instruction; } @@ -286,6 +287,7 @@ export class BehaviorInstruction { this.attributes = null; this.type = null; this.attrName = null; + this.inheritBindingContext = false; } } @@ -2086,7 +2088,7 @@ export class BoundViewFactory { constructor(parentContainer: Container, viewFactory: ViewFactory, partReplacements?: Object) { this.parentContainer = parentContainer; this.viewFactory = viewFactory; - this.factoryCreateInstruction = { partReplacements: partReplacements }; + this.factoryCreateInstruction = { partReplacements: partReplacements }; //This is referenced internally in the controller's bind method. } /** @@ -3226,7 +3228,7 @@ export class Controller { this.isAttached = false; this.view = null; this.isBound = false; - this.bindingContext = null; + this.scope = null; let observerLookup = behavior.observerLocator.getOrCreateObserversLookup(viewModel); let handlesBind = behavior.handlesBind; @@ -3264,7 +3266,7 @@ export class Controller { this.view.overrideContext = overrideContext || createOverrideContext(this.viewModel); this.view._isUserControlled = true; - if(this.behavior.handlesCreated) { + if (this.behavior.handlesCreated) { this.viewModel.created(owningView || null, this.view); } @@ -3283,10 +3285,9 @@ export class Controller { let x; let observer; let selfSubscriber; - let context = scope.bindingContext; if (this.isBound) { - if (this.bindingContext === context) { + if (this.scope === scope) { return; } @@ -3294,7 +3295,7 @@ export class Controller { } this.isBound = true; - this.bindingContext = context; + this.scope = scope; for (i = 0, ii = boundProperties.length; i < ii; ++i) { x = boundProperties[i]; @@ -3313,14 +3314,40 @@ export class Controller { observer.selfSubscriber = selfSubscriber; } + let overrideContext; if (this.view !== null) { if (skipSelfSubscriber) { this.view.viewModelScope = scope; } - - this.view.bind(this.viewModel, createOverrideContext(this.viewModel, scope.overrideContext)); + // do we need to create an overrideContext or is the scope's overrideContext + // valid for this viewModel? + if (this.viewModel === scope.overrideContext.bindingContext) { + overrideContext = scope.overrideContext; + // should we inherit the parent scope? (eg compose / router) + } else if (this.instruction.inheritBindingContext) { + overrideContext = createOverrideContext(this.viewModel, scope.overrideContext); + // create the overrideContext and capture the parent without making it + // available to AccessScope. We may need it later for template-part replacements. + } else { + overrideContext = createOverrideContext(this.viewModel); + overrideContext.__parentOverrideContext = scope.overrideContext; + } + this.view.bind(this.viewModel, overrideContext); } else if (skipSelfSubscriber) { - this.viewModel.bind(context, scope.overrideContext); + overrideContext = scope.overrideContext; + // the factoryCreateInstruction's partReplacements will either be null or an object + // containing the replacements. If there are partReplacements we need to preserve the parent + // context to allow replacement parts to bind to both the custom element scope and the ambient scope. + // Note that factoryCreateInstruction is a property defined on BoundViewFactory. The code below assumes the + // behavior stores a the BoundViewFactory on its viewModel under the name of viewFactory. This is implemented + // by the replaceable custom attribute. + if (scope.overrideContext.__parentOverrideContext !== undefined + && this.viewModel.viewFactory && this.viewModel.viewFactory.factoryCreateInstruction.partReplacements) { + // clone the overrideContext and connect the ambient context. + overrideContext = Object.assign({}, scope.overrideContext); + overrideContext.parentOverrideContext = scope.overrideContext.__parentOverrideContext; + } + this.viewModel.bind(scope.bindingContext, overrideContext); } } @@ -3932,7 +3959,7 @@ export class HtmlBehaviorResource { node = template; } } else if (this.elementName !== null) { //custom element - let partReplacements = instruction.partReplacements = {}; + let partReplacements = {}; if (this.processContent(compiler, resources, node, instruction) && node.hasChildNodes()) { if (this.usesShadowDOM) { @@ -3946,6 +3973,7 @@ export class HtmlBehaviorResource { if (currentChild.tagName === 'TEMPLATE' && (toReplace = currentChild.getAttribute('replace-part'))) { partReplacements[toReplace] = compiler.compile(currentChild, resources); DOM.removeNode(currentChild, parentNode); + instruction.partReplacements = partReplacements; } currentChild = nextSibling; @@ -3964,6 +3992,7 @@ export class HtmlBehaviorResource { if (currentChild.tagName === 'TEMPLATE' && (toReplace = currentChild.getAttribute('replace-part'))) { partReplacements[toReplace] = compiler.compile(currentChild, resources); DOM.removeNode(currentChild, parentNode); + instruction.partReplacements = partReplacements; } else { fragment.appendChild(currentChild); } @@ -4144,14 +4173,14 @@ function createChildObserverDecorator(selectorOrConfig, all) { } /** -* Creates a behavior property that references an array of immediate content child elememnts that matches the provided selector. +* Creates a behavior property that references an array of immediate content child elements that matches the provided selector. */ export function children(selectorOrConfig: string | Object): any { return createChildObserverDecorator(selectorOrConfig, true); } /** -* Creates a behavior property that references an immediate content child elememnt that matches the provided selector. +* Creates a behavior property that references an immediate content child element that matches the provided selector. */ export function child(selectorOrConfig: string | Object): any { return createChildObserverDecorator(selectorOrConfig, false); diff --git a/dist/system/aurelia-templating.d.ts b/dist/system/aurelia-templating.d.ts index 775de511..2c2f9ae1 100644 --- a/dist/system/aurelia-templating.d.ts +++ b/dist/system/aurelia-templating.d.ts @@ -880,6 +880,7 @@ declare module 'aurelia-templating' { */ constructor(parentContainer: Container, viewFactory: ViewFactory, partReplacements?: Object); + // This is referenced internally in the controller's bind method. /** * Creates a view or returns one from the internal cache, if available. * @return The created view. @@ -1363,12 +1364,12 @@ declare module 'aurelia-templating' { } /** - * Creates a behavior property that references an array of immediate content child elememnts that matches the provided selector. + * Creates a behavior property that references an array of immediate content child elements that matches the provided selector. */ export function children(selectorOrConfig: string | Object): any; /** - * Creates a behavior property that references an immediate content child elememnt that matches the provided selector. + * Creates a behavior property that references an immediate content child element that matches the provided selector. */ export function child(selectorOrConfig: string | Object): any; class ChildObserver { diff --git a/dist/system/aurelia-templating.js b/dist/system/aurelia-templating.js index bc8b33c7..90bd7572 100644 --- a/dist/system/aurelia-templating.js +++ b/dist/system/aurelia-templating.js @@ -806,6 +806,7 @@ System.register(['core-js', 'aurelia-logging', 'aurelia-metadata', 'aurelia-path instruction.host = host; instruction.viewModel = viewModel; instruction.viewFactory = viewFactory; + instruction.inheritBindingContext = true; return instruction; }; @@ -831,6 +832,7 @@ System.register(['core-js', 'aurelia-logging', 'aurelia-metadata', 'aurelia-path this.attributes = null; this.type = null; this.attrName = null; + this.inheritBindingContext = false; } return BehaviorInstruction; @@ -2985,7 +2987,7 @@ System.register(['core-js', 'aurelia-logging', 'aurelia-metadata', 'aurelia-path this.isAttached = false; this.view = null; this.isBound = false; - this.bindingContext = null; + this.scope = null; var observerLookup = behavior.observerLocator.getOrCreateObserversLookup(viewModel); var handlesBind = behavior.handlesBind; @@ -3028,10 +3030,9 @@ System.register(['core-js', 'aurelia-logging', 'aurelia-metadata', 'aurelia-path var x = undefined; var observer = undefined; var selfSubscriber = undefined; - var context = scope.bindingContext; if (this.isBound) { - if (this.bindingContext === context) { + if (this.scope === scope) { return; } @@ -3039,7 +3040,7 @@ System.register(['core-js', 'aurelia-logging', 'aurelia-metadata', 'aurelia-path } this.isBound = true; - this.bindingContext = context; + this.scope = scope; for (i = 0, ii = boundProperties.length; i < ii; ++i) { x = boundProperties[i]; @@ -3058,14 +3059,29 @@ System.register(['core-js', 'aurelia-logging', 'aurelia-metadata', 'aurelia-path observer.selfSubscriber = selfSubscriber; } + var overrideContext = undefined; if (this.view !== null) { if (skipSelfSubscriber) { this.view.viewModelScope = scope; } - this.view.bind(this.viewModel, createOverrideContext(this.viewModel, scope.overrideContext)); + if (this.viewModel === scope.overrideContext.bindingContext) { + overrideContext = scope.overrideContext; + } else if (this.instruction.inheritBindingContext) { + overrideContext = createOverrideContext(this.viewModel, scope.overrideContext); + } else { + overrideContext = createOverrideContext(this.viewModel); + overrideContext.__parentOverrideContext = scope.overrideContext; + } + this.view.bind(this.viewModel, overrideContext); } else if (skipSelfSubscriber) { - this.viewModel.bind(context, scope.overrideContext); + overrideContext = scope.overrideContext; + + if (scope.overrideContext.__parentOverrideContext !== undefined && this.viewModel.viewFactory && this.viewModel.viewFactory.factoryCreateInstruction.partReplacements) { + overrideContext = Object.assign({}, scope.overrideContext); + overrideContext.parentOverrideContext = scope.overrideContext.__parentOverrideContext; + } + this.viewModel.bind(scope.bindingContext, overrideContext); } }; @@ -3567,7 +3583,7 @@ System.register(['core-js', 'aurelia-logging', 'aurelia-metadata', 'aurelia-path node = template; } } else if (this.elementName !== null) { - var _partReplacements2 = instruction.partReplacements = {}; + var _partReplacements2 = {}; if (this.processContent(compiler, resources, node, instruction) && node.hasChildNodes()) { if (this.usesShadowDOM) { @@ -3581,6 +3597,7 @@ System.register(['core-js', 'aurelia-logging', 'aurelia-metadata', 'aurelia-path if (currentChild.tagName === 'TEMPLATE' && (toReplace = currentChild.getAttribute('replace-part'))) { _partReplacements2[toReplace] = compiler.compile(currentChild, resources); DOM.removeNode(currentChild, parentNode); + instruction.partReplacements = _partReplacements2; } currentChild = nextSibling; @@ -3599,6 +3616,7 @@ System.register(['core-js', 'aurelia-logging', 'aurelia-metadata', 'aurelia-path if (currentChild.tagName === 'TEMPLATE' && (toReplace = currentChild.getAttribute('replace-part'))) { _partReplacements2[toReplace] = compiler.compile(currentChild, resources); DOM.removeNode(currentChild, parentNode); + instruction.partReplacements = _partReplacements2; } else { fragment.appendChild(currentChild); } diff --git a/doc/CHANGELOG.md b/doc/CHANGELOG.md index 9643aafd..d947b1a6 100644 --- a/doc/CHANGELOG.md +++ b/doc/CHANGELOG.md @@ -1,3 +1,17 @@ +### 1.0.0-beta.1.1.0 (2016-01-29) + + +#### Bug Fixes + +* **Controller:** handle scope inheritance in template part with repeat Related to #244 ([9a488c44](http://github.com/aurelia/templating/commit/9a488c44e86872c91b2f86953519c8ef7308a262)) +* **controller:** stop element from inheriting scope ([a3ced53d](http://github.com/aurelia/templating/commit/a3ced53d67749244a6ea61d5193b04330e392bfc)) + + +#### Features + +* **all:** update jspm meta; core-js; aurelia-deps ([bdff3232](http://github.com/aurelia/templating/commit/bdff323282ebd7228063cb08a961a3258215fcea)) + + ### 1.0.0-beta.1.0.3 (2016-01-08) diff --git a/doc/api.json b/doc/api.json index 317a3b7d..5ddb90d8 100644 --- a/doc/api.json +++ b/doc/api.json @@ -902,7 +902,7 @@ "type": { "type": "reference", "name": "TaskQueue", - "id": 1596, + "id": 1603, "moduleName": "\"aurelia-task-queue\"" } }, @@ -1747,7 +1747,7 @@ "type": { "type": "reference", "name": "Container", - "id": 1153, + "id": 1159, "moduleName": "\"aurelia-dependency-injection\"" } }, @@ -3053,7 +3053,7 @@ "type": { "type": "reference", "name": "Origin", - "id": 1410, + "id": 1416, "moduleName": "\"aurelia-metadata\"" } } @@ -3213,7 +3213,7 @@ "type": { "type": "reference", "name": "Container", - "id": 1153, + "id": 1159, "moduleName": "\"aurelia-dependency-injection\"" } }, @@ -3270,7 +3270,7 @@ "type": { "type": "reference", "name": "Container", - "id": 1153, + "id": 1159, "moduleName": "\"aurelia-dependency-injection\"" } }, @@ -3589,7 +3589,7 @@ "type": { "type": "reference", "name": "Container", - "id": 1153, + "id": 1159, "moduleName": "\"aurelia-dependency-injection\"" } }, @@ -3687,7 +3687,7 @@ "type": { "type": "reference", "name": "Container", - "id": 1153, + "id": 1159, "moduleName": "\"aurelia-dependency-injection\"" } }, @@ -3744,7 +3744,7 @@ "type": { "type": "reference", "name": "Container", - "id": 1153, + "id": 1159, "moduleName": "\"aurelia-dependency-injection\"" } }, @@ -4611,7 +4611,7 @@ "type": { "type": "reference", "name": "Container", - "id": 1153, + "id": 1159, "moduleName": "\"aurelia-dependency-injection\"" } }, @@ -5126,7 +5126,7 @@ "type": { "type": "reference", "name": "Container", - "id": 1153, + "id": 1159, "moduleName": "\"aurelia-dependency-injection\"" } } @@ -5170,7 +5170,7 @@ "type": { "type": "reference", "name": "Container", - "id": 1153, + "id": 1159, "moduleName": "\"aurelia-dependency-injection\"" } }, @@ -5524,7 +5524,7 @@ "type": { "type": "reference", "name": "Container", - "id": 1153, + "id": 1159, "moduleName": "\"aurelia-dependency-injection\"" } } @@ -5568,7 +5568,7 @@ "type": { "type": "reference", "name": "Container", - "id": 1153, + "id": 1159, "moduleName": "\"aurelia-dependency-injection\"" } }, @@ -6238,7 +6238,7 @@ "type": { "type": "reference", "name": "TemplateRegistryEntry", - "id": 1259, + "id": 1265, "moduleName": "\"aurelia-loader\"" } } @@ -6401,7 +6401,7 @@ "type": { "type": "reference", "name": "Container", - "id": 1153, + "id": 1159, "moduleName": "\"aurelia-dependency-injection\"" } }, @@ -7628,7 +7628,7 @@ "type": { "type": "reference", "name": "Loader", - "id": 1274, + "id": 1280, "moduleName": "\"aurelia-loader\"" } }, @@ -7644,7 +7644,7 @@ "type": { "type": "reference", "name": "Container", - "id": 1153, + "id": 1159, "moduleName": "\"aurelia-dependency-injection\"" } }, @@ -7970,7 +7970,7 @@ "type": { "type": "reference", "name": "TemplateRegistryEntry", - "id": 1259, + "id": 1265, "moduleName": "\"aurelia-loader\"" } }, @@ -8064,7 +8064,7 @@ { "type": "reference", "name": "TemplateRegistryEntry", - "id": 1259 + "id": 1265 } ] } @@ -8278,7 +8278,7 @@ "type": { "type": "reference", "name": "Container", - "id": 1153, + "id": 1159, "moduleName": "\"aurelia-dependency-injection\"" } }, @@ -8550,7 +8550,7 @@ "type": { "type": "reference", "name": "Origin", - "id": 1410, + "id": 1416, "moduleName": "\"aurelia-metadata\"" } } @@ -8594,7 +8594,7 @@ "type": { "type": "reference", "name": "Origin", - "id": 1410, + "id": 1416, "moduleName": "\"aurelia-metadata\"" } } @@ -10133,7 +10133,7 @@ "type": { "type": "reference", "name": "Container", - "id": 1153 + "id": 1159 } }, { @@ -10150,7 +10150,7 @@ "type": { "type": "reference", "name": "Container", - "id": 1153 + "id": 1159 } }, { @@ -10384,7 +10384,7 @@ "type": { "type": "reference", "name": "Container", - "id": 1153 + "id": 1159 } }, { @@ -10780,7 +10780,7 @@ "type": { "type": "reference", "name": "Container", - "id": 1153 + "id": 1159 } }, { @@ -11270,7 +11270,7 @@ "kindString": "Call signature", "flags": {}, "comment": { - "shortText": "Creates a behavior property that references an immediate content child elememnt that matches the provided selector." + "shortText": "Creates a behavior property that references an immediate content child element that matches the provided selector." }, "parameters": [ { @@ -11317,7 +11317,7 @@ "kindString": "Call signature", "flags": {}, "comment": { - "shortText": "Creates a behavior property that references an array of immediate content child elememnts that matches the provided selector." + "shortText": "Creates a behavior property that references an array of immediate content child elements that matches the provided selector." }, "parameters": [ { diff --git a/package.json b/package.json index 68972172..55489304 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "aurelia-templating", - "version": "1.0.0-beta.1.0.3", + "version": "1.0.0-beta.1.1.0", "description": "An extensible HTML templating engine supporting databinding, custom elements, attached behaviors and more.", "keywords": [ "aurelia",