Instantly share code, notes, and snippets.
Last active
April 21, 2016 13:34
-
Star
(1)
1
You must be signed in to star a gist -
Fork
(0)
0
You must be signed in to fork a gist
-
Save Scapal/20518b932c4c8e3c1940 to your computer and use it in GitHub Desktop.
Aurelia navigation-view
This file contains 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 { | |
inject, Container, ViewSlot, ViewLocator, | |
customElement, noView, CompositionTransaction, | |
CompositionEngine, bindable | |
} from 'aurelia-framework'; | |
@noView() | |
@customElement('navigation-view') | |
@inject(Element, Container, ViewSlot, ViewLocator, CompositionEngine, CompositionTransaction) | |
export class NavigationView { | |
@bindable viewModel; | |
@bindable model; | |
@bindable title; | |
viewChanged = null; | |
subscribers = []; | |
stack = []; | |
busy = false; | |
constructor(element, container, viewSlot, viewLocator, compositionEngine, compositionTransaction) { | |
this.element = element; | |
this.container = container; | |
this.viewSlot = viewSlot; | |
this.viewLocator = viewLocator; | |
this.compositionEngine = compositionEngine; | |
this.compositionTransaction = compositionTransaction; | |
this.controller = null; | |
if (!('initialComposition' in compositionTransaction)) { | |
compositionTransaction.initialComposition = true; | |
this.compositionTransactionNotifier = compositionTransaction.enlist(); | |
} | |
} | |
get length() { | |
return this.stack.length; | |
} | |
_getViewModel(instruction) { | |
if (typeof instruction.viewModel === 'function') { | |
instruction.viewModel = Origin.get(instruction.viewModel).moduleId; | |
} | |
if (typeof instruction.viewModel === 'string') { | |
return this.compositionEngine.ensureViewModel(instruction); | |
} | |
return Promise.resolve(instruction); | |
} | |
created(owningView) { | |
this.owningView = owningView; | |
} | |
bind(bindingContext, overrideContext) { | |
this.container.viewModel = bindingContext; | |
this.overrideContext = overrideContext; | |
} | |
attached() { | |
this.navigate(this.viewModel, this.title, this.model); | |
} | |
_navigate(controller, title, swapDirection) { | |
let oldController = this.controller; | |
this.controller = controller; | |
let classList = this.element.classList; | |
this.title = title; | |
let compositionHandler = () => { | |
if (this.compositionTransactionNotifier) { | |
this.compositionTransactionNotifier.done(); | |
this.compositionTransactionNotifier = null; | |
} | |
classList.remove(`nav-${swapDirection}`); | |
this.busy = false; | |
}; | |
if (!oldController) { | |
return Promise.resolve(this.viewSlot.add(this.controller.view)).then( () => compositionHandler() ); | |
} else { | |
classList.add(`nav-${swapDirection}`); | |
this.invokeSubscribers(swapDirection); | |
return Promise.all([ | |
this.viewSlot.add(this.controller.view), | |
this.viewSlot.remove(oldController.view, true) | |
]).then( () => compositionHandler() ); | |
} | |
} | |
navigate(viewModel, title, model) { | |
if (this.busy) return; | |
this.busy = true; | |
let childContainer = this.container.createChild(); | |
let instruction = { | |
viewModel: viewModel, | |
container: this.container, | |
childContainer: childContainer, | |
model: model, | |
skipActivation: true | |
}; | |
this._getViewModel(instruction).then(returnedInstruction => { | |
this.invokeLifecycle(returnedInstruction.viewModel, 'canActivate', model).then(canActivate => { | |
if (canActivate) { | |
this.compositionEngine.createController(returnedInstruction).then(controller => { | |
this.invokeLifecycle(returnedInstruction.viewModel, 'activate', model).then( () => { | |
if (!this.compositionTransactionNotifier) { | |
this.compositionTransactionOwnershipToken = this.compositionTransaction.tryCapture(); | |
} | |
controller.automate(this.overrideContext, this.owningView); | |
if (this.compositionTransactionOwnershipToken) { | |
return this.compositionTransactionOwnershipToken.waitForCompositionComplete().then(() => { | |
this.compositionTransactionOwnershipToken = null; | |
if (this.controller !== null) { | |
this.stack.push({controller: this.controller, title: this.title}); | |
} | |
this._navigate(controller, title, 'forward'); | |
}); | |
} | |
}); | |
}); | |
} | |
}); | |
}); | |
} | |
navigateBack() { | |
if (!this.busy && this.stack.length > 0) { | |
this.busy = true; | |
let previousState = this.stack.pop(); | |
let controller = previousState.controller; | |
controller.bind(this); | |
this._navigate(controller, previousState.title, 'back'); | |
} | |
} | |
subscribe(callback) { | |
let subscribers = this.subscribers; | |
subscribers.push(callback); | |
return { | |
dispose() { | |
let idx = subscribers.indexOf(callback); | |
if (idx !== -1) { | |
subscribers.splice(idx, 1); | |
} | |
} | |
}; | |
} | |
invokeSubscribers(direction) { | |
let i = this.subscribers.length; | |
while (i--) { | |
this.subscribers[i](direction); | |
} | |
} | |
invokeLifecycle(instance, name, model) { | |
if (typeof instance[name] === 'function') { | |
let result = instance[name](model, this); | |
if (result instanceof Promise) { | |
return result; | |
} | |
if (result !== null && result !== undefined) { | |
return Promise.resolve(result); | |
} | |
return Promise.resolve(true); | |
} | |
return Promise.resolve(true); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Make the Navbar title animate when navigating: