Commit b9384ad7 authored by bingchuan's avatar bingchuan

[dev] version 0.3.3

parents
Pipeline #41 failed with stages
{
"name": "angular-breadcrumb",
"description": "AngularJS module that generates a breadcrumb from ui-router's states",
"version": "0.3.3",
"main": "release/angular-breadcrumb.js",
"ignore": [
"sample",
"src",
"test",
".bowerrc",
".coveralls.yml",
".gitignore",
".jshintrc",
".travis.yml",
"gruntfile.js",
"bower.json",
"karma.conf.js",
"libpeerconnection.log",
"package.json",
"README.md"
],
"dependencies": {
"angular": ">=1.0.8",
"angular-ui-router": ">=0.2.0"
},
"devDependencies": {
"bootstrap": "~2.3.2",
"angular-ui-bootstrap-bower": "~0.8.0",
"underscore": "~1.5.1",
"angular-mocks": ">=1.0.8",
"angular-sanitize": ">=1.0.8"
}
}
/*! angular-breadcrumb - v0.3.3
* http://ncuillery.github.io/angular-breadcrumb
* Copyright (c) 2014 Nicolas Cuillery; Licensed MIT */
(function (window, angular, undefined) {
'use strict';
function isAOlderThanB(scopeA, scopeB) {
if(angular.equals(scopeA.length, scopeB.length)) {
return scopeA > scopeB;
} else {
return scopeA.length > scopeB.length;
}
}
function parseStateRef(ref) {
var parsed = ref.replace(/\n/g, " ").match(/^([^(]+?)\s*(\((.*)\))?$/);
if (!parsed || parsed.length !== 4) { throw new Error("Invalid state ref '" + ref + "'"); }
return { state: parsed[1], paramExpr: parsed[3] || null };
}
function $Breadcrumb() {
var $$options = {
prefixStateName: null,
template: 'bootstrap3',
templateUrl: null,
includeAbstract : false
};
this.setOptions = function(options) {
angular.extend($$options, options);
};
this.$get = ['$state', '$stateParams', '$rootScope', function($state, $stateParams, $rootScope) {
var $lastViewScope = $rootScope;
// Early catch of $viewContentLoaded event
$rootScope.$on('$viewContentLoaded', function (event) {
// With nested views, the event occur several times, in "wrong" order
if(isAOlderThanB(event.targetScope.$id, $lastViewScope.$id)) {
$lastViewScope = event.targetScope;
}
});
// Get the parent state
var $$parentState = function(state) {
// Check if state has explicit parent OR we try guess parent from its name
var name = state.parent || (/^(.+)\.[^.]+$/.exec(state.name) || [])[1];
// If we were able to figure out parent name then get this state
return name;
};
// Add the state in the chain if not already in and if not abstract
var $$addStateInChain = function(chain, stateRef) {
var conf,
parentParams,
ref = parseStateRef(stateRef);
for(var i=0, l=chain.length; i<l; i+=1) {
if (chain[i].name === ref.state) {
return;
}
}
conf = $state.get(ref.state);
if((!conf.abstract || $$options.includeAbstract) && !(conf.ncyBreadcrumb && conf.ncyBreadcrumb.skip)) {
if(ref.paramExpr) {
parentParams = $lastViewScope.$eval(ref.paramExpr);
}
conf.ncyBreadcrumbLink = $state.href(ref.state, parentParams || $stateParams || {});
chain.unshift(conf);
}
};
// Get the state for the parent step in the breadcrumb
var $$breadcrumbParentState = function(stateRef) {
var ref = parseStateRef(stateRef),
conf = $state.get(ref.state);
if(conf.ncyBreadcrumb && conf.ncyBreadcrumb.parent) {
// Handle the "parent" property of the breadcrumb, override the parent/child relation of the state
var isFunction = typeof conf.ncyBreadcrumb.parent === 'function';
var parentStateRef = isFunction ? conf.ncyBreadcrumb.parent($lastViewScope) : conf.ncyBreadcrumb.parent;
if(parentStateRef) {
return parentStateRef;
}
}
return $$parentState(conf);
};
return {
getTemplate: function(templates) {
if($$options.templateUrl) {
// templateUrl takes precedence over template
return null;
} else if(templates[$$options.template]) {
// Predefined templates (bootstrap, ...)
return templates[$$options.template];
} else {
return $$options.template;
}
},
getTemplateUrl: function() {
return $$options.templateUrl;
},
getStatesChain: function(exitOnFirst) { // Deliberately undocumented param, see getLastStep
var chain = [];
// From current state to the root
for(var stateRef = $state.$current.self.name; stateRef; stateRef=$$breadcrumbParentState(stateRef)) {
$$addStateInChain(chain, stateRef);
if(exitOnFirst && chain.length) {
return chain;
}
}
// Prefix state treatment
if($$options.prefixStateName) {
$$addStateInChain(chain, $$options.prefixStateName);
}
return chain;
},
getLastStep: function() {
var chain = this.getStatesChain(true);
return chain.length ? chain[0] : undefined;
},
$getLastViewScope: function() {
return $lastViewScope;
}
};
}];
}
var getExpression = function(interpolationFunction) {
if(interpolationFunction.expressions) {
return interpolationFunction.expressions;
} else {
var expressions = [];
angular.forEach(interpolationFunction.parts, function(part) {
if(angular.isFunction(part)) {
expressions.push(part.exp);
}
});
return expressions;
}
};
var registerWatchers = function(labelWatcherArray, interpolationFunction, viewScope, step) {
angular.forEach(getExpression(interpolationFunction), function(expression) {
var watcher = viewScope.$watch(expression, function() {
step.ncyBreadcrumbLabel = interpolationFunction(viewScope);
});
labelWatcherArray.push(watcher);
});
};
var deregisterWatchers = function(labelWatcherArray) {
angular.forEach(labelWatcherArray, function(deregisterWatch) {
deregisterWatch();
});
labelWatcherArray = [];
};
function BreadcrumbDirective($interpolate, $breadcrumb, $rootScope) {
var $$templates = {
bootstrap2: '<ul class="breadcrumb">' +
'<li ng-repeat="step in steps" ng-switch="$last || !!step.abstract" ng-class="{active: $last}">' +
'<a ng-switch-when="false" href="{{step.ncyBreadcrumbLink}}">{{step.ncyBreadcrumbLabel}}</a> ' +
'<span ng-switch-when="true">{{step.ncyBreadcrumbLabel}}</span>' +
'<span class="divider" ng-hide="$last">/</span>' +
'</li>' +
'</ul>',
bootstrap3: '<ol class="breadcrumb">' +
'<li ng-repeat="step in steps" ng-class="{active: $last}" ng-switch="$last || !!step.abstract">' +
'<a ng-switch-when="false" href="{{step.ncyBreadcrumbLink}}">{{step.ncyBreadcrumbLabel}}</a> ' +
'<span ng-switch-when="true">{{step.ncyBreadcrumbLabel}}</span>' +
'</li>' +
'</ol>'
};
return {
restrict: 'AE',
replace: true,
scope: {},
template: $breadcrumb.getTemplate($$templates),
templateUrl: $breadcrumb.getTemplateUrl(),
link: {
post: function postLink(scope) {
var labelWatchers = [];
var renderBreadcrumb = function() {
deregisterWatchers(labelWatchers);
var viewScope = $breadcrumb.$getLastViewScope();
scope.steps = $breadcrumb.getStatesChain();
angular.forEach(scope.steps, function (step) {
if (step.ncyBreadcrumb && step.ncyBreadcrumb.label) {
var parseLabel = $interpolate(step.ncyBreadcrumb.label);
step.ncyBreadcrumbLabel = parseLabel(viewScope);
// Watcher for further viewScope updates
registerWatchers(labelWatchers, parseLabel, viewScope, step);
} else {
step.ncyBreadcrumbLabel = step.name;
}
});
};
$rootScope.$on('$viewContentLoaded', function () {
renderBreadcrumb();
});
// View(s) may be already loaded while the directive's linking
renderBreadcrumb();
}
}
};
}
BreadcrumbDirective.$inject = ['$interpolate', '$breadcrumb', '$rootScope'];
function BreadcrumbLastDirective($interpolate, $breadcrumb, $rootScope) {
return {
restrict: 'A',
scope: {},
template: '{{ncyBreadcrumbLabel}}',
compile: function(cElement, cAttrs) {
// Override the default template if ncyBreadcrumbLast has a value
var template = cElement.attr(cAttrs.$attr.ncyBreadcrumbLast);
if(template) {
cElement.html(template);
}
return {
post: function postLink(scope) {
var labelWatchers = [];
var renderLabel = function() {
deregisterWatchers(labelWatchers);
var viewScope = $breadcrumb.$getLastViewScope();
var lastStep = $breadcrumb.getLastStep();
if(lastStep) {
scope.ncyBreadcrumbLink = lastStep.ncyBreadcrumbLink;
if (lastStep.ncyBreadcrumb && lastStep.ncyBreadcrumb.label) {
var parseLabel = $interpolate(lastStep.ncyBreadcrumb.label);
scope.ncyBreadcrumbLabel = parseLabel(viewScope);
// Watcher for further viewScope updates
// Tricky last arg: the last step is the entire scope of the directive !
registerWatchers(labelWatchers, parseLabel, viewScope, scope);
} else {
scope.ncyBreadcrumbLabel = lastStep.name;
}
}
};
$rootScope.$on('$viewContentLoaded', function () {
renderLabel();
});
// View(s) may be already loaded while the directive's linking
renderLabel();
}
};
}
};
}
BreadcrumbLastDirective.$inject = ['$interpolate', '$breadcrumb', '$rootScope'];
angular.module('ncy-angular-breadcrumb', ['ui.router.state'])
.provider('$breadcrumb', $Breadcrumb)
.directive('ncyBreadcrumb', BreadcrumbDirective)
.directive('ncyBreadcrumbLast', BreadcrumbLastDirective);
})(window, window.angular);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment