import {Redirect} from './navigation-commands';
import {_resolveUrl} from './util';
/**
* The strategy to use when activating modules during navigation.
*/
export const activationStrategy = {
noChange: 'no-change',
invokeLifecycle: 'invoke-lifecycle',
replace: 'replace'
};
export class BuildNavigationPlanStep {
run(navigationInstruction: NavigationInstruction, next: Function) {
return _buildNavigationPlan(navigationInstruction)
.then(plan => {
navigationInstruction.plan = plan;
return next();
}).catch(next.cancel);
}
}
export function _buildNavigationPlan(instruction: NavigationInstruction, forceLifecycleMinimum): Promise<Object> {
let prev = instruction.previousInstruction;
let config = instruction.config;
let plan = {};
if ('redirect' in config) {
let redirectLocation = _resolveUrl(config.redirect, getInstructionBaseUrl(instruction));
Eif (instruction.queryString) {
redirectLocation += '?' + instruction.queryString;
}
return Promise.reject(new Redirect(redirectLocation));
}
if (prev) {
let newParams = hasDifferentParameterValues(prev, instruction);
let pending = [];
for (let viewPortName in prev.viewPortInstructions) {
let prevViewPortInstruction = prev.viewPortInstructions[viewPortName];
let nextViewPortConfig = config.viewPorts[viewPortName];
Iif (!nextViewPortConfig) throw new Error(`Invalid Route Config: Configuration for viewPort "${viewPortName}" was not found for route: "${instruction.config.route}."`);
let viewPortPlan = plan[viewPortName] = {
name: viewPortName,
config: nextViewPortConfig,
prevComponent: prevViewPortInstruction.component,
prevModuleId: prevViewPortInstruction.moduleId
};
if (prevViewPortInstruction.moduleId !== nextViewPortConfig.moduleId) {
viewPortPlan.strategy = activationStrategy.replace;
} else if ('determineActivationStrategy' in prevViewPortInstruction.component.viewModel) {
viewPortPlan.strategy = prevViewPortInstruction.component.viewModel
.determineActivationStrategy(...instruction.lifecycleArgs);
} else if (config.activationStrategy) {
viewPortPlan.strategy = config.activationStrategy;
} else if (newParams || forceLifecycleMinimum) {
viewPortPlan.strategy = activationStrategy.invokeLifecycle;
} else {
viewPortPlan.strategy = activationStrategy.noChange;
}
Iif (viewPortPlan.strategy !== activationStrategy.replace && prevViewPortInstruction.childRouter) {
let path = instruction.getWildcardPath();
let task = prevViewPortInstruction.childRouter
._createNavigationInstruction(path, instruction).then(childInstruction => { // eslint-disable-line no-loop-func
viewPortPlan.childNavigationInstruction = childInstruction;
return _buildNavigationPlan(
childInstruction,
viewPortPlan.strategy === activationStrategy.invokeLifecycle)
.then(childPlan => {
childInstruction.plan = childPlan;
});
});
pending.push(task);
}
}
return Promise.all(pending).then(() => plan);
}
for (let viewPortName in config.viewPorts) {
plan[viewPortName] = {
name: viewPortName,
strategy: activationStrategy.replace,
config: instruction.config.viewPorts[viewPortName]
};
}
return Promise.resolve(plan);
}
function hasDifferentParameterValues(prev: NavigationInstruction, next: NavigationInstruction): boolean {
let prevParams = prev.params;
let nextParams = next.params;
let nextWildCardName = next.config.hasChildRouter ? next.getWildCardName() : null;
for (let key in nextParams) {
Iif (key === nextWildCardName) {
continue;
}
if (prevParams[key] !== nextParams[key]) {
return true;
}
}
for (let key in prevParams) {
Iif (key === nextWildCardName) {
continue;
}
if (prevParams[key] !== nextParams[key]) {
return true;
}
}
if (!next.options.compareQueryParams) {
return false;
}
let prevQueryParams = prev.queryParams;
let nextQueryParams = next.queryParams;
for (let key in nextQueryParams) {
Eif (prevQueryParams[key] !== nextQueryParams[key]) {
return true;
}
}
for (let key in prevQueryParams) {
if (prevQueryParams[key] !== nextQueryParams[key]) {
return true;
}
}
return false;
}
function getInstructionBaseUrl(instruction: NavigationInstruction): string {
let instructionBaseUrlParts = [];
instruction = instruction.parentInstruction;
while (instruction) {
instructionBaseUrlParts.unshift(instruction.getBaseUrl());
instruction = instruction.parentInstruction;
}
instructionBaseUrlParts.unshift('/');
return instructionBaseUrlParts.join('');
}
|