Skip to content

Commit

Permalink
feat(1.x): make pipeline configurable
Browse files Browse the repository at this point in the history
  • Loading branch information
btford committed Mar 27, 2015
1 parent 7d56e3d commit 88d2f5c
Show file tree
Hide file tree
Showing 5 changed files with 254 additions and 63 deletions.
1 change: 1 addition & 0 deletions karma.es5.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ module.exports = function(config) {

buildDir + '/*.es5.js',

'test/*.es5.js',
'test/*.es5.spec.js'
],

Expand Down
146 changes: 97 additions & 49 deletions src/router-directive.es5.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,21 @@ angular.module('ngNewRouter', [])
.factory('$router', routerFactory)
.value('$routeParams', {})
.provider('$componentLoader', $componentLoaderProvider)
.factory('$$pipeline', pipelineFactory)
.provider('$pipeline', pipelineProvider)
.factory('$$pipeline', privatePipelineFactory)
.factory('$setupRoutersStep', setupRoutersStepFactory)
.factory('$initLocalsStep', initLocalsStepFactory)
.factory('$initControllersStep', initControllersStepFactory)
.factory('$runCanDeactivateHookStep', runCanDeactivateHookStepFactory)
.factory('$runCanActivateHookStep', runCanActivateHookStepFactory)
.factory('$loadTemplatesStep', loadTemplatesStepFactory)
.value('$activateStep', activateStepValue)
.directive('ngViewport', ngViewportDirective)
.directive('ngViewport', ngViewportFillContentDirective)
.directive('ngLink', ngLinkDirective)
.directive('a', anchorLinkDirective);
.directive('a', anchorLinkDirective)




/*
Expand Down Expand Up @@ -333,57 +343,31 @@ function anchorLinkDirective($router) {
}
}


function pipelineFactory($controller, $componentLoader, $q, $injector, $templateRequest) {

function invoke(method, context, instruction) {
return $injector.invoke(method, context, {
$routeParams: instruction.params
});
}

var STEPS = [
setupRouters,
initLocals,
initControllers,
runCanDeactivateHook,
runCanActivateHook,
loadTemplates,
activate
];

return {
process: function(instruction) {
// make a copy
var steps = STEPS.slice(0);

function processOne(result) {
if (steps.length === 0) {
return result;
}
var step = steps.shift();
return $q.when(step(instruction)).then(processOne);
}

return processOne();
}
}


function setupRouters(instruction) {
function setupRoutersStepFactory() {
return function (instruction) {
return instruction.router.makeDescendantRouters(instruction);
}
}

function initLocals(instruction) {
/*
* $initLocalsStep
*/
function initLocalsStepFactory() {
return function initLocals(instruction) {
return instruction.router.traverseInstruction(instruction, function(instruction) {
return instruction.locals = {
$router: instruction.router,
$routeParams: (instruction.params || {})
};
});
}
}

function initControllers(instruction) {
/*
* $initControllersStep
*/
function initControllersStepFactory($controller, $componentLoader) {
return function initControllers(instruction) {
return instruction.router.traverseInstruction(instruction, function(instruction) {
var controllerName = $componentLoader.controllerName(instruction.component);
var locals = instruction.locals;
Expand All @@ -397,32 +381,90 @@ function pipelineFactory($controller, $componentLoader, $q, $injector, $template
return instruction.controller = ctrl;
});
}
}

function runCanDeactivateHook(instruction) {
function runCanDeactivateHookStepFactory() {
return function runCanDeactivateHook(instruction) {
return instruction.router.canDeactivatePorts(instruction);
};
}

function runCanActivateHookStepFactory($injector) {

function invoke(method, context, instruction) {
return $injector.invoke(method, context, {
$routeParams: instruction.params
});
}

function runCanActivateHook(instruction) {
return function runCanActivateHook(instruction) {
return instruction.router.traverseInstruction(instruction, function(instruction) {
var controller = instruction.controller;
return !controller.canActivate || invoke(controller.canActivate, controller, instruction);
});
}
}

function loadTemplates(instruction) {
function loadTemplatesStepFactory($componentLoader, $templateRequest) {
return function loadTemplates(instruction) {
return instruction.router.traverseInstruction(instruction, function(instruction) {
var componentTemplateUrl = $componentLoader.template(instruction.component);
return $templateRequest(componentTemplateUrl).then(function (templateHtml) {
return instruction.template = templateHtml;
});
});
}
};
}

function activate(instruction) {
return instruction.router.activatePorts(instruction);
}

function activateStepValue(instruction) {
return instruction.router.activatePorts(instruction);
}


function pipelineProvider() {
var stepConfiguration;

var protoStepConfiguration = [
'$setupRoutersStep',
'$initLocalsStep',
'$initControllersStep',
'$runCanDeactivateHookStep',
'$runCanActivateHookStep',
'$loadTemplatesStep',
'$activateStep'
];

return {
steps: protoStepConfiguration.slice(0),
config: function (newConfig) {
protoStepConfiguration = newConfig;
},
$get: function ($injector, $q) {
stepConfiguration = protoStepConfiguration.map(function (step) {
return $injector.get(step);
});
return {
process: function(instruction) {
// make a copy
var steps = stepConfiguration.slice(0);

function processOne(result) {
if (steps.length === 0) {
return result;
}
var step = steps.shift();
return $q.when(step(instruction)).then(processOne);
}

return processOne();
}
}
}
};
}


/**
* @name $componentLoaderProvider
* @description
Expand Down Expand Up @@ -494,6 +536,12 @@ function $componentLoaderProvider() {
};
}

// this is a hack as a result of the build system used to transpile
function privatePipelineFactory($pipeline) {
return $pipeline;
}


function dashCase(str) {
return str.replace(/([A-Z])/g, function ($1) {
return '-' + $1.toLowerCase();
Expand Down
71 changes: 71 additions & 0 deletions test/pipeline.es5.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
describe('$pipeline', function () {

var elt,
$compile,
$rootScope,
$router,
$templateCache,
$controllerProvider;

beforeEach(function() {
module('ng');
module('ngNewRouter');
module(function(_$controllerProvider_) {
$controllerProvider = _$controllerProvider_;
});
});

it('should allow reconfiguration', function () {
module(function($pipelineProvider, $provide) {
$pipelineProvider.config([
'$setupRoutersStep',
'$initLocalsStep',
'myCustomStep',
'$initControllersStep',
'$runCanDeactivateHookStep',
'$runCanActivateHookStep',
'$loadTemplatesStep',
'$activateStep'
]);

$provide.value('myCustomStep', function (instruction) {
return instruction.router.traverseInstruction(instruction, function (instruction) {
return instruction.locals.custom = 'hello!'
});
});
});

inject(function(_$compile_, _$rootScope_, _$router_, _$templateCache_) {
$compile = _$compile_;
$rootScope = _$rootScope_;
$router = _$router_;
$templateCache = _$templateCache_;
});

put('one', '<div>{{one.custom}}</div>');
$controllerProvider.register('OneController', function (custom) {
this.custom = custom;
});

$router.config([
{ path: '/', component: 'one' }
]);

compile('<ng-viewport></ng-viewport>');

$router.navigate('/');
$rootScope.$digest();

expect(elt.text()).toBe('hello!');
});

function put (name, template) {
$templateCache.put(componentTemplatePath(name), [200, template, {}]);
}

function compile(template) {
elt = $compile('<div>' + template + '</div>')($rootScope);
$rootScope.$digest();
return elt;
}
});
14 changes: 0 additions & 14 deletions test/router-viewport.es5.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -731,17 +731,3 @@ describe('ngViewport animations', function () {
return elt;
}
});

function componentTemplatePath(name) {
return './components/' + dashCase(name) + '/' + dashCase(name) + '.html';
}

function componentControllerName(name) {
return name[0].toUpperCase() + name.substr(1) + 'Controller';
}

function dashCase(str) {
return str.replace(/([A-Z])/g, function ($1) {
return '-' + $1.toLowerCase();
});
}
85 changes: 85 additions & 0 deletions test/util.es5.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
* Helpers to keep tests DRY
*/

function componentTemplatePath(name) {
return './components/' + dashCase(name) + '/' + dashCase(name) + '.html';
}

function componentControllerName(name) {
return name[0].toUpperCase() + name.substr(1) + 'Controller';
}

function dashCase(str) {
return str.replace(/([A-Z])/g, function ($1) {
return '-' + $1.toLowerCase();
});
}

function boringController (model, value) {
return function () {
this[model] = value;
};
}

function provideHelpers(fn, preInject) {
return function () {
var elt,
$compile,
$rootScope,
$router,
$templateCache,
$controllerProvider;

module('ng');
module('ngNewRouter');
module(function(_$controllerProvider_) {
$controllerProvider = _$controllerProvider_;
});

inject(function(_$compile_, _$rootScope_, _$router_, _$templateCache_) {
$compile = _$compile_;
$rootScope = _$rootScope_;
$router = _$router_;
$templateCache = _$templateCache_;
});

function registerComponent(name, template, config) {
if (!template) {
template = '';
}
var ctrl;
if (!config) {
ctrl = function () {};
} else if (angular.isArray(config)) {
ctrl = function () {};
ctrl.$routeConfig = config;
} else if (typeof config === 'function') {
ctrl = config;
} else {
ctrl = function () {};
ctrl.prototype = config;
}
$controllerProvider.register(componentControllerName(name), ctrl);
put(name, template);
}


function put (name, template) {
$templateCache.put(componentTemplatePath(name), [200, template, {}]);
}

function compile(template) {
var elt = $compile('<div>' + template + '</div>')($rootScope);
$rootScope.$digest();
return elt;
}

fn({
registerComponent: registerComponent,
$router: $router,
put: put,
compile: compile
})
}
}

0 comments on commit 88d2f5c

Please sign in to comment.