import { ViewFactory, ViewSlot } from 'aurelia-templating'; /** * For internal use only. May change without warning. */ export class IfCore { /** * @internal */ viewFactory: ViewFactory; /** * @internal */ viewSlot: ViewSlot; /** * @internal */ view: any; /** * @internal */ bindingContext: any; /** * @internal */ overrideContext: any; /** * @internal */ showing: boolean; /** * @internal */ cache: boolean | string; constructor(viewFactory: ViewFactory, viewSlot: ViewSlot) { this.viewFactory = viewFactory; this.viewSlot = viewSlot; this.view = null; this.bindingContext = null; this.overrideContext = null; // If the child view is animated, `value` might not reflect the internal // state anymore, so we use `showing` for that. // Eventually, `showing` and `value` should be consistent. this.showing = false; this.cache = true; } bind(bindingContext, overrideContext) { // Store parent bindingContext, so we can pass it down this.bindingContext = bindingContext; this.overrideContext = overrideContext; } unbind() { if (this.view === null) { return; } this.view.unbind(); // It seems to me that this code is subject to race conditions when animating. // For example a view could be returned to the cache and reused while it's still // attached to the DOM and animated. if (!this.viewFactory.isCaching) { return; } if (this.showing) { this.showing = false; this.viewSlot.remove(this.view, /*returnToCache:*/true, /*skipAnimation:*/true); } else { this.view.returnToCache(); } this.view = null; } /** * @internal */ _show() { if (this.showing) { // Ensures the view is bound. // It might not be the case when the if was unbound but not detached, then rebound. // Typical case where this happens is nested ifs if (!this.view.isBound) { this.view.bind(this.bindingContext, this.overrideContext); } return; } if (this.view === null) { this.view = (this.viewFactory as any).create(); } if (!this.view.isBound) { this.view.bind(this.bindingContext, this.overrideContext); } this.showing = true; return this.viewSlot.add(this.view); // Promise or void } /** * @internal */ _hide() { if (!this.showing) { return; } this.showing = false; let removed = this.viewSlot.remove(this.view); // Promise or View if (removed instanceof Promise) { return removed.then(() => { this._unbindView(); }); } this._unbindView(); } /** * @internal */ _unbindView() { const cache = this.cache === 'false' ? false : !!this.cache; this.view.unbind(); if (!cache) { this.view = null; } } }