diff --git a/src/view-compiler.js b/src/view-compiler.js index cb60f0ee..889aed24 100644 --- a/src/view-compiler.js +++ b/src/view-compiler.js @@ -94,7 +94,7 @@ export class ViewCompiler { } compileInstruction.targetShadowDOM = compileInstruction.targetShadowDOM && FEATURE.shadowDOM; - resources._onBeforeCompile(content, resources, compileInstruction); + resources._invokeHook('beforeCompile', content, resources, compileInstruction); let instructions = {}; this._compileNode(content, resources, instructions, source, 'root', !compileInstruction.targetShadowDOM); @@ -110,7 +110,7 @@ export class ViewCompiler { factory.setCacheSize(cacheSize); } - resources._onAfterCompile(factory); + resources._invokeHook('afterCompile', factory); return factory; } diff --git a/src/view-factory.js b/src/view-factory.js index 19b600dd..b7f838e1 100644 --- a/src/view-factory.js +++ b/src/view-factory.js @@ -417,7 +417,7 @@ export class ViewFactory { let instructable; let instruction; - this.resources._onBeforeCreate(this, container, fragment, createInstruction); + this.resources._invokeHook('beforeCreate', this, container, fragment, createInstruction); if (element !== null && this.surrogateInstruction !== null) { applySurrogateInstruction(container, element, this.surrogateInstruction, controllers, bindings, children); @@ -437,7 +437,7 @@ export class ViewFactory { view.created(); } - this.resources._onAfterCreate(view); + this.resources._invokeHook('afterCreate', view); return view; } diff --git a/src/view-resources.js b/src/view-resources.js index 069634ff..c6a687f6 100644 --- a/src/view-resources.js +++ b/src/view-resources.js @@ -1,7 +1,6 @@ import {relativeToFile} from 'aurelia-path'; import {HtmlBehaviorResource} from './html-behavior'; import {BindingLanguage} from './binding-language'; -import {PLATFORM} from 'aurelia-pal'; import {ViewCompileInstruction, ViewCreateInstruction} from './instructions'; function register(lookup, name, resource, type) { @@ -50,6 +49,18 @@ interface ViewEngineHooks { * @param view The view that was created by the factory. */ afterCreate?: (view: View) => void; + + /** + * Invoked after the bindingContext and overrideContext are configured on the view but before the view is bound. + * @param view The view that was created by the factory. + */ + beforeBind?: (view: View) => void; + + /** + * Invoked before the view is unbind. The bindingContext and overrideContext are still available on the view. + * @param view The view that was created by the factory. + */ + beforeUnbind?: (view: View) => void; } /** @@ -79,106 +90,45 @@ export class ViewResources { this.valueConverters = {}; this.bindingBehaviors = {}; this.attributeMap = {}; - this.hook1 = null; - this.hook2 = null; - this.hook3 = null; - this.additionalHooks = null; + this.beforeCompile = this.afterCompile = this.beforeCreate = this.afterCreate = this.beforeBind = this.beforeUnbind = false; } - _onBeforeCompile(content: DocumentFragment, resources: ViewResources, instruction: ViewCompileInstruction): void { - if (this.hasParent) { - this.parent._onBeforeCompile(content, resources, instruction); - } - - if (this.hook1 !== null) { - this.hook1.beforeCompile(content, resources, instruction); - - if (this.hook2 !== null) { - this.hook2.beforeCompile(content, resources, instruction); - - if (this.hook3 !== null) { - this.hook3.beforeCompile(content, resources, instruction); + _tryAddHook(obj, name) { + if (typeof obj[name] === 'function') { + let func = obj[name].bind(obj); + let counter = 1; + let callbackName; - if (this.additionalHooks !== null) { - let hooks = this.additionalHooks; - for (let i = 0, length = hooks.length; i < length; ++i) { - hooks[i].beforeCompile(content, resources, instruction); - } - } - } + while (this[callbackName = name + counter.toString()] !== undefined) { + counter++; } - } - } - - _onAfterCompile(viewFactory: ViewFactory): void { - if (this.hasParent) { - this.parent._onAfterCompile(viewFactory); - } - if (this.hook1 !== null) { - this.hook1.afterCompile(viewFactory); - - if (this.hook2 !== null) { - this.hook2.afterCompile(viewFactory); - - if (this.hook3 !== null) { - this.hook3.afterCompile(viewFactory); - - if (this.additionalHooks !== null) { - let hooks = this.additionalHooks; - for (let i = 0, length = hooks.length; i < length; ++i) { - hooks[i].afterCompile(viewFactory); - } - } - } - } + this[name] = true; + this[callbackName] = func; } } - _onBeforeCreate(viewFactory: ViewFactory, container: Container, content: DocumentFragment, instruction: ViewCreateInstruction, bindingContext?:Object): void { + _invokeHook(name, one, two, three, four) { if (this.hasParent) { - this.parent._onBeforeCreate(viewFactory, container, content, instruction, bindingContext); - } - - if (this.hook1 !== null) { - this.hook1.beforeCreate(viewFactory, container, content, instruction, bindingContext); - - if (this.hook2 !== null) { - this.hook2.beforeCreate(viewFactory, container, content, instruction, bindingContext); - - if (this.hook3 !== null) { - this.hook3.beforeCreate(viewFactory, container, content, instruction, bindingContext); - - if (this.additionalHooks !== null) { - let hooks = this.additionalHooks; - for (let i = 0, length = hooks.length; i < length; ++i) { - hooks[i].beforeCreate(viewFactory, container, content, instruction, bindingContext); - } - } - } - } + this.parent._invokeHook(name, one, two, three, four); } - } - _onAfterCreate(view: View): void { - if (this.hasParent) { - this.parent._onAfterCreate(view); - } + if (this[name]) { + this[name + '1'](one, two, three, four); - if (this.hook1 !== null) { - this.hook1.afterCreate(view); + let callbackName = name + '2'; + if (this[callbackName]) { + this[callbackName](one, two, three, four); - if (this.hook2 !== null) { - this.hook2.afterCreate(view); + callbackName = name + '3'; + if (this[callbackName]) { + this[callbackName](one, two, three, four); - if (this.hook3 !== null) { - this.hook3.afterCreate(view); + let counter = 4; - if (this.additionalHooks !== null) { - let hooks = this.additionalHooks; - for (let i = 0, length = hooks.length; i < length; ++i) { - hooks[i].afterCreate(view); - } + while (this[callbackName = name + counter.toString()] !== undefined) { + this[callbackName](one, two, three, four); + counter++; } } } @@ -190,21 +140,12 @@ export class ViewResources { * @param hooks The hooks to register. */ registerViewEngineHooks(hooks:ViewEngineHooks): void { - if (hooks.beforeCompile === undefined) hooks.beforeCompile = PLATFORM.noop; - if (hooks.afterCompile === undefined) hooks.afterCompile = PLATFORM.noop; - if (hooks.beforeCreate === undefined) hooks.beforeCreate = PLATFORM.noop; - if (hooks.afterCreate === undefined) hooks.afterCreate = PLATFORM.noop; - - if (this.hook1 === null) this.hook1 = hooks; - else if (this.hook2 === null) this.hook2 = hooks; - else if (this.hook3 === null) this.hook3 = hooks; - else { - if (this.additionalHooks === null) { - this.additionalHooks = []; - } - - this.additionalHooks.push(hooks); - } + this._tryAddHook(hooks, 'beforeCompile'); + this._tryAddHook(hooks, 'afterCompile'); + this._tryAddHook(hooks, 'beforeCreate'); + this._tryAddHook(hooks, 'afterCreate'); + this._tryAddHook(hooks, 'beforeBind'); + this._tryAddHook(hooks, 'beforeUnbind'); } /** diff --git a/src/view.js b/src/view.js index 639a6a39..69c63e33 100644 --- a/src/view.js +++ b/src/view.js @@ -35,6 +35,7 @@ export class View { */ constructor(viewFactory: ViewFactory, fragment: DocumentFragment, controllers: Controller[], bindings: Binding[], children: ViewNode[], contentSelectors: Array) { this.viewFactory = viewFactory; + this.resources = viewFactory.resources; this.fragment = fragment; this.controllers = controllers; this.bindings = bindings; @@ -101,6 +102,8 @@ export class View { this.bindingContext = bindingContext; this.overrideContext = overrideContext || createOverrideContext(bindingContext); + this.resources._invokeHook('beforeBind', this); + bindings = this.bindings; for (i = 0, ii = bindings.length; i < ii; ++i) { bindings[i].bind(this); @@ -146,6 +149,8 @@ export class View { if (this.isBound) { this.isBound = false; + this.resources._invokeHook('beforeUnbind', this); + this.bindingContext = null; this.overrideContext = null;