UNPKG

aurelia-hot-module-reload

Version:

Tools designed to enable HMR for Aurelia's loaders.

102 lines (101 loc) 4.37 kB
import { TargetInstruction } from 'aurelia-templating'; export function recreateView(viewFactory, oldViewContainer) { let parentContainer = oldViewContainer.parent || oldViewContainer; const targetInstruction = oldViewContainer.get(TargetInstruction); // const targetInstruction = container.get(TargetInstruction) as TargetInstruction; let factoryCreateInstruction = targetInstruction.elementInstruction || { partReplacements: null }; // let factoryCreateInstruction = ({partReplacements: null} as BehaviorInstruction); // console.log(`new element instruction`, targetInstruction, factoryCreateInstruction); const newContainer = parentContainer.createChild(); newContainer._resolvers = oldViewContainer._resolvers; // const newContainer = oldViewContainer; const newView = viewFactory.create(newContainer, factoryCreateInstruction); newView._isUserControlled = true; return newView; } export function cleanupView(view) { const firstChild = view.firstChild; const lastChild = view.lastChild; const nextSibling = lastChild.nextSibling; const parent = firstChild.parentElement; const { bindingContext, overrideContext, container } = view; view.removeNodes(); let wasAttached = view.isAttached; if (wasAttached) { view.detached(); } let wasBound = view.isBound; if (wasBound) { view.unbind(); } view._invalidView = true; return { nextSibling, parent, wasBound, wasAttached, bindingContext, overrideContext, container }; } export function rerenderController(e, type, newViewFactory) { let oldView = e[type]; if (!oldView) { // view was removed from the controller in a previous run, ignore return; } if (oldView._invalidView) { // previously re-rendered, ensure controller is set and skip if (oldView._replacementView) { e[type] = oldView._replacementView; } return; } const { nextSibling, parent, wasBound, wasAttached, bindingContext, overrideContext, container: oldViewContainer } = cleanupView(oldView); // create & add view: const newView = oldView._replacementView = e[type] = recreateView(newViewFactory || oldView.viewFactory, oldViewContainer); if (!newView.isBound && wasBound) { newView.bind(bindingContext, overrideContext); } if (nextSibling) { newView.insertNodesBefore(nextSibling); } else { newView.appendNodesTo(parent); } if (!newView.isAttached && wasAttached) { newView.attached(); } } export function rerenderMatchingSlotChildren(slot, newViewFactory, originalFactoryTemplate, onlyViews) { const previousChildren = slot.children.slice(); const viewsToReplace = previousChildren.filter(view => (onlyViews && onlyViews.indexOf(view) >= 0) || (view.viewFactory && view.viewFactory.template === originalFactoryTemplate)); const bindingContexts = new Map(); const overrideContexts = new Map(); const controllers = new Map(); viewsToReplace.forEach(oldView => { // store contexts because they'll be removed when unbound: bindingContexts.set(oldView, oldView.bindingContext); overrideContexts.set(oldView, oldView.overrideContext); controllers.set(oldView, oldView.controller); if (oldView.isBound) { oldView.unbind(); } oldView._invalidView = true; }); slot.removeMany(viewsToReplace, false, true); // recreate removed Views in the same place: previousChildren.forEach((oldView, index) => { if (!oldView._invalidView) { // don't do anything to non-matching Views return; } const bindingContext = bindingContexts.get(oldView); const overrideContext = overrideContexts.get(oldView); const controller = controllers.get(oldView); const view = recreateView(newViewFactory || oldView.viewFactory, oldView.container); // setup _replacementView in case the same view is looped over again oldView._replacementView = view; if (controller) { controller.view = view; } if (!view.isBound) { view.bind(bindingContext, overrideContext); } // indicies should match up and grow as we iterate up slot.insert(index, view); }); }