Created
July 28, 2016 22:56
-
-
Save Vaccano/1e862b9318f4f0a9a8e1176ff4fb727e to your computer and use it in GitHub Desktop.
Screen Caching
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import {autoinject} from 'aurelia-dependency-injection'; | |
import {CompositionEngine, CompositionContext, ViewEngine} from 'aurelia-templating'; | |
import {RouteLoader, Router} from 'aurelia-router'; | |
import {relativeToFile} from 'aurelia-path'; | |
import {Origin} from 'aurelia-metadata'; | |
import {ViewModelCache} from '../../../src/cache/screen-cache/view-model-cache'; | |
import {ViewCache} from '../../../src/cache/screen-cache/view-cache'; | |
@autoinject | |
export class CachedRouteLoader extends RouteLoader { | |
constructor(compositionEngine: CompositionEngine, viewModelCache: ViewModelCache, viewEngine: ViewEngine, viewCache: ViewCache) { | |
super(); | |
this.compositionEngine = compositionEngine; | |
this.viewModelCache = viewModelCache; | |
this.viewEngine = viewEngine; | |
this.viewCache = viewCache; | |
} | |
private compositionEngine: CompositionEngine; | |
private viewModelCache: ViewModelCache; | |
private viewEngine: ViewEngine; | |
private viewCache: ViewCache; | |
loadRoute(router, config, navigationInstruction) { | |
let childContainer = router.container.createChild(); | |
let instruction = { | |
viewModel: relativeToFile(config.moduleId, Origin.get(router.container.viewModel.constructor).moduleId), | |
childContainer: childContainer, | |
view: config.view || config.viewStrategy, | |
router: router, | |
container: undefined, | |
bindingContext: undefined, | |
viewResources: undefined, | |
viewSlot: undefined | |
}; | |
childContainer.getChildRouter = function () { | |
let childRouter; | |
childContainer.registerHandler(Router, c => { | |
return childRouter || (childRouter = router.createChild(childContainer)); | |
}); | |
return childContainer.get(Router); | |
}; | |
return this.viewEngine.importViewModelResource(instruction.viewModel, undefined).then(viewModelResource => { | |
childContainer.autoRegister(viewModelResource["value"]); | |
let viewModel = null; | |
//some cache name | |
let cacheName = config.moduleId + ";" + navigationInstruction.fragment; | |
//cache magic | |
viewModel = this.viewModelCache.getViewModel(cacheName); | |
if (viewModel) { | |
//if there is a viewmodel in cache, do not activate it | |
viewModel.activate = () => { | |
return true; | |
} | |
} | |
//viewmodel not found in cache, let aurelia create one | |
if (!viewModel) | |
viewModel = childContainer.get(viewModelResource["value"]); | |
//cache if needed | |
this.viewModelCache.setViewModel(cacheName, viewModel); | |
instruction.viewModel = childContainer.viewModel = viewModel; | |
instruction["viewModelResource"] = viewModelResource; | |
return instruction; | |
}); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import {Container, inject, autoinject } from 'aurelia-framework'; | |
import {ViewSlot, ViewLocator, customElement, noView, BehaviorInstruction, bindable, ViewFactory, ViewResources, View, ViewCreateInstruction} from 'aurelia-templating'; | |
import {Router} from 'aurelia-router'; | |
import {Origin} from 'aurelia-metadata'; | |
import {DOM} from 'aurelia-pal'; | |
import {ViewCache} from '../../../src/cache/screen-cache/view-cache'; | |
import {SwapStrategies} from '../../../src/cache/screen-cache/swap-strategies'; | |
import {CachedViewFactory} from '../../../src/cache/screen-cache/cached-view-factory'; | |
const swapStrategies = new SwapStrategies(); | |
@customElement('cached-router-view') | |
@noView | |
@inject(DOM.Element, Container, ViewSlot, Router, ViewLocator, ViewCache, CachedViewFactory) | |
export class CachedRouterView { | |
@bindable swapOrder; | |
public owningView: any; | |
public overrideContext: any; | |
public view: any; | |
constructor(public element, public container, public viewSlot, public router, public viewLocator, private viewCache, private cacheViewFactory) { | |
this.router.registerViewPort(this, this.element.getAttribute('name')); | |
} | |
created(owningView) { | |
this.owningView = owningView; | |
} | |
bind(bindingContext, overrideContext) { | |
this.container.viewModel = bindingContext; | |
this.overrideContext = overrideContext; | |
} | |
process(viewPortInstruction, waitToSwap) { | |
let component = viewPortInstruction.component; | |
let childContainer = component.childContainer; | |
let viewModel = component.viewModel; | |
let viewModelResource = component.viewModelResource; | |
let metadata = viewModelResource.metadata; | |
let viewStrategy = this.viewLocator.getViewStrategy(component.view || viewModel); | |
if (viewStrategy) { | |
viewStrategy.makeRelativeTo(Origin.get(component.router.container.viewModel.constructor).moduleId); | |
} | |
return metadata.load(childContainer, viewModelResource.value, null, viewStrategy, true).then(viewFactory => { | |
//set cache name | |
let cacheName: string = viewPortInstruction.moduleId; | |
if (!this.includes(cacheName, '/index')) { | |
cacheName = cacheName + ';' + viewPortInstruction.lifecycleArgs[2].fragment; | |
} | |
//swap view factory with custom one | |
Object.assign(this.cacheViewFactory, viewFactory); | |
let ins = BehaviorInstruction.dynamic( | |
this.element, | |
viewModel, | |
this.cacheViewFactory | |
); | |
ins["cachedName"] = "view;" + cacheName; | |
viewPortInstruction.controller = metadata.create(childContainer, ins); | |
if (waitToSwap) { | |
return; | |
} | |
this.swap(viewPortInstruction); | |
}); | |
} | |
swap(viewPortInstruction) { | |
let previousView = this.view; | |
let viewSlot = this.viewSlot; | |
let swapStrategy = this.swapOrder in swapStrategies | |
? swapStrategies[this.swapOrder] | |
: swapStrategies.after; | |
swapStrategy(viewSlot, previousView, () => { | |
viewPortInstruction.controller.automate(this.overrideContext, this.owningView); | |
return viewSlot.add(viewPortInstruction.controller.view); | |
}); | |
this.view = viewPortInstruction.controller.view; | |
} | |
includes(source: string, search: string, start: number = 0): boolean { | |
'use strict'; | |
if (typeof start !== 'number') { | |
start = 0; | |
} | |
if (start + search.length > source.length) { | |
return false; | |
} else { | |
return source.indexOf(search, start) !== -1; | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import {Container, autoinject } from 'aurelia-framework'; | |
import {ViewFactory, ViewResources, ViewCreateInstruction, View} from 'aurelia-templating'; | |
import {ViewCache} from '../../../src/cache/screen-cache/view-cache'; | |
export class CacheViewCreateInstruction implements ViewCreateInstruction { | |
public cachedName: string; | |
} | |
@autoinject | |
export class CachedViewFactory extends ViewFactory { | |
constructor(template: DocumentFragment, instructions: Object, resources: ViewResources, private viewCache: ViewCache) { | |
super(template, instructions, resources); | |
} | |
public create(container: Container, createInstruction?: CacheViewCreateInstruction, element?: Element): View { | |
let view; | |
if (createInstruction) { | |
//try and find view in cache | |
view = this.viewCache.getView(createInstruction.cachedName); | |
} | |
if (view) { | |
//return cached view | |
return view; | |
} | |
//create new view if not found in cache | |
view = super.create(container, createInstruction, element); | |
if (createInstruction) { | |
//add to cache | |
this.viewCache.setView(createInstruction.cachedName, view); | |
} | |
return view; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import {CachedRouteLoader} from '../src/cache/screen-cache/cached-route-loader'; | |
import {RouteLoader} from 'aurelia-router'; | |
import {Aurelia} from 'aurelia-framework'; | |
// Other Imports needed | |
bootstrap((aurelia: Aurelia): void => { | |
aurelia.use | |
.standardConfiguration() | |
.developmentLogging()); | |
// This is the relevant part. This replaces the loader with the cached loader. | |
aurelia.container.registerSingleton(RouteLoader, CachedRouteLoader); | |
// Other stuff for file. | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export class SwapStrategies { | |
// animate the next view in before removing the current view; | |
before(viewSlot, previousView, callback) { | |
let promise = Promise.resolve(callback()); | |
if (previousView !== undefined) { | |
return promise.then(() => viewSlot.remove(previousView, true)); | |
} | |
return promise; | |
} | |
// animate the next view at the same time the current view is removed | |
with(viewSlot, previousView, callback) { | |
let promise = Promise.resolve(callback()); | |
if (previousView !== undefined) { | |
return Promise.all([viewSlot.remove(previousView, true), promise]); | |
} | |
return promise; | |
} | |
// animate the next view in after the current view has been removed | |
after(viewSlot, previousView, callback) { | |
return Promise.resolve(viewSlot.removeAll(true)).then(callback); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import {IDictionary} from '../../../src/common/interfaces/dictionary-interface' | |
export class ViewCache { | |
views: IDictionary<any> = {}; | |
getView(resourceKey: string): any { | |
return this.views[resourceKey]; | |
} | |
setView(resourceKey: string, resource: any) { | |
this.views[resourceKey] = resource; | |
} | |
} | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import {IDictionary} from '../../../src/common/interfaces/dictionary-interface' | |
export class ViewModelCache { | |
viewModels: IDictionary<any> = {}; | |
getViewModel(resourceKey: string): any { | |
return this.viewModels[resourceKey]; | |
} | |
setViewModel(resourceKey: string, resource: any) { | |
this.viewModels[resourceKey] = resource; | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment