1
0
mirror of https://github.com/ansible/awx.git synced 2024-11-01 16:51:11 +03:00

Added angular-breadcrumb to the project

This commit is contained in:
Michael Abashian 2015-12-21 10:38:40 -05:00 committed by Jared Tabor
parent 51f3784a5f
commit cfc5f0e78c
13 changed files with 1350 additions and 10 deletions

View File

@ -0,0 +1,44 @@
{
"name": "angular-breadcrumb",
"description": "AngularJS module that generates a breadcrumb from ui-router's states",
"version": "0.4.1",
"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"
},
"homepage": "https://github.com/ncuillery/angular-breadcrumb",
"_release": "0.4.1",
"_resolution": {
"type": "version",
"tag": "v0.4.1",
"commit": "b291e06f4010ebebbb41ea2c14e73e236aa70930"
},
"_source": "git://github.com/ncuillery/angular-breadcrumb.git",
"_target": "~0.4.1",
"_originalSource": "angular-breadcrumb",
"_direct": true
}

View File

@ -0,0 +1,16 @@
# EditorConfig helps developers define and maintain consistent
# coding styles between different editors and IDEs
# editorconfig.org
root = true
[*]
indent_style = space
indent_size = 4
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false

View File

@ -0,0 +1,15 @@
sample
src
test
.idea
bower_components
coverage
testDependencies
.bowerrc
.coveralls.yml
.gitignore
.jshintrc
.travis.yml
gruntfile.js
karma.conf.js
libpeerconnection.log

View File

@ -0,0 +1,151 @@
<a name="0.4.1"></a>
### 0.4.1 (2015-08-09)
#### Features
* add the scope-based ncyBreadcrumbIgnore flag ([934c5523](http://github.com/ncuillery/angular-breadcrumb/commit/934c5523208a9615d7cfa3abcb397bbe131332ac), closes [#42](http://github.com/ncuillery/angular-breadcrumb/issues/42), [#62](http://github.com/ncuillery/angular-breadcrumb/issues/42))
<a name="0.4.0"></a>
### 0.4.0 (2015-05-17)
#### Bug Fixes
* **$breadcrumb:** Handle parents provided by StateObject references ([f4288d37](http://github.com/ncuillery/angular-breadcrumb/commit/f4288d375fd1090ffec1d67e85c6300d74d86d37), closes [#82](http://github.com/ncuillery/angular-breadcrumb/issues/82))
* **ncyBreadcrumb:**
* Prevent memory leak when label is a binding ([264e10f6](http://github.com/ncuillery/angular-breadcrumb/commit/264e10f680e1bbb8d1e00cf500de39cac4222cfd), closes [#88](http://github.com/ncuillery/angular-breadcrumb/issues/88))
* Removed trailing spaces from breadcrumb items([bc276ed5](http://github.com/ncuillery/angular-breadcrumb/commit/bc276ed5351a586d4a6dc83ada0687e6ca485344), closes [#77](http://github.com/ncuillery/angular-breadcrumb/issues/77))
#### Features
* Add force to ncyBreadcrumb options ([31125a38](http://github.com/ncuillery/angular-breadcrumb/commit/31125a386d706dd76df807b3b02e1fccea38fb59), closes [#77](http://github.com/ncuillery/angular-breadcrumb/issues/78))
* **ncyBreadcrumbText:** Add ncyBreadcrumbText directive ([82b2b443](http://github.com/ncuillery/angular-breadcrumb/commit/82b2b443fab220cd9ac7d3a8c90c1edc4291e54a), closes [#71](http://github.com/ncuillery/angular-breadcrumb/issues/71), [#83](http://github.com/ncuillery/angular-breadcrumb/issues/83))
<a name="0.3.3"></a>
### 0.3.3 (2014-12-16)
#### Bug Fixes
* **ncyBreadcrumb:** define `$$templates` with var instead of attaching it to `window` ([c35c9d25](http://github.com/ncuillery/angular-breadcrumb/commit/c35c9d255b5e2585d225a961d1efdb51d18f6a55), closes [#55](http://github.com/ncuillery/angular-breadcrumb/issues/55))
<a name="0.3.2"></a>
### 0.3.2 (2014-11-15)
* **npm:** nothing, it's only a blank release due to a network problem during the last `npm publish` (f...ing npm doesn't allow a republish with the same version number [npm-registry-couchapp#148](https://github.com/npm/npm-registry-couchapp/issues/148)).
<a name="0.3.1"></a>
### 0.3.1 (2014-11-15)
#### Bug Fixes
* **npm:** update package.json after (unclean) npm publish ([ab8161c2](http://github.com/ncuillery/angular-breadcrumb/commit/ab8161c25f98613f725b5e5ff8fe147acd60b365), closes [#52](http://github.com/ncuillery/angular-breadcrumb/issues/52))
* **sample:** Send correct url params for the room link in booking view ([876de49a](http://github.com/ncuillery/angular-breadcrumb/commit/876de49a9c5d6e2d75714a606238e9041ed49baf))
<a name="0.3.0"></a>
## 0.3.0 (2014-10-29)
#### Bug Fixes
* organize state-level options in `ncyBreadcrumb` key instead of `data` ([1ea436d3](http://github.com/ncuillery/angular-breadcrumb/commit/1ea436d3f6d5470b7ae3e71e71259dbd2422bc00), closes [#30](http://github.com/ncuillery/angular-breadcrumb/issues/30))
* curly braces appearing on title of sample app ([855e76cb](http://github.com/ncuillery/angular-breadcrumb/commit/855e76cb33fda607fa3caa230564b77b48262c40))
#### Features
* Add a global option to include abstract states ([6f0461ea](http://github.com/ncuillery/angular-breadcrumb/commit/6f0461ea7db36d8e10c29ed10de1f1c08d215a19), closes [#35](http://github.com/ncuillery/angular-breadcrumb/issues/35), [#28](http://github.com/ncuillery/angular-breadcrumb/issues/28))
* **$breadcrumb:**
* Support url params when using `ncyBreadcrumb.parent` property ([55730045](http://github.com/ncuillery/angular-breadcrumb/commit/55730045dcf3b4fb1048c67f1e18953505563ed4), closes [#46](http://github.com/ncuillery/angular-breadcrumb/issues/46))
* add the customization of the parent state with a function ([ada09015](http://github.com/ncuillery/angular-breadcrumb/commit/ada09015c49f05a94349dabf078f1ed621811aaa), closes [#32](http://github.com/ncuillery/angular-breadcrumb/issues/32))
* **ncyBreadcrumbLast:** Add a new directive rendering the last step ([1eef24fb](http://github.com/ncuillery/angular-breadcrumb/commit/1eef24fbe862a1e3308181c38f50755843cf4426), closes [#37](http://github.com/ncuillery/angular-breadcrumb/issues/37))
#### Breaking Changes
* state-level options has been moved under the custom key
`ncyBreadcrumb` in state's configuration.
To migrate the code follow the example below:
```
// Before
$stateProvider.state('A', {
url: '/a',
data: {
ncyBreadcrumbLabel: 'State A'
}
});
```
```
// After
$stateProvider.state('A', {
url: '/a',
ncyBreadcrumb: {
label: 'State A'
}
});
```
See [API reference](https://github.com/ncuillery/angular-breadcrumb/wiki/API-Reference) for more informations.
([1ea436d3](http://github.com/ncuillery/angular-breadcrumb/commit/1ea436d3f6d5470b7ae3e71e71259dbd2422bc00))
<a name="0.2.3"></a>
### 0.2.3 (2014-07-26)
#### Bug Fixes
* **$breadcrumb:** use `$stateParams` in case of unhierarchical states ([1c3c05e0](http://github.com/ncuillery/angular-breadcrumb/commit/1c3c05e0acac191fe2e76db2ef18da339caefaaa), closes [#29](http://github.com/ncuillery/angular-breadcrumb/issues/29))
<a name="0.2.2"></a>
### 0.2.2 (2014-06-23)
#### Bug Fixes
* catch the `$viewContentLoaded` earlier ([bb47dd54](http://github.com/ncuillery/angular-breadcrumb/commit/bb47dd54deb5efc579ccb9b1575e686803dee1c5), closes [#14](http://github.com/ncuillery/angular-breadcrumb/issues/14))
* **sample:**
* make the CRU(D) about rooms working ([3ca89ec7](http://github.com/ncuillery/angular-breadcrumb/commit/3ca89ec771fd20dc4ab2d733612bdcfb96ced703))
* prevent direct URL access to a day disabled in the datepicker ([95236916](http://github.com/ncuillery/angular-breadcrumb/commit/95236916e00b19464a3dfe3584ef1b18da9ffb25), closes [#17](http://github.com/ncuillery/angular-breadcrumb/issues/17))
* use the same variable in the datepicker and from url params for state `booking.day` ([646f7060](http://github.com/ncuillery/angular-breadcrumb/commit/646f70607e494f0e5e3c2483ed69f689684b2742), closes [#16](http://github.com/ncuillery/angular-breadcrumb/issues/16))
#### Features
* **ncyBreadcrumb:** watch every expression founded in labels ([1363515e](http://github.com/ncuillery/angular-breadcrumb/commit/1363515e20977ce2f39a1f5e5e1d701f0d7af296), closes [#20](http://github.com/ncuillery/angular-breadcrumb/issues/20))
<a name="0.2.1"></a>
### 0.2.1 (2014-05-16)
#### Bug Fixes
* **$breadcrumb:** check if a state has a parent when looking for an inheritated property ([77e668b5](http://github.com/ncuillery/angular-breadcrumb/commit/77e668b5eb759570a64c2a885e81580953af3201), closes [#11](http://github.com/ncuillery/angular-breadcrumb/issues/11))
<a name="0.2.0"></a>
### 0.2.0 (2014-05-08)
#### Bug Fixes
* **$breadcrumb:** remove abstract states from breadcrumb ([8a06c5ab](http://github.com/ncuillery/angular-breadcrumb/commit/8a06c5abce749027d48f7309d1aabea1e447dfd5), closes [#8](http://github.com/ncuillery/angular-breadcrumb/issues/8))
* **ncyBreadcrumb:** display the correct breadcrumb in case of direct access ([e1f455ba](http://github.com/ncuillery/angular-breadcrumb/commit/e1f455ba4def97d3fc76b53772867b5f9daf4232), closes [#10](http://github.com/ncuillery/angular-breadcrumb/issues/10))
#### Features
* **$breadcrumb:**
* add a configuration property for skipping a state in the breadcrumb ([dd255d90](http://github.com/ncuillery/angular-breadcrumb/commit/dd255d906c4231f44b48f066d4db197a9c6b9e27), closes [#9](http://github.com/ncuillery/angular-breadcrumb/issues/9))
* allow chain of states customization ([028e493a](http://github.com/ncuillery/angular-breadcrumb/commit/028e493a1ebcae5ae60b8a9d42b949262000d7df), closes [#7](http://github.com/ncuillery/angular-breadcrumb/issues/7))
* **ncyBreadcrumb:** add 'Element' declaration style '<ncy-breadcrumb />' ([b51441ea](http://github.com/ncuillery/angular-breadcrumb/commit/b51441eafb1659b782fea1f8668c7f455e1d6b4d))

View File

@ -0,0 +1,52 @@
# Contributing to angular-breadcrumb
I am very glad to see this project living with PR from contributors who trust in it. Here is some guidelines to keep the contributions useful and efficient.
## Development hints
### Installation
- Checkout the repository
- Run `npm install`
- Run `bower install`
### Test running
This module uses the classic AngularJS stack with:
- Karma (test runner)
- Jasmine (assertion framework)
- angular-mocks (AngularJS module for testing)
Run the test with the grunt task `grunt test`. It runs the tests with different versions of AngularJS.
### Test developing
Tests are build around modules with a specific `$stateProvider` configuration:
- [Basic configuration](https://github.com/ncuillery/angular-breadcrumb/blob/master/test/mock/test-modules.js#L6): Basic definitions (no template, no controller)
- [Interpolation configuration](https://github.com/ncuillery/angular-breadcrumb/blob/master/test/mock/test-modules.js#L21): States with bindings in `ncyBreadcrumbLabel`
- [HTML configuration](https://github.com/ncuillery/angular-breadcrumb/blob/master/test/mock/test-modules.js#L36): States with HTML in `ncyBreadcrumbLabel`
- [Sample configuration](https://github.com/ncuillery/angular-breadcrumb/blob/master/test/mock/test-modules.js#L41): Bridge towards the sample app configuration for using in tests
- [UI-router's configuration](https://github.com/ncuillery/angular-breadcrumb/blob/master/test/mock/test-ui-router-sample.js#L9): Clone of the UI-router sample app (complemented with breadcrumb configuration)
Theses modules are loaded by Karma and they are available in test specifications.
Specifications are generally related to the directive `ncyBreadcrumb` or the service `$breadcrumb`.
### Sample
If you are not familiar with JS testing. You can run the [sample](http://ncuillery.github.io/angular-breadcrumb/#/sample) locally for testing purposes by using `grunt sample`. Sources are live-reloaded after each changes.
## Submitting a Pull Request
- Fork the [repository](https://github.com/ncuillery/angular-breadcrumb/)
- Make your changes in a new git branch following the coding rules below.
- Run the grunt default task (by typing `grunt` or `grunt default`): it will run the tests and build the module in `dist` directory)
- Commit the changes (including the `dist` directory) by using the commit conventions explained below.
- Push and make the PR
## Coding rules
- When making changes on the source file, please check that your changes are covered by the tests. If not, create a new test case.
## Commit conventions
angular-breadcrumb uses the same strict conventions as AngularJS and UI-router. These conventions are explained [here](https://github.com/angular/angular.js/blob/master/CONTRIBUTING.md#-git-commit-guidelines).
It is very important to fit these conventions especially for types `fix` and `feature` which are used by the CHANGELOG.md generation (it uses the [grunt-conventional-changelog](https://github.com/btford/grunt-conventional-changelog)).

View File

@ -0,0 +1,258 @@
'use strict';
var LIVERELOAD_PORT = 35729;
var lrSnippet = require('connect-livereload')({ port: LIVERELOAD_PORT });
var mountFolder = function (connect, dir) {
return connect.static(require('path').resolve(dir));
};
module.exports = function (grunt) {
// Project configuration.
grunt.initConfig({
// Metadata.
pkg: grunt.file.readJSON('package.json'),
headerDev: '/*! <%= pkg.name %> - v<%= pkg.version %>-dev-<%= grunt.template.today("yyyy-mm-dd") %>\n',
headerRelease: '/*! <%= pkg.name %> - v<%= pkg.version %>\n',
banner: '<%= pkg.homepage ? "* " + pkg.homepage + "\\n" : "" %>' +
'* Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>;' +
' Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %> */\n',
// Task configuration.
concat: {
dev: {
options: {
banner: '<%= headerDev %><%= banner %>\n(function (window, angular, undefined) {\n',
footer: '})(window, window.angular);\n',
stripBanners: true
},
src: ['src/<%= pkg.name %>.js'],
dest: 'dist/<%= pkg.name %>.js'
},
release: {
options: {
banner: '<%= headerRelease %><%= banner %>\n(function (window, angular, undefined) {\n',
footer: '})(window, window.angular);\n',
stripBanners: true
},
src: ['src/<%= pkg.name %>.js'],
dest: 'release/<%= pkg.name %>.js'
}
},
uglify: {
dev: {
options: {
banner: '<%= headerDev %><%= banner %>'
},
src: '<%= concat.dev.dest %>',
dest: 'dist/<%= pkg.name %>.min.js'
},
release: {
options: {
banner: '<%= headerRelease %><%= banner %>'
},
src: '<%= concat.release.dest %>',
dest: 'release/<%= pkg.name %>.min.js'
}
},
karma: {
unit: {
configFile: 'karma.conf.js'
}
},
jshint: {
options: {
jshintrc: '.jshintrc'
},
gruntfile: {
src: 'Gruntfile.js'
},
sources: {
options: {
jshintrc: 'src/.jshintrc'
},
src: ['src/**/*.js']
},
test: {
src: ['test/**/*.js']
}
},
watch: {
gruntfile: {
files: '<%= jshint.gruntfile.src %>',
tasks: ['jshint:gruntfile']
},
sources: {
files: '<%= jshint.sources.src %>',
tasks: ['jshint:sources', 'karma']
},
test: {
files: '<%= jshint.test.src %>',
tasks: ['jshint:test', 'karma']
},
sample: {
options: {
livereload: LIVERELOAD_PORT
},
tasks: 'copy:breadcrumb',
files: [
'sample/*.{css,js,html}',
'sample/controllers/*.{css,js,html}',
'sample/views/*.{css,js,html}',
'src/*.js'
]
}
},
copy: {
breadcrumb: {
files: [
{
flatten: true,
expand: true,
src: [
'src/angular-breadcrumb.js'
],
dest: 'sample/asset/'
}
]
},
asset: {
files: [
{
flatten: true,
expand: true,
src: [
'dist/angular-breadcrumb.js',
'bower_components/angular/angular.js',
'bower_components/angular-ui-router/release/angular-ui-router.js',
'bower_components/angular-ui-bootstrap-bower/ui-bootstrap-tpls.js',
'bower_components/bootstrap/docs/assets/css/bootstrap.css',
'bower_components/underscore/underscore.js'
],
dest: 'sample/asset/'
}
]
},
img: {
files: [
{
flatten: true,
expand: true,
src: [
'bower_components/bootstrap.css/img/glyphicons-halflings.png'
],
dest: 'sample/img/'
}
]
}
},
connect: {
options: {
port: 9000,
hostname: 'localhost'
},
livereload: {
options: {
middleware: function (connect) {
return [
lrSnippet,
mountFolder(connect, 'sample')
];
}
}
}
},
open: {
server: {
url: 'http://localhost:<%= connect.options.port %>/index.html'
}
},
bump: {
options: {
files: ['package.json', 'bower.json'],
updateConfigs: ['pkg']
}
},
clean: {
release: ["sample/*.zip"],
test: ["testDependencies/*"]
},
compress: {
release: {
options: {
archive: 'sample/<%= pkg.name %>-<%= pkg.version %>.zip'
},
files: [
{expand: true, cwd: 'release/', src: ['*.js']}
]
}
},
replace: {
release: {
src: ['sample/views/home.html'],
overwrite: true,
replacements: [{
from: /angular-breadcrumb-[0-9]+\.[0-9]+\.[0-9]+\.zip/g,
to: "angular-breadcrumb-<%= pkg.version %>.zip"
},
{
from: /\([0-9]+\.[0-9]+\.[0-9]+\)/g,
to: "(<%= pkg.version %>)"
}]
}
},
shell: {
testMinimal: {
command: 'bower install angular#=1.0.8 angular-mocks#=1.0.8 angular-sanitize#=1.0.8 angular-ui-router#=0.2.0 --config.directory=. --config.cwd=testDependencies'
},
test1dot2: {
command: 'bower install angular#=1.2.18 angular-mocks#=1.2.18 angular-sanitize#=1.2.18 angular-ui-router#=0.2.15 --config.directory=. --config.cwd=testDependencies'
},
testLatest: {
command: 'bower install angular angular-mocks angular-sanitize angular-ui-router --config.directory=. --config.cwd=testDependencies'
}
}
});
// These plugins provide necessary tasks.
grunt.loadNpmTasks('grunt-bump');
grunt.loadNpmTasks('grunt-contrib-clean');
grunt.loadNpmTasks('grunt-contrib-compress');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-copy');
grunt.loadNpmTasks('grunt-contrib-connect');
grunt.loadNpmTasks('grunt-conventional-changelog');
grunt.loadNpmTasks('grunt-karma');
grunt.loadNpmTasks('grunt-open');
grunt.loadNpmTasks('grunt-shell');
grunt.loadNpmTasks('grunt-text-replace');
grunt.registerTask('test', ['jshint', 'testMin', 'test1dot2', 'testLatest']);
grunt.registerTask('testMin', ['clean:test', 'shell:testMinimal', 'karma']);
grunt.registerTask('test1dot2', ['clean:test', 'shell:test1dot2', 'karma']);
grunt.registerTask('testLatest', ['clean:test', 'shell:testLatest', 'karma']);
grunt.registerTask('default', ['test', 'concat:dev', 'uglify:dev']);
grunt.registerTask('sample', ['concat:dev', 'copy:asset', 'copy:img', 'connect:livereload', 'open', 'watch']);
grunt.registerTask('release-prepare', 'Update all files for a release', function(target) {
if(!target) {
target = 'patch';
}
grunt.task.run(
'bump-only:' + target, // Version update
'test', // Tests
'concat:release', // Concat with release banner
'uglify:release', // Minify with release banner
'changelog', // Changelog update
'clean:release', // Delete old version download file
'compress:release', // New version download file
'replace:release' // Update version in download button (link & label)
);
});
};

View File

@ -0,0 +1,24 @@
The MIT License
Copyright (c) 2013 Nicolas Cuillery
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

View File

@ -0,0 +1,33 @@
{
"name": "angular-breadcrumb",
"description": "AngularJS module that generates a breadcrumb from ui-router's states",
"version": "0.4.1",
"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"
}
}

View File

@ -0,0 +1,369 @@
/*! angular-breadcrumb - v0.4.0-dev-2015-08-07
* http://ncuillery.github.io/angular-breadcrumb
* Copyright (c) 2015 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(!event.targetScope.ncyBreadcrumbIgnore &&
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 parent = state.parent || (/^(.+)\.[^.]+$/.exec(state.name) || [])[1];
var isObjectParent = typeof parent === "object";
// if parent is a object reference, then extract the name
return isObjectParent ? parent.name : parent;
};
// 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),
force = false,
skip = false;
for(var i=0, l=chain.length; i<l; i+=1) {
if (chain[i].name === ref.state) {
return;
}
}
conf = $state.get(ref.state);
// Get breadcrumb options
if(conf.ncyBreadcrumb) {
if(conf.ncyBreadcrumb.force){ force = true; }
if(conf.ncyBreadcrumb.skip){ skip = true; }
}
if((!conf.abstract || $$options.includeAbstract || force) && !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();
});
};
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);
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 (event) {
if(!event.targetScope.ncyBreadcrumbIgnore) {
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);
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 (event) {
if(!event.targetScope.ncyBreadcrumbIgnore) {
renderLabel();
}
});
// View(s) may be already loaded while the directive's linking
renderLabel();
}
};
}
};
}
BreadcrumbLastDirective.$inject = ['$interpolate', '$breadcrumb', '$rootScope'];
function BreadcrumbTextDirective($interpolate, $breadcrumb, $rootScope) {
return {
restrict: 'A',
scope: {},
template: '{{ncyBreadcrumbChain}}',
compile: function(cElement, cAttrs) {
// Override the default template if ncyBreadcrumbText has a value
var template = cElement.attr(cAttrs.$attr.ncyBreadcrumbText);
if(template) {
cElement.html(template);
}
var separator = cElement.attr(cAttrs.$attr.ncyBreadcrumbTextSeparator) || ' / ';
return {
post: function postLink(scope) {
var labelWatchers = [];
var registerWatchersText = function(labelWatcherArray, interpolationFunction, viewScope) {
angular.forEach(getExpression(interpolationFunction), function(expression) {
var watcher = viewScope.$watch(expression, function(newValue, oldValue) {
if (newValue !== oldValue) {
renderLabel();
}
});
labelWatcherArray.push(watcher);
});
};
var renderLabel = function() {
deregisterWatchers(labelWatchers);
labelWatchers = [];
var viewScope = $breadcrumb.$getLastViewScope();
var steps = $breadcrumb.getStatesChain();
var combinedLabels = [];
angular.forEach(steps, function (step) {
if (step.ncyBreadcrumb && step.ncyBreadcrumb.label) {
var parseLabel = $interpolate(step.ncyBreadcrumb.label);
combinedLabels.push(parseLabel(viewScope));
// Watcher for further viewScope updates
registerWatchersText(labelWatchers, parseLabel, viewScope);
} else {
combinedLabels.push(step.name);
}
});
scope.ncyBreadcrumbChain = combinedLabels.join(separator);
};
$rootScope.$on('$viewContentLoaded', function (event) {
if(!event.targetScope.ncyBreadcrumbIgnore) {
renderLabel();
}
});
// View(s) may be already loaded while the directive's linking
renderLabel();
}
};
}
};
}
BreadcrumbTextDirective.$inject = ['$interpolate', '$breadcrumb', '$rootScope'];
angular.module('ncy-angular-breadcrumb', ['ui.router.state'])
.provider('$breadcrumb', $Breadcrumb)
.directive('ncyBreadcrumb', BreadcrumbDirective)
.directive('ncyBreadcrumbLast', BreadcrumbLastDirective)
.directive('ncyBreadcrumbText', BreadcrumbTextDirective);
})(window, window.angular);

View File

@ -0,0 +1,4 @@
/*! angular-breadcrumb - v0.4.0-dev-2015-08-07
* http://ncuillery.github.io/angular-breadcrumb
* Copyright (c) 2015 Nicolas Cuillery; Licensed MIT */
!function(a,b,c){"use strict";function d(a,c){return b.equals(a.length,c.length)?a>c:a.length>c.length}function e(a){var b=a.replace(/\n/g," ").match(/^([^(]+?)\s*(\((.*)\))?$/);if(!b||4!==b.length)throw new Error("Invalid state ref '"+a+"'");return{state:b[1],paramExpr:b[3]||null}}function f(){var a={prefixStateName:null,template:"bootstrap3",templateUrl:null,includeAbstract:!1};this.setOptions=function(c){b.extend(a,c)},this.$get=["$state","$stateParams","$rootScope",function(b,f,g){var h=g;g.$on("$viewContentLoaded",function(a){!a.targetScope.ncyBreadcrumbIgnore&&d(a.targetScope.$id,h.$id)&&(h=a.targetScope)});var i=function(a){var b=a.parent||(/^(.+)\.[^.]+$/.exec(a.name)||[])[1],c="object"==typeof b;return c?b.name:b},j=function(c,d){for(var g,i,j=e(d),k=!1,l=!1,m=0,n=c.length;n>m;m+=1)if(c[m].name===j.state)return;g=b.get(j.state),g.ncyBreadcrumb&&(g.ncyBreadcrumb.force&&(k=!0),g.ncyBreadcrumb.skip&&(l=!0)),g["abstract"]&&!a.includeAbstract&&!k||l||(j.paramExpr&&(i=h.$eval(j.paramExpr)),g.ncyBreadcrumbLink=b.href(j.state,i||f||{}),c.unshift(g))},k=function(a){var c=e(a),d=b.get(c.state);if(d.ncyBreadcrumb&&d.ncyBreadcrumb.parent){var f="function"==typeof d.ncyBreadcrumb.parent,g=f?d.ncyBreadcrumb.parent(h):d.ncyBreadcrumb.parent;if(g)return g}return i(d)};return{getTemplate:function(b){return a.templateUrl?null:b[a.template]?b[a.template]:a.template},getTemplateUrl:function(){return a.templateUrl},getStatesChain:function(c){for(var d=[],e=b.$current.self.name;e;e=k(e))if(j(d,e),c&&d.length)return d;return a.prefixStateName&&j(d,a.prefixStateName),d},getLastStep:function(){var a=this.getStatesChain(!0);return a.length?a[0]:c},$getLastViewScope:function(){return h}}}]}function g(a,c,d){var e={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:!0,scope:{},template:c.getTemplate(e),templateUrl:c.getTemplateUrl(),link:{post:function(e){var f=[],g=function(){l(f),f=[];var d=c.$getLastViewScope();e.steps=c.getStatesChain(),b.forEach(e.steps,function(b){if(b.ncyBreadcrumb&&b.ncyBreadcrumb.label){var c=a(b.ncyBreadcrumb.label);b.ncyBreadcrumbLabel=c(d),k(f,c,d,b)}else b.ncyBreadcrumbLabel=b.name})};d.$on("$viewContentLoaded",function(a){a.targetScope.ncyBreadcrumbIgnore||g()}),g()}}}}function h(a,b,c){return{restrict:"A",scope:{},template:"{{ncyBreadcrumbLabel}}",compile:function(d,e){var f=d.attr(e.$attr.ncyBreadcrumbLast);return f&&d.html(f),{post:function(d){var e=[],f=function(){l(e),e=[];var c=b.$getLastViewScope(),f=b.getLastStep();if(f)if(d.ncyBreadcrumbLink=f.ncyBreadcrumbLink,f.ncyBreadcrumb&&f.ncyBreadcrumb.label){var g=a(f.ncyBreadcrumb.label);d.ncyBreadcrumbLabel=g(c),k(e,g,c,d)}else d.ncyBreadcrumbLabel=f.name};c.$on("$viewContentLoaded",function(a){a.targetScope.ncyBreadcrumbIgnore||f()}),f()}}}}}function i(a,c,d){return{restrict:"A",scope:{},template:"{{ncyBreadcrumbChain}}",compile:function(e,f){var g=e.attr(f.$attr.ncyBreadcrumbText);g&&e.html(g);var h=e.attr(f.$attr.ncyBreadcrumbTextSeparator)||" / ";return{post:function(e){var f=[],g=function(a,c,d){b.forEach(j(c),function(b){var c=d.$watch(b,function(a,b){a!==b&&i()});a.push(c)})},i=function(){l(f),f=[];var d=c.$getLastViewScope(),i=c.getStatesChain(),j=[];b.forEach(i,function(b){if(b.ncyBreadcrumb&&b.ncyBreadcrumb.label){var c=a(b.ncyBreadcrumb.label);j.push(c(d)),g(f,c,d)}else j.push(b.name)}),e.ncyBreadcrumbChain=j.join(h)};d.$on("$viewContentLoaded",function(a){a.targetScope.ncyBreadcrumbIgnore||i()}),i()}}}}}var j=function(a){if(a.expressions)return a.expressions;var c=[];return b.forEach(a.parts,function(a){b.isFunction(a)&&c.push(a.exp)}),c},k=function(a,c,d,e){b.forEach(j(c),function(b){var f=d.$watch(b,function(){e.ncyBreadcrumbLabel=c(d)});a.push(f)})},l=function(a){b.forEach(a,function(a){a()})};g.$inject=["$interpolate","$breadcrumb","$rootScope"],h.$inject=["$interpolate","$breadcrumb","$rootScope"],i.$inject=["$interpolate","$breadcrumb","$rootScope"],b.module("ncy-angular-breadcrumb",["ui.router.state"]).provider("$breadcrumb",f).directive("ncyBreadcrumb",g).directive("ncyBreadcrumbLast",h).directive("ncyBreadcrumbText",i)}(window,window.angular);

View File

@ -0,0 +1,369 @@
/*! angular-breadcrumb - v0.4.1
* http://ncuillery.github.io/angular-breadcrumb
* Copyright (c) 2015 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(!event.targetScope.ncyBreadcrumbIgnore &&
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 parent = state.parent || (/^(.+)\.[^.]+$/.exec(state.name) || [])[1];
var isObjectParent = typeof parent === "object";
// if parent is a object reference, then extract the name
return isObjectParent ? parent.name : parent;
};
// 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),
force = false,
skip = false;
for(var i=0, l=chain.length; i<l; i+=1) {
if (chain[i].name === ref.state) {
return;
}
}
conf = $state.get(ref.state);
// Get breadcrumb options
if(conf.ncyBreadcrumb) {
if(conf.ncyBreadcrumb.force){ force = true; }
if(conf.ncyBreadcrumb.skip){ skip = true; }
}
if((!conf.abstract || $$options.includeAbstract || force) && !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();
});
};
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);
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 (event) {
if(!event.targetScope.ncyBreadcrumbIgnore) {
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);
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 (event) {
if(!event.targetScope.ncyBreadcrumbIgnore) {
renderLabel();
}
});
// View(s) may be already loaded while the directive's linking
renderLabel();
}
};
}
};
}
BreadcrumbLastDirective.$inject = ['$interpolate', '$breadcrumb', '$rootScope'];
function BreadcrumbTextDirective($interpolate, $breadcrumb, $rootScope) {
return {
restrict: 'A',
scope: {},
template: '{{ncyBreadcrumbChain}}',
compile: function(cElement, cAttrs) {
// Override the default template if ncyBreadcrumbText has a value
var template = cElement.attr(cAttrs.$attr.ncyBreadcrumbText);
if(template) {
cElement.html(template);
}
var separator = cElement.attr(cAttrs.$attr.ncyBreadcrumbTextSeparator) || ' / ';
return {
post: function postLink(scope) {
var labelWatchers = [];
var registerWatchersText = function(labelWatcherArray, interpolationFunction, viewScope) {
angular.forEach(getExpression(interpolationFunction), function(expression) {
var watcher = viewScope.$watch(expression, function(newValue, oldValue) {
if (newValue !== oldValue) {
renderLabel();
}
});
labelWatcherArray.push(watcher);
});
};
var renderLabel = function() {
deregisterWatchers(labelWatchers);
labelWatchers = [];
var viewScope = $breadcrumb.$getLastViewScope();
var steps = $breadcrumb.getStatesChain();
var combinedLabels = [];
angular.forEach(steps, function (step) {
if (step.ncyBreadcrumb && step.ncyBreadcrumb.label) {
var parseLabel = $interpolate(step.ncyBreadcrumb.label);
combinedLabels.push(parseLabel(viewScope));
// Watcher for further viewScope updates
registerWatchersText(labelWatchers, parseLabel, viewScope);
} else {
combinedLabels.push(step.name);
}
});
scope.ncyBreadcrumbChain = combinedLabels.join(separator);
};
$rootScope.$on('$viewContentLoaded', function (event) {
if(!event.targetScope.ncyBreadcrumbIgnore) {
renderLabel();
}
});
// View(s) may be already loaded while the directive's linking
renderLabel();
}
};
}
};
}
BreadcrumbTextDirective.$inject = ['$interpolate', '$breadcrumb', '$rootScope'];
angular.module('ncy-angular-breadcrumb', ['ui.router.state'])
.provider('$breadcrumb', $Breadcrumb)
.directive('ncyBreadcrumb', BreadcrumbDirective)
.directive('ncyBreadcrumbLast', BreadcrumbLastDirective)
.directive('ncyBreadcrumbText', BreadcrumbTextDirective);
})(window, window.angular);

View File

@ -0,0 +1,4 @@
/*! angular-breadcrumb - v0.4.1
* http://ncuillery.github.io/angular-breadcrumb
* Copyright (c) 2015 Nicolas Cuillery; Licensed MIT */
!function(a,b,c){"use strict";function d(a,c){return b.equals(a.length,c.length)?a>c:a.length>c.length}function e(a){var b=a.replace(/\n/g," ").match(/^([^(]+?)\s*(\((.*)\))?$/);if(!b||4!==b.length)throw new Error("Invalid state ref '"+a+"'");return{state:b[1],paramExpr:b[3]||null}}function f(){var a={prefixStateName:null,template:"bootstrap3",templateUrl:null,includeAbstract:!1};this.setOptions=function(c){b.extend(a,c)},this.$get=["$state","$stateParams","$rootScope",function(b,f,g){var h=g;g.$on("$viewContentLoaded",function(a){!a.targetScope.ncyBreadcrumbIgnore&&d(a.targetScope.$id,h.$id)&&(h=a.targetScope)});var i=function(a){var b=a.parent||(/^(.+)\.[^.]+$/.exec(a.name)||[])[1],c="object"==typeof b;return c?b.name:b},j=function(c,d){for(var g,i,j=e(d),k=!1,l=!1,m=0,n=c.length;n>m;m+=1)if(c[m].name===j.state)return;g=b.get(j.state),g.ncyBreadcrumb&&(g.ncyBreadcrumb.force&&(k=!0),g.ncyBreadcrumb.skip&&(l=!0)),g["abstract"]&&!a.includeAbstract&&!k||l||(j.paramExpr&&(i=h.$eval(j.paramExpr)),g.ncyBreadcrumbLink=b.href(j.state,i||f||{}),c.unshift(g))},k=function(a){var c=e(a),d=b.get(c.state);if(d.ncyBreadcrumb&&d.ncyBreadcrumb.parent){var f="function"==typeof d.ncyBreadcrumb.parent,g=f?d.ncyBreadcrumb.parent(h):d.ncyBreadcrumb.parent;if(g)return g}return i(d)};return{getTemplate:function(b){return a.templateUrl?null:b[a.template]?b[a.template]:a.template},getTemplateUrl:function(){return a.templateUrl},getStatesChain:function(c){for(var d=[],e=b.$current.self.name;e;e=k(e))if(j(d,e),c&&d.length)return d;return a.prefixStateName&&j(d,a.prefixStateName),d},getLastStep:function(){var a=this.getStatesChain(!0);return a.length?a[0]:c},$getLastViewScope:function(){return h}}}]}function g(a,c,d){var e={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:!0,scope:{},template:c.getTemplate(e),templateUrl:c.getTemplateUrl(),link:{post:function(e){var f=[],g=function(){l(f),f=[];var d=c.$getLastViewScope();e.steps=c.getStatesChain(),b.forEach(e.steps,function(b){if(b.ncyBreadcrumb&&b.ncyBreadcrumb.label){var c=a(b.ncyBreadcrumb.label);b.ncyBreadcrumbLabel=c(d),k(f,c,d,b)}else b.ncyBreadcrumbLabel=b.name})};d.$on("$viewContentLoaded",function(a){a.targetScope.ncyBreadcrumbIgnore||g()}),g()}}}}function h(a,b,c){return{restrict:"A",scope:{},template:"{{ncyBreadcrumbLabel}}",compile:function(d,e){var f=d.attr(e.$attr.ncyBreadcrumbLast);return f&&d.html(f),{post:function(d){var e=[],f=function(){l(e),e=[];var c=b.$getLastViewScope(),f=b.getLastStep();if(f)if(d.ncyBreadcrumbLink=f.ncyBreadcrumbLink,f.ncyBreadcrumb&&f.ncyBreadcrumb.label){var g=a(f.ncyBreadcrumb.label);d.ncyBreadcrumbLabel=g(c),k(e,g,c,d)}else d.ncyBreadcrumbLabel=f.name};c.$on("$viewContentLoaded",function(a){a.targetScope.ncyBreadcrumbIgnore||f()}),f()}}}}}function i(a,c,d){return{restrict:"A",scope:{},template:"{{ncyBreadcrumbChain}}",compile:function(e,f){var g=e.attr(f.$attr.ncyBreadcrumbText);g&&e.html(g);var h=e.attr(f.$attr.ncyBreadcrumbTextSeparator)||" / ";return{post:function(e){var f=[],g=function(a,c,d){b.forEach(j(c),function(b){var c=d.$watch(b,function(a,b){a!==b&&i()});a.push(c)})},i=function(){l(f),f=[];var d=c.$getLastViewScope(),i=c.getStatesChain(),j=[];b.forEach(i,function(b){if(b.ncyBreadcrumb&&b.ncyBreadcrumb.label){var c=a(b.ncyBreadcrumb.label);j.push(c(d)),g(f,c,d)}else j.push(b.name)}),e.ncyBreadcrumbChain=j.join(h)};d.$on("$viewContentLoaded",function(a){a.targetScope.ncyBreadcrumbIgnore||i()}),i()}}}}}var j=function(a){if(a.expressions)return a.expressions;var c=[];return b.forEach(a.parts,function(a){b.isFunction(a)&&c.push(a.exp)}),c},k=function(a,c,d,e){b.forEach(j(c),function(b){var f=d.$watch(b,function(){e.ncyBreadcrumbLabel=c(d)});a.push(f)})},l=function(a){b.forEach(a,function(a){a()})};g.$inject=["$interpolate","$breadcrumb","$rootScope"],h.$inject=["$interpolate","$breadcrumb","$rootScope"],i.$inject=["$interpolate","$breadcrumb","$rootScope"],b.module("ncy-angular-breadcrumb",["ui.router.state"]).provider("$breadcrumb",f).directive("ncyBreadcrumb",g).directive("ncyBreadcrumbLast",h).directive("ncyBreadcrumbText",i)}(window,window.angular);

View File

@ -186,7 +186,8 @@ var tower = angular.module('Tower', [
'features',
'longDateFilter',
'pendolytics',
'ui.router'
'ui.router',
'ncy-angular-breadcrumb'
])
.constant('AngularScheduler.partials', urlPrefix + 'lib/angular-scheduler/lib/')
@ -773,15 +774,15 @@ var tower = angular.module('Tower', [
state('dashboard', {
url: '/home',
templateUrl: urlPrefix + 'partials/home.html',
controller: Home,
resolve: {
graphData: ['$q', 'jobStatusGraphData', 'FeaturesService', function($q, jobStatusGraphData, FeaturesService) {
return $q.all({
jobStatus: jobStatusGraphData.get("month", "all"),
features: FeaturesService.get()
});
}]
}
controller: Home
// resolve: {
// graphData: ['$q', 'jobStatusGraphData', 'FeaturesService', function($q, jobStatusGraphData, FeaturesService) {
// return $q.all({
// jobStatus: jobStatusGraphData.get("month", "all"),
// features: FeaturesService.get()
// });
// }]
// }
}).
state('dashboardGroups', {