kongadmin
Version:
Kong admin GUI
179 lines (163 loc) • 8.49 kB
JavaScript
/**
* uiBreadcrumbs automatic breadcrumbs directive for AngularJS & Angular ui-router.
*
* https://github.com/michaelbromley/angularUtils/tree/master/src/directives/uiBreadcrumbs
*
* Copyright 2014 Michael Bromley <michael@michaelbromley.co.uk>
*/
(function() {
/**
* Config
*/
var moduleName = 'angularUtils.directives.uiBreadcrumbs';
var templateUrl = 'directives/uiBreadcrumbs/uiBreadcrumbs.tpl.html';
/**
* Module
*/
var module;
try {
module = angular.module(moduleName);
} catch(err) {
// named module does not exist, so create one
module = angular.module(moduleName, ['ui.router']);
}
module.directive('uiBreadcrumbs', ['$interpolate', '$state', function($interpolate, $state) {
return {
restrict: 'E',
templateUrl: function(elem, attrs) {
return attrs.templateUrl || templateUrl;
},
scope: {
displaynameProperty: '@',
abstractProxyProperty: '@?'
},
link: function(scope) {
scope.breadcrumbs = [];
if ($state.$current.name !== '') {
updateBreadcrumbsArray();
}
scope.$on('$stateChangeSuccess', function() {
updateBreadcrumbsArray();
});
/**
* Start with the current state and traverse up the path to build the
* array of breadcrumbs that can be used in an ng-repeat in the template.
*/
function updateBreadcrumbsArray() {
var workingState;
var displayName;
var breadcrumbs = [];
var currentState = $state.$current;
while(currentState && currentState.name !== '') {
workingState = getWorkingState(currentState);
if (workingState) {
displayName = getDisplayName(workingState);
if (displayName !== false && !stateAlreadyInBreadcrumbs(workingState, breadcrumbs)) {
breadcrumbs.push({
displayName: displayName,
route: workingState.name
});
}
}
currentState = currentState.parent;
}
breadcrumbs.reverse();
scope.breadcrumbs = breadcrumbs;
}
/**
* Get the state to put in the breadcrumbs array, taking into account that if the current state is abstract,
* we need to either substitute it with the state named in the `scope.abstractProxyProperty` property, or
* set it to `false` which means this breadcrumb level will be skipped entirely.
* @param currentState
* @returns {*}
*/
function getWorkingState(currentState) {
var proxyStateName;
var workingState = currentState;
if (currentState.abstract === true) {
if (typeof scope.abstractProxyProperty !== 'undefined') {
proxyStateName = getObjectValue(scope.abstractProxyProperty, currentState);
if (proxyStateName) {
workingState = angular.copy($state.get(proxyStateName));
if (workingState) {
workingState.locals = currentState.locals;
}
} else {
workingState = false;
}
} else {
workingState = false;
}
}
return workingState;
}
/**
* Resolve the displayName of the specified state. Take the property specified by the `displayname-property`
* attribute and look up the corresponding property on the state's config object. The specified string can be interpolated against any resolved
* properties on the state config object, by using the usual {{ }} syntax.
* @param currentState
* @returns {*}
*/
function getDisplayName(currentState) {
var interpolationContext;
var propertyReference;
var displayName;
if (!scope.displaynameProperty) {
// if the displayname-property attribute was not specified, default to the state's name
return currentState.name;
}
propertyReference = getObjectValue(scope.displaynameProperty, currentState);
if (propertyReference === false) {
return false;
} else if (typeof propertyReference === 'undefined') {
return currentState.name;
} else {
// use the $interpolate service to handle any bindings in the propertyReference string.
interpolationContext = (typeof currentState.locals !== 'undefined') ? currentState.locals.globals : currentState;
displayName = $interpolate(propertyReference)(interpolationContext);
return displayName;
}
}
/**
* Given a string of the type 'object.property.property', traverse the given context (eg the current $state object) and return the
* value found at that path.
*
* @param objectPath
* @param context
* @returns {*}
*/
function getObjectValue(objectPath, context) {
var i;
var propertyArray = objectPath.split('.');
var propertyReference = context;
for (i = 0; i < propertyArray.length; i ++) {
if (angular.isDefined(propertyReference[propertyArray[i]])) {
propertyReference = propertyReference[propertyArray[i]];
} else {
// if the specified property was not found, default to the state's name
return undefined;
}
}
return propertyReference;
}
/**
* Check whether the current `state` has already appeared in the current breadcrumbs array. This check is necessary
* when using abstract states that might specify a proxy that is already there in the breadcrumbs.
* @param state
* @param breadcrumbs
* @returns {boolean}
*/
function stateAlreadyInBreadcrumbs(state, breadcrumbs) {
var i;
var alreadyUsed = false;
for(i = 0; i < breadcrumbs.length; i++) {
if (breadcrumbs[i].route === state.name) {
alreadyUsed = true;
}
}
return alreadyUsed;
}
}
};
}]);
})();