From 06743ca640ee21db6651fe074587ac13a9e3e212 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Wenzel?= Date: Fri, 20 Oct 2017 01:07:41 +0200 Subject: [PATCH] feat(templating): stateful routes Adds stateful routes so that route configurations can specify a module or a module in a viewport as stateful: true. A stateful module that's loaded in a viewport is never unloaded when navigating away, it's just not shown, and is displayed with the same state whenever a route places it in the same viewport again. Required by aurelia/router/stateful-viewports. Closes aurelia/router#534. --- src/swap-strategies.js | 38 ++++++++++++++++++++++++++++++++++ src/view-slot.js | 46 ++++++++++++++++++++++++++++++++++++------ src/view.js | 14 +++++++++++++ 3 files changed, 92 insertions(+), 6 deletions(-) diff --git a/src/swap-strategies.js b/src/swap-strategies.js index 73ad2b27..0b431701 100644 --- a/src/swap-strategies.js +++ b/src/swap-strategies.js @@ -24,3 +24,41 @@ export const SwapStrategies = { return Promise.resolve(viewSlot.removeAll(true)).then(callback); } }; + +export const SwapStrategiesStateful = { + // animate the next viewports in before hiding the current viewports; + before(viewPort, previous, callback) { + return viewPort.hide(false).then(() => callback()).then(() => Promise.all(previous.map((prevViewPort) => { + if (!prevViewPort.stateful) { + return prevViewPort.viewSlot.removeAll(true); + } + else { + return prevViewPort.hide(true); + } + }))); + }, + + // animate the next viewport at the same time the current viewports are removed + with(viewPort, previous, callback) { + return Promise.all(previous.map((prevViewPort) => { + if (!prevViewPort.stateful) { + return prevViewPort.viewSlot.removeAll(true); + } + else { + return prevViewPort.hide(true); + } + }), viewPort.hide(false).then(() => callback())); + }, + + // animate the next viewport in after the current viewports have been removed + after(viewPort, previous, callback) { + return Promise.all(previous.map((prevViewPort) => { + if (!prevViewPort.stateful) { + return prevViewPort.viewSlot.removeAll(true); + } + else { + return prevViewPort.hide(true); + } + })).then(() => viewPort.hide(false).then(() => callback())); + } +}; diff --git a/src/view-slot.js b/src/view-slot.js index 9e8d2f9b..50326dc4 100644 --- a/src/view-slot.js +++ b/src/view-slot.js @@ -56,12 +56,12 @@ export class ViewSlot { if (animatableElement !== null) { switch (direction) { - case 'enter': - return this.animator.enter(animatableElement); - case 'leave': - return this.animator.leave(animatableElement); - default: - throw new Error('Invalid animation direction: ' + direction); + case 'enter': + return this.animator.enter(animatableElement); + case 'leave': + return this.animator.leave(animatableElement); + default: + throw new Error('Invalid animation direction: ' + direction); } } } @@ -357,6 +357,40 @@ export class ViewSlot { return removeAction(); } + /** + * Hides or shows all views in the slot. + * @param hide If the views should be hidden. + * @param skipAnimation Should the removal animation be skipped? + * @return May return a promise if the view removals triggered an animation. + */ + hide(hide_: boolean, skipAnimation?: boolean): void | Promise { + let children = this.children; + let rmPromises = []; + + children.forEach(child => { + if (skipAnimation) { + child.hide(hide_); + } + + let animation = this.animateView(child, (hide_ ? 'leave' : 'enter')); + if (animation) { + if (hide_) { + rmPromises.push(animation.then(() => child.hide(hide_))); + } + else { + child.hide(hide_); + rmPromises.push(animation); + } + } else { + child.hide(hide_); + } + }); + + // if (rmPromises.length > 0) { + return Promise.all(rmPromises); + // } + } + /** * Triggers the attach for the slot and its children. */ diff --git a/src/view.js b/src/view.js index fb1af83c..4bf3c4b5 100644 --- a/src/view.js +++ b/src/view.js @@ -315,4 +315,18 @@ export class View { } } } + + /** + * Hides or shows view + * @param hide If the view should be hidden + */ + hide(hide_: boolean): void { + let current = this.firstChild; + while (current) { + if (current.style) { + current.style.display = hide_ ? 'none' : ''; + } + current = current.nextSibling; + } + } }