├── .gitignore ├── app ├── html │ ├── playlist.html │ ├── query-form.html │ └── index.html ├── css │ └── style.css ├── app.js └── javascript │ └── services │ └── services.js ├── .bowerrc ├── .floo ├── .flooignore ├── bower_components ├── angular-echonest │ ├── .gitignore │ ├── bower.json │ ├── .travis.yml │ ├── .bower.json │ ├── package.json │ ├── LICENSE │ ├── Gruntfile.js │ ├── karma.config.js │ ├── build │ │ ├── angular-echonest.min.js │ │ └── angular-echonest.js │ ├── test │ │ ├── songs.js │ │ └── artists.js │ ├── README.md │ └── src │ │ └── angular-echonest.js ├── angular │ ├── angular.min.js.gzip │ ├── bower.json │ ├── angular-csp.css │ ├── .bower.json │ ├── package.json │ └── README.md ├── angular-mocks │ ├── bower.json │ ├── .bower.json │ ├── package.json │ └── README.md └── ui-router │ ├── bower.json │ ├── .bower.json │ ├── LICENSE │ ├── src │ ├── stateFilters.js │ ├── viewScroll.js │ ├── view.js │ ├── templateFactory.js │ ├── common.js │ ├── viewDirective.js │ ├── stateDirectives.js │ ├── resolve.js │ └── urlRouter.js │ ├── CONTRIBUTING.md │ ├── api │ └── angular-ui-router.d.ts │ ├── README.md │ ├── CHANGELOG.md │ └── release │ └── angular-ui-router.min.js ├── echonest-sample.js ├── README.md └── index.html /.gitignore: -------------------------------------------------------------------------------- 1 | /echonest.js -------------------------------------------------------------------------------- /app/html/playlist.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/css/style.css: -------------------------------------------------------------------------------- 1 | style.css 2 | -------------------------------------------------------------------------------- /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "bower_components" 3 | } 4 | -------------------------------------------------------------------------------- /.floo: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://floobits.com/HackReactor/Muse" 3 | } -------------------------------------------------------------------------------- /.flooignore: -------------------------------------------------------------------------------- 1 | #* 2 | *.o 3 | *.pyc 4 | *~ 5 | extern/ 6 | node_modules/ 7 | tmp 8 | vendor/ -------------------------------------------------------------------------------- /bower_components/angular-echonest/.gitignore: -------------------------------------------------------------------------------- 1 | app/ 2 | node_modules/ 3 | bower_components/ 4 | .DS_Store -------------------------------------------------------------------------------- /bower_components/angular/angular.min.js.gzip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicmitchell/muse/HEAD/bower_components/angular/angular.min.js.gzip -------------------------------------------------------------------------------- /bower_components/angular-echonest/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-echonest", 3 | "version": "0.2.5", 4 | "main": "build/angular-echonest.js" 5 | } -------------------------------------------------------------------------------- /echonest-sample.js: -------------------------------------------------------------------------------- 1 | // Replace the value below with your EchoNest API key 2 | // Uncomment the line 3 | // Rename this file to 'echonest.js' 4 | // var echonestApiKey = 'API KEY'; -------------------------------------------------------------------------------- /bower_components/angular/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular", 3 | "version": "1.3.5", 4 | "main": "./angular.js", 5 | "ignore": [], 6 | "dependencies": { 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /bower_components/angular-mocks/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-mocks", 3 | "version": "1.3.5", 4 | "main": "./angular-mocks.js", 5 | "ignore": [], 6 | "dependencies": { 7 | "angular": "1.3.5" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /bower_components/angular-echonest/.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 0.10 4 | before_script: 5 | - export DISPLAY=:99.0 6 | - sh -e /etc/init.d/xvfb start 7 | - npm install -g grunt-cli 8 | - npm install -g bower 9 | - bower install angular 10 | - bower install angular-mocks -------------------------------------------------------------------------------- /bower_components/angular/angular-csp.css: -------------------------------------------------------------------------------- 1 | /* Include this file in your html if you are using the CSP mode. */ 2 | 3 | @charset "UTF-8"; 4 | 5 | [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], 6 | .ng-cloak, .x-ng-cloak, 7 | .ng-hide:not(.ng-hide-animate) { 8 | display: none !important; 9 | } 10 | 11 | ng\:form { 12 | display: block; 13 | } 14 | -------------------------------------------------------------------------------- /app/html/query-form.html: -------------------------------------------------------------------------------- 1 |
2 |

Artist

3 | 4 |

Title

5 | 6 | 7 |

Searching for {{artist}} {{title}}

8 |
9 | -------------------------------------------------------------------------------- /bower_components/angular-echonest/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-echonest", 3 | "main": "build/angular-echonest.js", 4 | "homepage": "https://github.com/Kraku/angular-echonest", 5 | "_release": "65f49da82b", 6 | "_resolution": { 7 | "type": "branch", 8 | "branch": "master", 9 | "commit": "65f49da82b7d43b993c02e1ace30e4092ceed2b2" 10 | }, 11 | "_source": "git://github.com/Kraku/angular-echonest.git", 12 | "_target": "*", 13 | "_originalSource": "angular-echonest", 14 | "_direct": true 15 | } -------------------------------------------------------------------------------- /bower_components/ui-router/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-ui-router", 3 | "version": "0.2.13", 4 | "main": "./release/angular-ui-router.js", 5 | "dependencies": { 6 | "angular": ">= 1.0.8" 7 | }, 8 | "ignore": [ 9 | "**/.*", 10 | "node_modules", 11 | "bower_components", 12 | "component.json", 13 | "package.json", 14 | "lib", 15 | "config", 16 | "sample", 17 | "test", 18 | "tests", 19 | "ngdoc_assets", 20 | "Gruntfile.js", 21 | "files.js" 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /bower_components/angular/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular", 3 | "version": "1.3.5", 4 | "main": "./angular.js", 5 | "ignore": [], 6 | "dependencies": {}, 7 | "homepage": "https://github.com/angular/bower-angular", 8 | "_release": "1.3.5", 9 | "_resolution": { 10 | "type": "version", 11 | "tag": "v1.3.5", 12 | "commit": "9acb014af4fd7b0ab001c64fa7bcac454ab4050b" 13 | }, 14 | "_source": "git://github.com/angular/bower-angular.git", 15 | "_target": "1.3.5", 16 | "_originalSource": "angular" 17 | } -------------------------------------------------------------------------------- /bower_components/angular-mocks/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-mocks", 3 | "version": "1.3.5", 4 | "main": "./angular-mocks.js", 5 | "ignore": [], 6 | "dependencies": { 7 | "angular": "1.3.5" 8 | }, 9 | "homepage": "https://github.com/angular/bower-angular-mocks", 10 | "_release": "1.3.5", 11 | "_resolution": { 12 | "type": "version", 13 | "tag": "v1.3.5", 14 | "commit": "e5356ca3fa80f824ac7e3d9651156401e6bf2a38" 15 | }, 16 | "_source": "git://github.com/angular/bower-angular-mocks.git", 17 | "_target": "~1.3.5", 18 | "_originalSource": "angular-mocks", 19 | "_direct": true 20 | } -------------------------------------------------------------------------------- /bower_components/angular/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular", 3 | "version": "1.3.5", 4 | "description": "HTML enhanced for web apps", 5 | "main": "angular.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/angular/angular.js.git" 12 | }, 13 | "keywords": [ 14 | "angular", 15 | "framework", 16 | "browser", 17 | "client-side" 18 | ], 19 | "author": "Angular Core Team ", 20 | "license": "MIT", 21 | "bugs": { 22 | "url": "https://github.com/angular/angular.js/issues" 23 | }, 24 | "homepage": "http://angularjs.org" 25 | } 26 | -------------------------------------------------------------------------------- /bower_components/angular-mocks/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-mocks", 3 | "version": "1.3.5", 4 | "description": "AngularJS mocks for testing", 5 | "main": "angular-mocks.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/angular/angular.js.git" 12 | }, 13 | "keywords": [ 14 | "angular", 15 | "framework", 16 | "browser", 17 | "mocks", 18 | "testing", 19 | "client-side" 20 | ], 21 | "author": "Angular Core Team ", 22 | "license": "MIT", 23 | "bugs": { 24 | "url": "https://github.com/angular/angular.js/issues" 25 | }, 26 | "homepage": "http://angularjs.org" 27 | } 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Muse 2 | A smarter, smart playlist built with Angular and Foundation utilizing song data from the EchoNest API. Users can adjust playlist setting by changing desired levels for tempo, popularity, danceability, and other factors 3 | 4 | ## Usage 5 | Enter an artist and song name and click "Search" 6 | Adjust the range sliders for danceability, energy, etc. 7 | Click "Update Playlist" to get a new set of songs 8 | 9 | ## Getting Started 10 | - [Obtain an EchoNest API key](http://developer.echonest.com/raw_tutorials/register.html) 11 | - Follow the instructions in the `echonest-sample.js` file: 12 | - Add your API key 13 | - Uncomment the line 14 | - Rename the file to `echonest.js` 15 | 16 | ## Screenshot 17 | ====== 18 | 19 | ![Screenshot](http://i.imgur.com/EwQ9jda.png) 20 | -------------------------------------------------------------------------------- /bower_components/angular-echonest/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-echonest", 3 | "description": "Echonest adapter for AngularJS.", 4 | "version": "0.2.5", 5 | "author": "Maciej Podsiedlak ", 6 | "main": "angular-echonest.js", 7 | "repository": { 8 | "type": "git", 9 | "url": "https://github.com/kraku/angular-echonest" 10 | }, 11 | "dependencies": { 12 | "grunt-contrib-connect": "0.2.0", 13 | "grunt-contrib-uglify": "*", 14 | "grunt-contrib-watch": "*", 15 | "grunt-contrib-copy": "*", 16 | "karma": "~0.12.0", 17 | "grunt-karma": "~0.8.2", 18 | "karma-jasmine": "~0.2.2", 19 | "karma-phantomjs-launcher": "~0.1.2" 20 | }, 21 | "scripts": { 22 | "test": "./node_modules/karma/bin/karma start karma.config.js --no-auto-watch --single-run --reporters=dots --browsers=PhantomJS" 23 | } 24 | } -------------------------------------------------------------------------------- /bower_components/ui-router/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-ui-router", 3 | "version": "0.2.13", 4 | "main": "./release/angular-ui-router.js", 5 | "dependencies": { 6 | "angular": ">= 1.0.8" 7 | }, 8 | "ignore": [ 9 | "**/.*", 10 | "node_modules", 11 | "bower_components", 12 | "component.json", 13 | "package.json", 14 | "lib", 15 | "config", 16 | "sample", 17 | "test", 18 | "tests", 19 | "ngdoc_assets", 20 | "Gruntfile.js", 21 | "files.js" 22 | ], 23 | "homepage": "https://github.com/angular-ui/ui-router", 24 | "_release": "0.2.13", 25 | "_resolution": { 26 | "type": "version", 27 | "tag": "0.2.13", 28 | "commit": "c3d543aae43d4600512520a0d70723ac31f2cb62" 29 | }, 30 | "_source": "git://github.com/angular-ui/ui-router.git", 31 | "_target": "~0.2.13", 32 | "_originalSource": "ui-router", 33 | "_direct": true 34 | } -------------------------------------------------------------------------------- /bower_components/angular-echonest/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /bower_components/ui-router/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2014 The AngularUI Team, Karsten Sperling 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /bower_components/ui-router/src/stateFilters.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @ngdoc filter 3 | * @name ui.router.state.filter:isState 4 | * 5 | * @requires ui.router.state.$state 6 | * 7 | * @description 8 | * Translates to {@link ui.router.state.$state#methods_is $state.is("stateName")}. 9 | */ 10 | $IsStateFilter.$inject = ['$state']; 11 | function $IsStateFilter($state) { 12 | var isFilter = function (state) { 13 | return $state.is(state); 14 | }; 15 | isFilter.$stateful = true; 16 | return isFilter; 17 | } 18 | 19 | /** 20 | * @ngdoc filter 21 | * @name ui.router.state.filter:includedByState 22 | * 23 | * @requires ui.router.state.$state 24 | * 25 | * @description 26 | * Translates to {@link ui.router.state.$state#methods_includes $state.includes('fullOrPartialStateName')}. 27 | */ 28 | $IncludedByStateFilter.$inject = ['$state']; 29 | function $IncludedByStateFilter($state) { 30 | var includesFilter = function (state) { 31 | return $state.includes(state); 32 | }; 33 | includesFilter.$stateful = true; 34 | return includesFilter; 35 | } 36 | 37 | angular.module('ui.router.state') 38 | .filter('isState', $IsStateFilter) 39 | .filter('includedByState', $IncludedByStateFilter); 40 | -------------------------------------------------------------------------------- /bower_components/angular-echonest/Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function (grunt) { 2 | grunt.initConfig({ 3 | pkg: grunt.file.readJSON('package.json'), 4 | 5 | connect: { 6 | server: { 7 | options: { 8 | port: 8080, 9 | hostname: 'localhost' 10 | } 11 | } 12 | }, 13 | 14 | uglify: { 15 | build: { 16 | files: { 17 | 'build/angular-echonest.min.js': ['src/angular-echonest.js'] 18 | } 19 | } 20 | }, 21 | 22 | copy: { 23 | main: { 24 | files: [ 25 | { 26 | expand: true, 27 | cwd: 'src/', 28 | src: 'angular-echonest.js', 29 | dest: 'build/' 30 | } 31 | ] 32 | } 33 | }, 34 | 35 | watch: { 36 | scripts: { 37 | files: ['src/*.js'], 38 | tasks: ['build'], 39 | options: { 40 | livereload: true 41 | }, 42 | } 43 | }, 44 | 45 | karma: { 46 | unit: { 47 | configFile: 'karma.config.js' 48 | } 49 | } 50 | }); 51 | 52 | grunt.loadNpmTasks('grunt-contrib-connect'); 53 | grunt.loadNpmTasks('grunt-contrib-uglify'); 54 | grunt.loadNpmTasks('grunt-contrib-watch'); 55 | grunt.loadNpmTasks('grunt-contrib-copy'); 56 | grunt.loadNpmTasks('grunt-karma'); 57 | 58 | grunt.registerTask('serve', ['connect', 'watch']); 59 | grunt.registerTask('build', ['uglify', 'copy']); 60 | }; -------------------------------------------------------------------------------- /bower_components/ui-router/src/viewScroll.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @ngdoc object 3 | * @name ui.router.state.$uiViewScrollProvider 4 | * 5 | * @description 6 | * Provider that returns the {@link ui.router.state.$uiViewScroll} service function. 7 | */ 8 | function $ViewScrollProvider() { 9 | 10 | var useAnchorScroll = false; 11 | 12 | /** 13 | * @ngdoc function 14 | * @name ui.router.state.$uiViewScrollProvider#useAnchorScroll 15 | * @methodOf ui.router.state.$uiViewScrollProvider 16 | * 17 | * @description 18 | * Reverts back to using the core [`$anchorScroll`](http://docs.angularjs.org/api/ng.$anchorScroll) service for 19 | * scrolling based on the url anchor. 20 | */ 21 | this.useAnchorScroll = function () { 22 | useAnchorScroll = true; 23 | }; 24 | 25 | /** 26 | * @ngdoc object 27 | * @name ui.router.state.$uiViewScroll 28 | * 29 | * @requires $anchorScroll 30 | * @requires $timeout 31 | * 32 | * @description 33 | * When called with a jqLite element, it scrolls the element into view (after a 34 | * `$timeout` so the DOM has time to refresh). 35 | * 36 | * If you prefer to rely on `$anchorScroll` to scroll the view to the anchor, 37 | * this can be enabled by calling {@link ui.router.state.$uiViewScrollProvider#methods_useAnchorScroll `$uiViewScrollProvider.useAnchorScroll()`}. 38 | */ 39 | this.$get = ['$anchorScroll', '$timeout', function ($anchorScroll, $timeout) { 40 | if (useAnchorScroll) { 41 | return $anchorScroll; 42 | } 43 | 44 | return function ($element) { 45 | $timeout(function () { 46 | $element[0].scrollIntoView(); 47 | }, 0, false); 48 | }; 49 | }]; 50 | } 51 | 52 | angular.module('ui.router.state').provider('$uiViewScroll', $ViewScrollProvider); 53 | -------------------------------------------------------------------------------- /bower_components/angular-echonest/karma.config.js: -------------------------------------------------------------------------------- 1 | // Karma configuration 2 | // Generated on Tue Mar 04 2014 19:50:43 GMT+0100 (CET) 3 | 4 | module.exports = function(config) { 5 | config.set({ 6 | 7 | // base path, that will be used to resolve files and exclude 8 | basePath: '', 9 | 10 | 11 | // frameworks to use 12 | frameworks: ['jasmine'], 13 | 14 | 15 | // list of files / patterns to load in the browser 16 | files: [ 17 | 'bower_components/angular/angular.js', 18 | 'bower_components/angular-mocks/angular-mocks.js', 19 | 'src/*.js', 20 | 'test/*.js' 21 | ], 22 | 23 | 24 | // list of files to exclude 25 | exclude: [ 26 | 27 | ], 28 | 29 | 30 | // test results reporter to use 31 | // possible values: 'dots', 'progress', 'junit', 'growl', 'coverage' 32 | reporters: ['progress'], 33 | 34 | 35 | // web server port 36 | port: 9876, 37 | 38 | 39 | // enable / disable colors in the output (reporters and logs) 40 | colors: true, 41 | 42 | 43 | // level of logging 44 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG 45 | logLevel: config.LOG_INFO, 46 | 47 | 48 | // enable / disable watching file and executing tests whenever any file changes 49 | autoWatch: true, 50 | 51 | 52 | // Start these browsers, currently available: 53 | // - Chrome 54 | // - ChromeCanary 55 | // - Firefox 56 | // - Opera (has to be installed with `npm install karma-opera-launcher`) 57 | // - Safari (only Mac; has to be installed with `npm install karma-safari-launcher`) 58 | // - PhantomJS 59 | // - IE (only Windows; has to be installed with `npm install karma-ie-launcher`) 60 | browsers: ['PhantomJS'], 61 | 62 | 63 | // If browser does not capture in given timeout [ms], kill it 64 | captureTimeout: 60000, 65 | 66 | 67 | // Continuous Integration mode 68 | // if true, it capture browsers, run tests and exit 69 | singleRun: false 70 | }); 71 | }; 72 | -------------------------------------------------------------------------------- /app/html/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Muse 11 | 12 | 13 | 14 |

Muse

15 |
16 | 17 |
18 |
19 |
20 |
21 |

** HIDDEN ** Artist

22 | 23 |

Danceability

24 | {{danceability}} 25 |

Energy

26 | {{energy}} 27 | 28 |
29 |

Playlist

30 |
31 |
Artist: {{song.artist_name}}
32 |
Song: {{song.title}}
33 |
34 |
35 |
36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /bower_components/angular-mocks/README.md: -------------------------------------------------------------------------------- 1 | # packaged angular-mocks 2 | 3 | This repo is for distribution on `npm` and `bower`. The source for this module is in the 4 | [main AngularJS repo](https://github.com/angular/angular.js/tree/master/src/ngMock). 5 | Please file issues and pull requests against that repo. 6 | 7 | ## Install 8 | 9 | You can install this package either with `npm` or with `bower`. 10 | 11 | ### npm 12 | 13 | ```shell 14 | npm install angular-mocks 15 | ``` 16 | 17 | The mocks are then available at `node_modules/angular-mocks/angular-mocks.js`. 18 | 19 | Note that this package is not in CommonJS format, so doing `require('angular-mocks')` will 20 | return `undefined`. 21 | 22 | ### bower 23 | 24 | ```shell 25 | bower install angular-mocks 26 | ``` 27 | 28 | The mocks are then available at `bower_components/angular-mocks/angular-mocks.js`. 29 | 30 | ## Documentation 31 | 32 | Documentation is available on the 33 | [AngularJS docs site](https://docs.angularjs.org/guide/unit-testing). 34 | 35 | ## License 36 | 37 | The MIT License 38 | 39 | Copyright (c) 2010-2012 Google, Inc. http://angularjs.org 40 | 41 | Permission is hereby granted, free of charge, to any person obtaining a copy 42 | of this software and associated documentation files (the "Software"), to deal 43 | in the Software without restriction, including without limitation the rights 44 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 45 | copies of the Software, and to permit persons to whom the Software is 46 | furnished to do so, subject to the following conditions: 47 | 48 | The above copyright notice and this permission notice shall be included in 49 | all copies or substantial portions of the Software. 50 | 51 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 52 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 53 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 54 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 55 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 56 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 57 | THE SOFTWARE. 58 | -------------------------------------------------------------------------------- /bower_components/angular-echonest/build/angular-echonest.min.js: -------------------------------------------------------------------------------- 1 | !function(){"use strict";angular.module("angular-echonest",[]).provider("Echonest",function(){var a,b,c,d,e,f,g="http://developer.echonest.com/api/v4/",h="",i=function(a,b){var c=f.defer();return b.api_key=h,b.format="jsonp",b.callback="JSON_CALLBACK",e({method:"JSONP",url:g+a,params:b}).success(function(a){c.resolve(a.response)}),c.promise},j=function(a,b){var c=f.defer(),d=this;return b=b||{},b.id=d.id,i("artist/"+a,b).then(function(b){d[a]=b[a],c.resolve(d)}),c.promise},k=function(a){var b=[];if(a instanceof Object)for(var c in a)a.hasOwnProperty(c)&&(b[c]=a[c]);return b},l=function(b,c){return i("artist/"+b,c).then(function(b){var c=[];for(var d in b.artists)c.push(new a(b.artists[d]));return c})};this.setApiKey=function(a){h=a},a=function(a){if(a instanceof Object)for(var b in a)a.hasOwnProperty(b)&&(this[b]=a[b]);return this},a.prototype={getBiographies:function(a){return j.call(this,"biographies",a)},getBlogs:function(a){return j.call(this,"blogs",a)},getImages:function(a){return j.call(this,"images",a)},getNews:function(a){return j.call(this,"news",a)},getReviews:function(a){return j.call(this,"reviews",a)},getSongs:function(a){return j.call(this,"songs",a)},getFamiliarity:function(a){return j.call(this,"familiarity",a)},getHotnes:function(a){return j.call(this,"hotttnesss",a)},getSimilar:function(a){return j.call(this,"similar",a)},getTerms:function(a){return j.call(this,"terms",a)},getTwitter:function(a){return j.call(this,"twitter",a)},getUrls:function(a){return j.call(this,"urls",a)}},b=function(){return this},b.prototype={search:function(a){var b=k(a);return l.call(this,"search",b)},get:function(b){return b instanceof Object?i("artist/profile",b).then(function(b){return new a(b.artist)}):void 0},topHot:function(a){var b=k(a);return l.call(this,"top_hottt",b)},suggest:function(a){var b=k(a);return l.call(this,"suggest",b)},extract:function(a){var b=k(a);return l.call(this,"extract",b)}},c=function(){return this},c.prototype={search:function(a){var b=k(a);return i("song/search",b).then(function(a){return a.songs})},get:function(a){return a instanceof Object?i("song/profile",a).then(function(a){return a.songs[0]}):void 0},identify:function(a){var b=k(a);return i("song/identify",b).then(function(a){return a.songs})}},this.$get=["$http","$q",function(a,g){return e=a,f=g,d={artists:new b,songs:new c}}]})}(); -------------------------------------------------------------------------------- /bower_components/angular/README.md: -------------------------------------------------------------------------------- 1 | # packaged angular 2 | 3 | This repo is for distribution on `npm` and `bower`. The source for this module is in the 4 | [main AngularJS repo](https://github.com/angular/angular.js). 5 | Please file issues and pull requests against that repo. 6 | 7 | ## Install 8 | 9 | You can install this package either with `npm` or with `bower`. 10 | 11 | ### npm 12 | 13 | ```shell 14 | npm install angular 15 | ``` 16 | 17 | Then add a ` 21 | ``` 22 | 23 | Note that this package is not in CommonJS format, so doing `require('angular')` will return `undefined`. 24 | If you're using [Browserify](https://github.com/substack/node-browserify), you can use 25 | [exposify](https://github.com/thlorenz/exposify) to have `require('angular')` return the `angular` 26 | global. 27 | 28 | ### bower 29 | 30 | ```shell 31 | bower install angular 32 | ``` 33 | 34 | Then add a ` 38 | ``` 39 | 40 | ## Documentation 41 | 42 | Documentation is available on the 43 | [AngularJS docs site](http://docs.angularjs.org/). 44 | 45 | ## License 46 | 47 | The MIT License 48 | 49 | Copyright (c) 2010-2012 Google, Inc. http://angularjs.org 50 | 51 | Permission is hereby granted, free of charge, to any person obtaining a copy 52 | of this software and associated documentation files (the "Software"), to deal 53 | in the Software without restriction, including without limitation the rights 54 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 55 | copies of the Software, and to permit persons to whom the Software is 56 | furnished to do so, subject to the following conditions: 57 | 58 | The above copyright notice and this permission notice shall be included in 59 | all copies or substantial portions of the Software. 60 | 61 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 62 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 63 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 64 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 65 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 66 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 67 | THE SOFTWARE. 68 | -------------------------------------------------------------------------------- /bower_components/ui-router/src/view.js: -------------------------------------------------------------------------------- 1 | 2 | $ViewProvider.$inject = []; 3 | function $ViewProvider() { 4 | 5 | this.$get = $get; 6 | /** 7 | * @ngdoc object 8 | * @name ui.router.state.$view 9 | * 10 | * @requires ui.router.util.$templateFactory 11 | * @requires $rootScope 12 | * 13 | * @description 14 | * 15 | */ 16 | $get.$inject = ['$rootScope', '$templateFactory']; 17 | function $get( $rootScope, $templateFactory) { 18 | return { 19 | // $view.load('full.viewName', { template: ..., controller: ..., resolve: ..., async: false, params: ... }) 20 | /** 21 | * @ngdoc function 22 | * @name ui.router.state.$view#load 23 | * @methodOf ui.router.state.$view 24 | * 25 | * @description 26 | * 27 | * @param {string} name name 28 | * @param {object} options option object. 29 | */ 30 | load: function load(name, options) { 31 | var result, defaults = { 32 | template: null, controller: null, view: null, locals: null, notify: true, async: true, params: {} 33 | }; 34 | options = extend(defaults, options); 35 | 36 | if (options.view) { 37 | result = $templateFactory.fromConfig(options.view, options.params, options.locals); 38 | } 39 | if (result && options.notify) { 40 | /** 41 | * @ngdoc event 42 | * @name ui.router.state.$state#$viewContentLoading 43 | * @eventOf ui.router.state.$view 44 | * @eventType broadcast on root scope 45 | * @description 46 | * 47 | * Fired once the view **begins loading**, *before* the DOM is rendered. 48 | * 49 | * @param {Object} event Event object. 50 | * @param {Object} viewConfig The view config properties (template, controller, etc). 51 | * 52 | * @example 53 | * 54 | *
55 |          * $scope.$on('$viewContentLoading',
56 |          * function(event, viewConfig){
57 |          *     // Access to all the view config properties.
58 |          *     // and one special property 'targetView'
59 |          *     // viewConfig.targetView
60 |          * });
61 |          * 
62 | */ 63 | $rootScope.$broadcast('$viewContentLoading', options); 64 | } 65 | return result; 66 | } 67 | }; 68 | } 69 | } 70 | 71 | angular.module('ui.router.state').provider('$view', $ViewProvider); 72 | -------------------------------------------------------------------------------- /app/app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var muse = angular.module('muse', [ 4 | 'services', 5 | 'ui.router' 6 | ]); 7 | 8 | muse.config(function($stateProvider){ 9 | $stateProvider 10 | .state("query", { 11 | url: '/query', 12 | templateUrl: 'app/html/query-form.html', 13 | controller: 'QueryController' 14 | }); 15 | }); 16 | 17 | muse.controller("QueryController", function($scope,$http, $q, EchonestFactory) { 18 | //USE songs/artist suggest for error handling 19 | //Search for songs based on query 20 | $scope.search = function(artist,title){ 21 | EchonestFactory.search(artist,title); 22 | } 23 | 24 | // var defer = $q.defer(); 25 | 26 | // defer.promise.then(function () { 27 | // console.log(EchonestFactory.results.audio_summary.audio_summary.danceability); 28 | // $scope.danceability = EchonestFactory.results.audio_summary.audio_summary.danceability; 29 | // $scope.energy = EchonestFactory.results.audio_summary.audio_summary.energy; 30 | // $scope.instrumentalness = EchonestFactory.results.audio_summary.audio_summary.instrumentalness; 31 | // $scope.liveness = EchonestFactory.results.audio_summary.audio_summary.liveness; 32 | // $scope.speachiness = EchonestFactory.results.audio_summary.audio_summary.speachiness; 33 | // $scope.initial = EchonestFactory.results.songs[0]; 34 | // }); 35 | 36 | // defer.resolve(); 37 | }); 38 | 39 | 40 | muse.controller("PlaylistController", function($scope,$http, PlaylistFactory, EchonestFactory) { 41 | 42 | $scope.search = function(artist, danceability, energy){ 43 | var playlist = PlaylistFactory.search(EchonestFactory.results.artist_summary.name, danceability, energy); 44 | $scope.playlist = PlaylistFactory.results; 45 | // console.log('PLAYLIST RESULTS', $scope.playlist); 46 | }; 47 | 48 | }); 49 | 50 | 51 | 52 | muse.controller("YoutubeController", function($scope,$http, YoutubeFactory, EchonestFactory) { 53 | 54 | 55 | $scope.youtubeSearch = function(artist, title){ 56 | console.log(EchonestFactory.results); 57 | YoutubeFactory.search(artist, title); 58 | // YoutubeFactory.search(EchonestFactory.results.songs[0].artist_name, EchonestFactory.results.songs[0].title); 59 | console.log('YOUTUBE CONTROLLER', YoutubeFactory); 60 | // $scope.initialDanceability = PlaylistFactory.search($scope.selectedArtist, danceability, energy)[0] 61 | }; 62 | 63 | $scope.vidId = YoutubeFactory.results.vidId; 64 | }); 65 | 66 | 67 | // create a playlist 68 | // based on: 69 | // genre 70 | // specicied audio_buckets (danceability) 71 | 72 | 73 | // max_danceability no no 0.0 < danceability < 1.0 the maximum danceability of any song 74 | // min_danceability no no 0.0 < danceability < 1.0 the minimum danceability of any song 75 | 76 | //EXPERIMENTAL SPEECH QUERY 77 | // Generates a 20 song playlist of popular music from the 70s sorted by increasing tempo 78 | // http://developer.echonest.com/api/v4/playlist/static?api_key=CNQ7EJLGCHNW8QOIT&description=70s&description=disco&type=artist-description&artist_min_familiarity=.7&sort=tempo-asc&results=20 79 | -------------------------------------------------------------------------------- /bower_components/angular-echonest/test/songs.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('Artists', function() { 4 | var echonest, httpBackend; 5 | var apiUrl = 'http://developer.echonest.com/api/v4/'; 6 | 7 | var songsApiResponse = { 8 | response: { 9 | songs: [ 10 | { 11 | artist_id: '456', 12 | id: '74574', 13 | artist_name: 'motorhead', 14 | title: 'foo bar' 15 | }, 16 | { 17 | artist_id: '678', 18 | id: '6546546', 19 | artist_name: 'nirvana', 20 | title: 'bar' 21 | }, 22 | { 23 | artist_id: '5453', 24 | id: '321312', 25 | artist_name: 'acdc', 26 | title: 'foo' 27 | } 28 | ], 29 | status: { 30 | code: 0, 31 | message: 'Success', 32 | version: '4.2' 33 | } 34 | } 35 | }; 36 | 37 | var songApiResponse = { 38 | response: { 39 | songs: [ 40 | { 41 | artist_id: '456', 42 | id: '74574', 43 | artist_name: 'motorhead', 44 | title: 'foo bar' 45 | } 46 | ], 47 | status: { 48 | code: 0, 49 | message: 'Success', 50 | version: '4.2' 51 | } 52 | } 53 | }; 54 | 55 | beforeEach(angular.mock.module('angular-echonest')); 56 | 57 | beforeEach(inject(function($injector) { 58 | echonest = $injector.get('Echonest'); 59 | httpBackend = $injector.get("$httpBackend"); 60 | 61 | httpBackend.when('JSONP', apiUrl + 'song/profile?api_key=&callback=JSON_CALLBACK&format=jsonp&id=SOCZMFK12AC468668F').respond(songApiResponse); 62 | httpBackend.when('JSONP', apiUrl + 'song/search?api_key=&callback=JSON_CALLBACK&format=jsonp&name=foo+bar').respond(songsApiResponse); 63 | httpBackend.when('JSONP', apiUrl + 'song/identify?api_key=&artist=Michael+Jackson&callback=JSON_CALLBACK&code=eJxVlIuNwzAMQ1fxC&format=jsonp&title=Billie+Jean').respond(songsApiResponse); 64 | })); 65 | 66 | // 67 | // Songs 68 | // 69 | it('get method should return song object', function() { 70 | echonest.songs.get({ 71 | id: 'SOCZMFK12AC468668F' 72 | }).then(function(song, status) { 73 | expect(song.artist_id).toBe('456'); 74 | expect(song.id).toBe('74574'); 75 | expect(song.artist_name).toBe('motorhead'); 76 | expect(song.title).toBe('foo bar'); 77 | }); 78 | 79 | httpBackend.flush(); 80 | }); 81 | 82 | it('search method should return array of song objects', function() { 83 | echonest.songs.search({ 84 | name: 'foo bar' 85 | }).then(function(songs, status) { 86 | expect(songs.constructor.name).toBe('Array'); 87 | expect(songs[0].constructor.name).toBe('Object'); 88 | expect(songs[0].artist_id).toBe('456'); 89 | expect(songs[0].id).toBe('74574'); 90 | expect(songs[0].artist_name).toBe('motorhead'); 91 | expect(songs[0].title).toBe('foo bar'); 92 | }); 93 | 94 | httpBackend.flush(); 95 | }); 96 | 97 | it('identify method should return array of song objects', function() { 98 | echonest.songs.identify({ 99 | artist: 'Michael Jackson', 100 | title: 'Billie Jean', 101 | code: 'eJxVlIuNwzAMQ1fxC' 102 | }).then(function(songs, status) { 103 | expect(songs.constructor.name).toBe('Array'); 104 | expect(songs[0].constructor.name).toBe('Object'); 105 | expect(songs[0].artist_id).toBe('456'); 106 | expect(songs[0].id).toBe('74574'); 107 | expect(songs[0].artist_name).toBe('motorhead'); 108 | expect(songs[0].title).toBe('foo bar'); 109 | }); 110 | 111 | httpBackend.flush(); 112 | }); 113 | }); 114 | -------------------------------------------------------------------------------- /app/javascript/services/services.js: -------------------------------------------------------------------------------- 1 | var services = angular.module('services', ['angular-echonest']) 2 | 3 | services.config(['EchonestProvider', function(EchonestProvider) { 4 | EchonestProvider.setApiKey(echonestApiKey); 5 | }]); 6 | 7 | services.factory('EchonestFactory', function ($http, Echonest) { 8 | 9 | var results = {}; 10 | var search = function(artist, title){ 11 | Echonest.songs.search({ 12 | artist: artist || null, 13 | title: title || null, 14 | //return songs 15 | }).then(function(songs) { 16 | results.songs = songs; 17 | console.log('SONG RESULT', songs); 18 | 19 | //get artist info on top result 20 | Echonest.artists.get({ 21 | id: songs[0].artist_id, 22 | bucket: 'terms' 23 | }).then(function(artist_summary) { 24 | results.artist_summary = artist_summary; 25 | console.log('ARTIST SUMMARY', artist_summary); 26 | return results; 27 | }) 28 | 29 | //get audio summary on top result 30 | Echonest.songs.get({ 31 | id: songs[0].id, 32 | bucket: 'audio_summary' 33 | }).then(function(audio_summary) { 34 | results.audio_summary = audio_summary; 35 | console.log('AUDIO SUMMARY', audio_summary); 36 | return results; 37 | }) 38 | return results; 39 | }); 40 | }; 41 | 42 | return { 43 | search: search, 44 | results: results 45 | }; 46 | 47 | }); 48 | 49 | services.factory('PlaylistFactory', function($http){ 50 | var results = {}; 51 | var search = function(artist, danceability, energy){ 52 | var queryURL = 'http://developer.echonest.com/api/v4/playlist/static?api_key=' + echonestApiKey; 53 | if(artist){ 54 | queryURL += '&artist=' + artist; 55 | } 56 | if(danceability){ 57 | queryURL += '&max_danceability=' + danceability; 58 | } 59 | if(energy){ 60 | queryURL += '&max_energy=' + energy; 61 | } 62 | queryURL += '&format=json&results=5&type=artist-radio&bucket=audio_summary'; 63 | 64 | $http.get(queryURL) 65 | .success(function(data, status, headers, config) { 66 | results.playlist = data; 67 | return data; 68 | }) 69 | .error(function(data, status, headers, config) { 70 | console.log('error'); 71 | }); 72 | // return results; 73 | }; 74 | 75 | return { 76 | search: search, 77 | results: results 78 | }; 79 | }); 80 | 81 | 82 | services.factory('YoutubeFactory', function ($http) { 83 | 84 | var results = {}; 85 | var search = function(artist, title){ 86 | console.log(artist); 87 | var youtubeApiKey = 'AIzaSyD8M6zcr3cPZlLL1XmBnRWBUlblNEYzMBo'; 88 | 89 | //Query for youtube results based on echonest selected song 90 | var dataurl ='http://gdata.youtube.com/feeds/api/videos?q=' + title + '%20' + artist + '&orderby=rating&alt=json'; 91 | 92 | $http.get(dataurl).success(function(data){ 93 | console.log('YOUTUBE RESULTS', data.feed.entry) 94 | return data.feed.entry; 95 | var vidId = data.feed.entry[0].id.$t 96 | var result = vidId.split('videos/')[1] 97 | results.push(result); 98 | }); 99 | 100 | //Return media for irst result of query 101 | // $http.get('http://developer.echonest.com/api/v4/playlist/static?api_key=' + echonestApiKey + '&artist=' + artist.name + '&format=json&results=5&type=artist').success(function(data, status, headers, config) { 102 | // playlist = data; 103 | // }) 104 | // .error(function(data, status, headers, config) { 105 | // console.log('error'); 106 | // }); 107 | } 108 | 109 | return { 110 | search: search, 111 | results: results 112 | } 113 | }); 114 | -------------------------------------------------------------------------------- /bower_components/ui-router/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | 2 | # Report an Issue 3 | 4 | Help us make UI-Router better! If you think you might have found a bug, or some other weirdness, start by making sure 5 | it hasn't already been reported. You can [search through existing issues](https://github.com/angular-ui/ui-router/search?q=wat%3F&type=Issues) 6 | to see if someone's reported one similar to yours. 7 | 8 | If not, then [create a plunkr](http://bit.ly/UIR-Plunk) that demonstrates the problem (try to use as little code 9 | as possible: the more minimalist, the faster we can debug it). 10 | 11 | Next, [create a new issue](https://github.com/angular-ui/ui-router/issues/new) that briefly explains the problem, 12 | and provides a bit of background as to the circumstances that triggered it. Don't forget to include the link to 13 | that plunkr you created! 14 | 15 | **Note**: If you're unsure how a feature is used, or are encountering some unexpected behavior that you aren't sure 16 | is a bug, it's best to talk it out on 17 | [StackOverflow](http://stackoverflow.com/questions/ask?tags=angularjs,angular-ui-router) before reporting it. This 18 | keeps development streamlined, and helps us focus on building great software. 19 | 20 | 21 | Issues only! | 22 | -------------| 23 | Please keep in mind that the issue tracker is for *issues*. Please do *not* post an issue if you need help or support. Instead, see one of the above-mentioned forums or [IRC](irc://irc.freenode.net/#angularjs). | 24 | 25 | ####Purple Labels 26 | A purple label means that **you** need to take some further action. 27 | - ![Not Actionable - Need Info](http://angular-ui.github.io/ui-router/images/notactionable.png): Your issue is not specific enough, or there is no clear action that we can take. Please clarify and refine your issue. 28 | - ![Plunkr Please](http://angular-ui.github.io/ui-router/images/plunkrplease.png): Please [create a plunkr](http://bit.ly/UIR-Plunk) 29 | - ![StackOverflow](http://angular-ui.github.io/ui-router/images/stackoverflow.png): We suspect your issue is really a help request, or could be answered by the community. Please ask your question on [StackOverflow](http://stackoverflow.com/questions/ask?tags=angularjs,angular-ui-router). If you determine that is an actual issue, please explain why. 30 | 31 | If your issue gets labeled with purple label, no further action will be taken until you respond to the label appropriately. 32 | 33 | # Contribute 34 | 35 | **(1)** See the **[Developing](#developing)** section below, to get the development version of UI-Router up and running on your local machine. 36 | 37 | **(2)** Check out the [roadmap](https://github.com/angular-ui/ui-router/milestones) to see where the project is headed, and if your feature idea fits with where we're headed. 38 | 39 | **(3)** If you're not sure, [open an RFC](https://github.com/angular-ui/ui-router/issues/new?title=RFC:%20My%20idea) to get some feedback on your idea. 40 | 41 | **(4)** Finally, commit some code and open a pull request. Code & commits should abide by the following rules: 42 | 43 | - *Always* have test coverage for new features (or regression tests for bug fixes), and *never* break existing tests 44 | - Commits should represent one logical change each; if a feature goes through multiple iterations, squash your commits down to one 45 | - Make sure to follow the [Angular commit message format](https://github.com/angular/angular.js/blob/master/CONTRIBUTING.md#commit-message-format) so your change will appear in the changelog of the next release. 46 | - Changes should always respect the coding style of the project 47 | 48 | 49 | 50 | # Developing 51 | 52 | UI-Router uses grunt >= 0.4.x. Make sure to upgrade your environment and read the 53 | [Migration Guide](http://gruntjs.com/upgrading-from-0.3-to-0.4). 54 | 55 | Dependencies for building from source and running tests: 56 | 57 | * [grunt-cli](https://github.com/gruntjs/grunt-cli) - run: `$ npm install -g grunt-cli` 58 | * Then, install the development dependencies by running `$ npm install` from the project directory 59 | 60 | There are a number of targets in the gruntfile that are used to generating different builds: 61 | 62 | * `grunt`: Perform a normal build, runs jshint and karma tests 63 | * `grunt build`: Perform a normal build 64 | * `grunt dist`: Perform a clean build and generate documentation 65 | * `grunt dev`: Run dev server (sample app) and watch for changes, builds and runs karma tests on changes. 66 | -------------------------------------------------------------------------------- /bower_components/ui-router/src/templateFactory.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @ngdoc object 3 | * @name ui.router.util.$templateFactory 4 | * 5 | * @requires $http 6 | * @requires $templateCache 7 | * @requires $injector 8 | * 9 | * @description 10 | * Service. Manages loading of templates. 11 | */ 12 | $TemplateFactory.$inject = ['$http', '$templateCache', '$injector']; 13 | function $TemplateFactory( $http, $templateCache, $injector) { 14 | 15 | /** 16 | * @ngdoc function 17 | * @name ui.router.util.$templateFactory#fromConfig 18 | * @methodOf ui.router.util.$templateFactory 19 | * 20 | * @description 21 | * Creates a template from a configuration object. 22 | * 23 | * @param {object} config Configuration object for which to load a template. 24 | * The following properties are search in the specified order, and the first one 25 | * that is defined is used to create the template: 26 | * 27 | * @param {string|object} config.template html string template or function to 28 | * load via {@link ui.router.util.$templateFactory#fromString fromString}. 29 | * @param {string|object} config.templateUrl url to load or a function returning 30 | * the url to load via {@link ui.router.util.$templateFactory#fromUrl fromUrl}. 31 | * @param {Function} config.templateProvider function to invoke via 32 | * {@link ui.router.util.$templateFactory#fromProvider fromProvider}. 33 | * @param {object} params Parameters to pass to the template function. 34 | * @param {object} locals Locals to pass to `invoke` if the template is loaded 35 | * via a `templateProvider`. Defaults to `{ params: params }`. 36 | * 37 | * @return {string|object} The template html as a string, or a promise for 38 | * that string,or `null` if no template is configured. 39 | */ 40 | this.fromConfig = function (config, params, locals) { 41 | return ( 42 | isDefined(config.template) ? this.fromString(config.template, params) : 43 | isDefined(config.templateUrl) ? this.fromUrl(config.templateUrl, params) : 44 | isDefined(config.templateProvider) ? this.fromProvider(config.templateProvider, params, locals) : 45 | null 46 | ); 47 | }; 48 | 49 | /** 50 | * @ngdoc function 51 | * @name ui.router.util.$templateFactory#fromString 52 | * @methodOf ui.router.util.$templateFactory 53 | * 54 | * @description 55 | * Creates a template from a string or a function returning a string. 56 | * 57 | * @param {string|object} template html template as a string or function that 58 | * returns an html template as a string. 59 | * @param {object} params Parameters to pass to the template function. 60 | * 61 | * @return {string|object} The template html as a string, or a promise for that 62 | * string. 63 | */ 64 | this.fromString = function (template, params) { 65 | return isFunction(template) ? template(params) : template; 66 | }; 67 | 68 | /** 69 | * @ngdoc function 70 | * @name ui.router.util.$templateFactory#fromUrl 71 | * @methodOf ui.router.util.$templateFactory 72 | * 73 | * @description 74 | * Loads a template from the a URL via `$http` and `$templateCache`. 75 | * 76 | * @param {string|Function} url url of the template to load, or a function 77 | * that returns a url. 78 | * @param {Object} params Parameters to pass to the url function. 79 | * @return {string|Promise.} The template html as a string, or a promise 80 | * for that string. 81 | */ 82 | this.fromUrl = function (url, params) { 83 | if (isFunction(url)) url = url(params); 84 | if (url == null) return null; 85 | else return $http 86 | .get(url, { cache: $templateCache, headers: { Accept: 'text/html' }}) 87 | .then(function(response) { return response.data; }); 88 | }; 89 | 90 | /** 91 | * @ngdoc function 92 | * @name ui.router.util.$templateFactory#fromProvider 93 | * @methodOf ui.router.util.$templateFactory 94 | * 95 | * @description 96 | * Creates a template by invoking an injectable provider function. 97 | * 98 | * @param {Function} provider Function to invoke via `$injector.invoke` 99 | * @param {Object} params Parameters for the template. 100 | * @param {Object} locals Locals to pass to `invoke`. Defaults to 101 | * `{ params: params }`. 102 | * @return {string|Promise.} The template html as a string, or a promise 103 | * for that string. 104 | */ 105 | this.fromProvider = function (provider, params, locals) { 106 | return $injector.invoke(provider, null, locals || { params: params }); 107 | }; 108 | } 109 | 110 | angular.module('ui.router.util').service('$templateFactory', $TemplateFactory); 111 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Muse 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 |
24 |

Muse

25 | 27 |
28 |
29 |
30 |

Artist

31 | 32 |

Title

33 | 34 | 35 |

Searching for {{artist}} {{title}}

36 |

{{initial.artist_name}}

37 |

{{initial.title}}

38 |

{{initial.audio_summary}}

39 |
40 | 41 | 44 | 45 |
46 | 47 |
48 |
49 |
50 |

Playlist Settings

51 |
52 |
53 | 55 |
Danceability
56 | {{danceability}} 57 |
Energy
58 | {{energy}} 59 |
Instrumentalness
60 | {{instrumentalness}} 61 |
Speachiness
62 | {{speachiness}} 63 |
Liveness
64 | {{liveness}} 65 | 66 |
67 |
68 |
69 |

Playlist

70 |
71 |
72 |
73 |
Artist: {{song.artist_name}}
74 |
Song: {{song.title}}
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 | 83 | 84 | -------------------------------------------------------------------------------- /bower_components/ui-router/api/angular-ui-router.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for Angular JS 1.1.5+ (ui.router module) 2 | // Project: https://github.com/angular-ui/ui-router 3 | // Definitions by: Michel Salib 4 | // Definitions: https://github.com/borisyankov/DefinitelyTyped 5 | 6 | declare module ng.ui { 7 | 8 | interface IState { 9 | name?: string; 10 | template?: string; 11 | templateUrl?: any; // string || () => string 12 | templateProvider?: any; // () => string || IPromise 13 | controller?: any; 14 | controllerAs?: string; 15 | controllerProvider?: any; 16 | resolve?: {}; 17 | url?: string; 18 | params?: any; 19 | views?: {}; 20 | abstract?: boolean; 21 | onEnter?: (...args: any[]) => void; 22 | onExit?: (...args: any[]) => void; 23 | data?: any; 24 | reloadOnSearch?: boolean; 25 | } 26 | 27 | interface ITypedState extends IState { 28 | data?: T; 29 | } 30 | 31 | interface IStateProvider extends IServiceProvider { 32 | state(name: string, config: IState): IStateProvider; 33 | state(config: IState): IStateProvider; 34 | decorator(name?: string, decorator?: (state: IState, parent: Function) => any): any; 35 | } 36 | 37 | interface IUrlMatcher { 38 | concat(pattern: string): IUrlMatcher; 39 | exec(path: string, searchParams: {}): {}; 40 | parameters(): string[]; 41 | format(values: {}): string; 42 | } 43 | 44 | interface IUrlMatcherFactory { 45 | compile(pattern: string): IUrlMatcher; 46 | isMatcher(o: any): boolean; 47 | } 48 | 49 | interface IUrlRouterProvider extends IServiceProvider { 50 | when(whenPath: RegExp, handler: Function): IUrlRouterProvider; 51 | when(whenPath: RegExp, handler: any[]): IUrlRouterProvider; 52 | when(whenPath: RegExp, toPath: string): IUrlRouterProvider; 53 | when(whenPath: IUrlMatcher, hanlder: Function): IUrlRouterProvider; 54 | when(whenPath: IUrlMatcher, handler: any[]): IUrlRouterProvider; 55 | when(whenPath: IUrlMatcher, toPath: string): IUrlRouterProvider; 56 | when(whenPath: string, handler: Function): IUrlRouterProvider; 57 | when(whenPath: string, handler: any[]): IUrlRouterProvider; 58 | when(whenPath: string, toPath: string): IUrlRouterProvider; 59 | otherwise(handler: Function): IUrlRouterProvider; 60 | otherwise(handler: any[]): IUrlRouterProvider; 61 | otherwise(path: string): IUrlRouterProvider; 62 | rule(handler: Function): IUrlRouterProvider; 63 | rule(handler: any[]): IUrlRouterProvider; 64 | } 65 | 66 | interface IStateOptions { 67 | location?: any; 68 | inherit?: boolean; 69 | relative?: IState; 70 | notify?: boolean; 71 | reload?: boolean; 72 | } 73 | 74 | interface IHrefOptions { 75 | lossy?: boolean; 76 | inherit?: boolean; 77 | relative?: IState; 78 | absolute?: boolean; 79 | } 80 | 81 | interface IStateService { 82 | go(to: string, params?: {}, options?: IStateOptions): IPromise; 83 | transitionTo(state: string, params?: {}, updateLocation?: boolean): void; 84 | transitionTo(state: string, params?: {}, options?: IStateOptions): void; 85 | includes(state: string, params?: {}): boolean; 86 | is(state:string, params?: {}): boolean; 87 | is(state: IState, params?: {}): boolean; 88 | href(state: IState, params?: {}, options?: IHrefOptions): string; 89 | href(state: string, params?: {}, options?: IHrefOptions): string; 90 | get(state: string): IState; 91 | get(): IState[]; 92 | current: IState; 93 | params: any; 94 | reload(): void; 95 | } 96 | 97 | interface IStateParamsService { 98 | [key: string]: any; 99 | } 100 | 101 | interface IStateParams { 102 | [key: string]: any; 103 | } 104 | 105 | interface IUrlRouterService { 106 | /* 107 | * Triggers an update; the same update that happens when the address bar 108 | * url changes, aka $locationChangeSuccess. 109 | * 110 | * This method is useful when you need to use preventDefault() on the 111 | * $locationChangeSuccess event, perform some custom logic (route protection, 112 | * auth, config, redirection, etc) and then finally proceed with the transition 113 | * by calling $urlRouter.sync(). 114 | * 115 | */ 116 | sync(): void; 117 | } 118 | 119 | interface IUiViewScrollProvider { 120 | /* 121 | * Reverts back to using the core $anchorScroll service for scrolling 122 | * based on the url anchor. 123 | */ 124 | useAnchorScroll(): void; 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /bower_components/angular-echonest/README.md: -------------------------------------------------------------------------------- 1 | Angular-echonest v0.2.5 [![Build Status](https://travis-ci.org/Kraku/angular-echonest.svg?branch=master)](https://travis-ci.org/Kraku/angular-echonest) 2 | ============= 3 | 4 | Angular-echonest allows you to easily call Echo Nest methods in AngularJS. 5 | 6 | Uses EchoNest API v4. 7 | 8 | ## Installation 9 | ```js 10 | var myApp = angular.module('myApp', [ 11 | 'angular-echonest' 12 | ]); 13 | 14 | myApp.config(['EchonestProvider', function(EchonestProvider) { 15 | EchonestProvider.setApiKey('apiKey'); 16 | }]); 17 | ``` 18 | 19 | Get [an API key](http://developer.echonest.com/docs/v4/#keys). 20 | 21 | ## Usage 22 | ```js 23 | myApp.controller('SomeCtrl', function($scope, Echonest) { 24 | ... 25 | }); 26 | ``` 27 | 28 | ## Tests 29 | ``` 30 | npm install 31 | bower install angular 32 | bower install angular-mocks 33 | 34 | grunt karma:unit 35 | 36 | ``` 37 | 38 | ### Artists Methods 39 | - **search** - Search artists. 40 | - **get** - Get artist by id or name. 41 | - **topHot** - Return a list of the top hottt artists. 42 | - **suggest** - Suggest artists based upon partial names. This method will return a list of potential artist matches based upon a query string. The method returns the most familiar best matching artist for the query. 43 | - **extract** - Extract artist names from text. 44 | 45 | ### Artist Methods 46 | - **getBiographies** - Get a list of artist biographies. 47 | - **getBlogs** - Get a list of blog articles related to an artist. 48 | - **getImages** - Get a list of artist images. 49 | - **getNews** - Get a list of news articles found on the web related to an artist. 50 | - **getReviews** - Get reviews related to an artist's work. 51 | - **getSongs** - Get a list of songs created by an artist. 52 | - **getFamiliarity** - Get our numerical estimation of how familiar an artist currently is to the world. 53 | - **getHotnes** - Returns our numerical description of how hottt an artist currently is. 54 | - **getSimilar** - Return similar artists given one or more artists for comparison. The Echo Nest provides up-to-the-minute artist similarity and recommendations from their real-time musical and cultural analysis of what people are saying across the Internet and what the music sounds like. 55 | - **getTerms** - Get a list of most descriptive terms for an artist. 56 | - **getTwitter** - Gets the twitter handle for an artist. 57 | - **getUrls** - Get links to the artist's official site, MusicBrainz site, MySpace site, Wikipedia article, and official URL. 58 | 59 | [Artist Api Doc](http://developer.echonest.com/docs/v4/artist.html) 60 | 61 | ### Songs Methods 62 | - **search** - Search for songs given different query types. 63 | - **get** - Get song by id or track_id. 64 | - **identify** - Identifies a song given an Echoprint or Echo Nest Musical Fingerprint hash codes. 65 | 66 | [Song Api Doc](http://developer.echonest.com/docs/v4/song.html) 67 | 68 | 69 | ## Example 70 | #### Get artist songs 71 | ```js 72 | // Multiple requests 73 | Echonest.artists.get({ 74 | name: 'nirvana' 75 | }).then(function(artist) { 76 | return artist.getSongs(); 77 | }).then(function(artist) { 78 | console.log(artist.songs); // -> {id: "ARH3S5S1187FB4F76B", name: "Nirvana", songs: Array[15]} 79 | }); 80 | 81 | // or 82 | 83 | // Single request 84 | Echonest.artists.get({ 85 | name: 'nirvana', 86 | bucket: 'songs' 87 | }).then(function(artist) { 88 | console.log(artist); // -> {id: "ARH3S5S1187FB4F76B", name: "Nirvana", songs: Array[15]} 89 | }); 90 | ``` 91 | 92 | #### Search for artists from the Boston area 93 | ```js 94 | Echonest.artists.search({ 95 | artist_location: 'boston', 96 | results: 3 97 | }).then(function(artists) { 98 | console.log(artists); // -> [{id: "AR12F2S1187FB56EEF", name: "Aerosmith"}, {...}, {...}] 99 | }); 100 | ``` 101 | 102 | #### Get artist by name 103 | ```js 104 | Echonest.artists.get({ 105 | name: 'motorhead' 106 | }).then(function(artist) { 107 | console.log(artist); // -> {id: "AR212SC1187FB4A4F9", name: "Motörhead"} 108 | }); 109 | ``` 110 | 111 | #### Get top 3 rock artists 112 | ```js 113 | Echonest.artists.topHot({ 114 | genre: 'rock', 115 | results: 10 116 | }).then(function(artists) { 117 | console.log(artists); // -> [{id: "ARUJ5A41187FB3F5F1", name: "U2"}, {...}, {...}] 118 | }); 119 | ``` 120 | 121 | #### Get song by artist and title 122 | ```js 123 | Echonest.songs.search({ 124 | artist: 'radiohead', 125 | title: 'karma police' 126 | }).then(function(songs) { 127 | console.log(songs); // -> [{artist_id: "ARH6W4X1187B99274F", artist_name: "Radiohead", id: "SOHJOLH12A6310DFE5", title: "Karma Police"}, {...}] 128 | }); 129 | ``` 130 | 131 | #### Get song by id 132 | ```js 133 | Echonest.songs.get({ 134 | id: 'SOCZMFK12AC468668F' 135 | }).then(function(song) { 136 | console.log(song); // -> {artist_id: "ARZHQSP12FE086C216", id: "SOCZMFK12AC468668F", artist_name: "Wil-Lean", title: "Stay Fly"} 137 | }); 138 | ``` 139 | 140 | #### Get song by code, artist and title 141 | ```js 142 | Echonest.songs.identify({ 143 | artist: 'Michael Jackson', 144 | title: 'Billie Jean', 145 | code: 'eJxVlIuNwzAMQ1fxCDL133-xo1rnGqNAEcWy_ERa2aKeZmW9ustWVYrXrl5bthn_laFkzguNWpklEmoTB74JKYZSPlbJ0sy9fQrsrbEaO9W3bsbaWOoK7IhkHFaf_ag2d75oOQSZczbz5CKA7XgTIBIXASvFi0A3W8pMUZ7FZTWTVbujCcADlQ_f_WbdRNJ2vDUwSF0EZmFvAku_CVy440fgiIvArWZZWoJ7GWd-CVTYC5FCFI8GQdECdROE20UQfLoIUmhLC7IiByF1gzbAs3tsSKctyC76MPJlHRsZ5qhSQhu_CJFcKtW4EMrHSIrpTGLFqsdItj1H9JYHQYN7W2nkC6GDPjZTAzL9dx0fS4M1FoROHh9YhLHWdRchQSd_CLTpOHkQQP3xQsA2-sLOUD7CzxU0GmHVdIxh46Oide0NrNEmjghG44Ax_k2AoDHsiV6WsiD6OFm8y-0Lyt8haDBBzeMlAnTuuGYIB4WA2lEPAWbdeOabgFN6TQMs6ctLA5fHyKMBB0veGrjPfP00IAlWNm9n7hEh5PiYYBGKQDP-x4F0CL8HkhoQnRWN997JyEpnHFR7EhLPQMZmgXS68hsHktEVErranvSSR2VwfJhQCnkuwhBUcINNY-xu1pmw3PmBqU9-8xu0kiF1ngOa8vwBSSzzNw==' 146 | }).then(function(songs) { 147 | console.log(songs); // -> [{artist_id: "ARXPPEY1187FB51DF4", artist_name: "Michael Jackson", id: "SODJXOA1313438FB61", message: "OK (match type 5)", score: 54, title: "Billie Jean"}] 148 | }); 149 | ``` 150 | 151 | ## TO DO 152 | * Genre API Methods 153 | * Track API Methods 154 | 155 |
156 | --- 157 | © 2014 [Maciej Podsiedlak](http://mpodsiedlak.com) - Released under MIT [License](https://github.com/Kraku/angular-echonest/blob/master/LICENSE) 158 | -------------------------------------------------------------------------------- /bower_components/angular-echonest/build/angular-echonest.js: -------------------------------------------------------------------------------- 1 | /** 2 | * angular-echonest module 3 | * https://github.com/kraku/angular-echonest 4 | * 5 | * Author: Maciej Podsiedlak - http://mpodsiedlak.com 6 | */ 7 | 8 | (function() { 9 | 'use strict'; 10 | 11 | angular.module('angular-echonest', []).provider('Echonest', function() { 12 | var apiUrl = 'http://developer.echonest.com/api/v4/'; 13 | var apiKey = ''; 14 | var Artist, Artists, Songs, obj, http, q; 15 | 16 | var query = function(url, data) { 17 | var deferred = q.defer(); 18 | 19 | data.api_key = apiKey; 20 | data.format = 'jsonp'; 21 | data.callback = 'JSON_CALLBACK'; 22 | 23 | http({ 24 | method: 'JSONP', 25 | url: apiUrl + url, 26 | params: data 27 | }).success(function(result) { 28 | deferred.resolve(result.response); 29 | }); 30 | 31 | return deferred.promise; 32 | }; 33 | 34 | var artistGet = function(name, data) { 35 | var deferred = q.defer(); 36 | var t = this; 37 | data = data || {}; 38 | 39 | data.id = t.id; 40 | 41 | query('artist/' + name, data).then(function(result) { 42 | t[name] = result[name]; 43 | 44 | deferred.resolve(t); 45 | }); 46 | 47 | return deferred.promise; 48 | }; 49 | 50 | var getParams = function(params) { 51 | var data = []; 52 | 53 | if (params instanceof Object) { 54 | for (var i in params) { 55 | if (params.hasOwnProperty(i)) { 56 | data[i] = params[i]; 57 | } 58 | } 59 | } 60 | 61 | return data; 62 | }; 63 | 64 | var artistsGet = function(name, data) { 65 | return query('artist/' + name, data).then(function(result) { 66 | var artists = []; 67 | 68 | for (var i in result.artists) { 69 | artists.push(new Artist(result.artists[i])); 70 | } 71 | 72 | return artists; 73 | }); 74 | }; 75 | 76 | this.setApiKey = function(value) { 77 | apiKey = value; 78 | }; 79 | 80 | 81 | // Artist class 82 | Artist = function(props) { 83 | if (props instanceof Object) { 84 | for (var i in props) { 85 | if (props.hasOwnProperty(i)) { 86 | this[i] = props[i]; 87 | } 88 | } 89 | } 90 | 91 | return this; 92 | }; 93 | 94 | Artist.prototype = { 95 | getBiographies: function(data) { 96 | return artistGet.call(this, 'biographies', data); 97 | }, 98 | getBlogs: function(data) { 99 | return artistGet.call(this, 'blogs', data); 100 | }, 101 | getImages: function(data) { 102 | return artistGet.call(this, 'images', data); 103 | }, 104 | getNews: function(data) { 105 | return artistGet.call(this, 'news', data); 106 | }, 107 | getReviews: function(data) { 108 | return artistGet.call(this, 'reviews', data); 109 | }, 110 | getSongs: function(data) { 111 | return artistGet.call(this, 'songs', data); 112 | }, 113 | getFamiliarity: function(data) { 114 | return artistGet.call(this, 'familiarity', data); 115 | }, 116 | getHotnes: function(data) { 117 | return artistGet.call(this, 'hotttnesss', data); 118 | }, 119 | getSimilar: function(data) { 120 | return artistGet.call(this, 'similar', data); 121 | }, 122 | getTerms: function(data) { 123 | return artistGet.call(this, 'terms', data); 124 | }, 125 | getTwitter: function(data) { 126 | return artistGet.call(this, 'twitter', data); 127 | }, 128 | getUrls: function(data) { 129 | return artistGet.call(this, 'urls', data); 130 | } 131 | }; 132 | 133 | 134 | // Artists class 135 | Artists = function() { 136 | return this; 137 | }; 138 | 139 | Artists.prototype = { 140 | 141 | /* 142 | * Search artists 143 | * 144 | * doc: http://developer.echonest.com/docs/v4/artist.html#search 145 | */ 146 | search: function(params) { 147 | var data = getParams(params); 148 | 149 | return artistsGet.call(this, 'search', data); 150 | }, 151 | 152 | /* 153 | * Get artist 154 | * 155 | * doc: http://developer.echonest.com/docs/v4/artist.html#profile 156 | */ 157 | get: function(data) { 158 | if (data instanceof Object) { 159 | return query('artist/profile', data).then(function(data) { 160 | return new Artist(data.artist); 161 | }); 162 | } 163 | }, 164 | 165 | /* 166 | * Return a list of the top hottt artists. 167 | * 168 | * doc: http://developer.echonest.com/docs/v4/artist.html#top-hottt 169 | */ 170 | topHot: function(params) { 171 | var data = getParams(params); 172 | 173 | return artistsGet.call(this, 'top_hottt', data); 174 | }, 175 | 176 | /* 177 | * Suggest artists based upon partial names. 178 | * 179 | * doc: http://developer.echonest.com/docs/v4/artist.html#suggest-beta 180 | */ 181 | suggest: function(params) { 182 | var data = getParams(params); 183 | 184 | return artistsGet.call(this, 'suggest', data); 185 | }, 186 | 187 | /* 188 | * Extract artist names from text. 189 | * 190 | * doc: http://developer.echonest.com/docs/v4/artist.html#extract-beta 191 | */ 192 | extract: function(params) { 193 | var data = getParams(params); 194 | 195 | return artistsGet.call(this, 'extract', data); 196 | } 197 | }; 198 | 199 | 200 | // Songs class 201 | Songs = function() { 202 | return this; 203 | }; 204 | 205 | Songs.prototype = { 206 | 207 | /* 208 | * Search for songs given different query types. 209 | * 210 | * doc: http://developer.echonest.com/docs/v4/song.html#search 211 | */ 212 | search: function(params) { 213 | var data = getParams(params); 214 | 215 | return query('song/search', data).then(function(result) { 216 | return result.songs; 217 | }); 218 | }, 219 | 220 | /* 221 | * Get info about songs given a list of ids. 222 | * 223 | * doc: http://developer.echonest.com/docs/v4/song.html#profile 224 | */ 225 | get: function(data) { 226 | if (data instanceof Object) { 227 | return query('song/profile', data).then(function(result) { 228 | return result.songs[0]; 229 | }); 230 | } 231 | }, 232 | 233 | /* 234 | * Identifies a song given an Echoprint or Echo Nest Musical Fingerprint hash codes. 235 | * 236 | * doc: http://developer.echonest.com/docs/v4/song.html#identify 237 | */ 238 | identify: function(params) { 239 | var data = getParams(params); 240 | 241 | return query('song/identify', data).then(function(result) { 242 | return result.songs; 243 | }); 244 | } 245 | }; 246 | 247 | 248 | this.$get = ['$http', '$q', function($http, $q) { 249 | http = $http; 250 | q = $q; 251 | 252 | obj = { 253 | artists: new Artists(), 254 | songs: new Songs() 255 | }; 256 | 257 | return obj; 258 | }]; 259 | }); 260 | })(); 261 | -------------------------------------------------------------------------------- /bower_components/angular-echonest/src/angular-echonest.js: -------------------------------------------------------------------------------- 1 | /** 2 | * angular-echonest module 3 | * https://github.com/kraku/angular-echonest 4 | * 5 | * Author: Maciej Podsiedlak - http://mpodsiedlak.com 6 | */ 7 | 8 | (function() { 9 | 'use strict'; 10 | 11 | angular.module('angular-echonest', []).provider('Echonest', function() { 12 | var apiUrl = 'http://developer.echonest.com/api/v4/'; 13 | var apiKey = ''; 14 | var Artist, Artists, Songs, obj, http, q; 15 | 16 | var query = function(url, data) { 17 | var deferred = q.defer(); 18 | 19 | data.api_key = apiKey; 20 | data.format = 'jsonp'; 21 | data.callback = 'JSON_CALLBACK'; 22 | 23 | http({ 24 | method: 'JSONP', 25 | url: apiUrl + url, 26 | params: data 27 | }).success(function(result) { 28 | deferred.resolve(result.response); 29 | }); 30 | 31 | return deferred.promise; 32 | }; 33 | 34 | var artistGet = function(name, data) { 35 | var deferred = q.defer(); 36 | var t = this; 37 | data = data || {}; 38 | 39 | data.id = t.id; 40 | 41 | query('artist/' + name, data).then(function(result) { 42 | t[name] = result[name]; 43 | 44 | deferred.resolve(t); 45 | }); 46 | 47 | return deferred.promise; 48 | }; 49 | 50 | var getParams = function(params) { 51 | var data = []; 52 | 53 | if (params instanceof Object) { 54 | for (var i in params) { 55 | if (params.hasOwnProperty(i)) { 56 | data[i] = params[i]; 57 | } 58 | } 59 | } 60 | 61 | return data; 62 | }; 63 | 64 | var artistsGet = function(name, data) { 65 | return query('artist/' + name, data).then(function(result) { 66 | var artists = []; 67 | 68 | for (var i in result.artists) { 69 | artists.push(new Artist(result.artists[i])); 70 | } 71 | 72 | return artists; 73 | }); 74 | }; 75 | 76 | this.setApiKey = function(value) { 77 | apiKey = value; 78 | }; 79 | 80 | 81 | // Artist class 82 | Artist = function(props) { 83 | if (props instanceof Object) { 84 | for (var i in props) { 85 | if (props.hasOwnProperty(i)) { 86 | this[i] = props[i]; 87 | } 88 | } 89 | } 90 | 91 | return this; 92 | }; 93 | 94 | Artist.prototype = { 95 | getBiographies: function(data) { 96 | return artistGet.call(this, 'biographies', data); 97 | }, 98 | getBlogs: function(data) { 99 | return artistGet.call(this, 'blogs', data); 100 | }, 101 | getImages: function(data) { 102 | return artistGet.call(this, 'images', data); 103 | }, 104 | getNews: function(data) { 105 | return artistGet.call(this, 'news', data); 106 | }, 107 | getReviews: function(data) { 108 | return artistGet.call(this, 'reviews', data); 109 | }, 110 | getSongs: function(data) { 111 | return artistGet.call(this, 'songs', data); 112 | }, 113 | getFamiliarity: function(data) { 114 | return artistGet.call(this, 'familiarity', data); 115 | }, 116 | getHotnes: function(data) { 117 | return artistGet.call(this, 'hotttnesss', data); 118 | }, 119 | getSimilar: function(data) { 120 | return artistGet.call(this, 'similar', data); 121 | }, 122 | getTerms: function(data) { 123 | return artistGet.call(this, 'terms', data); 124 | }, 125 | getTwitter: function(data) { 126 | return artistGet.call(this, 'twitter', data); 127 | }, 128 | getUrls: function(data) { 129 | return artistGet.call(this, 'urls', data); 130 | } 131 | }; 132 | 133 | 134 | // Artists class 135 | Artists = function() { 136 | return this; 137 | }; 138 | 139 | Artists.prototype = { 140 | 141 | /* 142 | * Search artists 143 | * 144 | * doc: http://developer.echonest.com/docs/v4/artist.html#search 145 | */ 146 | search: function(params) { 147 | var data = getParams(params); 148 | 149 | return artistsGet.call(this, 'search', data); 150 | }, 151 | 152 | /* 153 | * Get artist 154 | * 155 | * doc: http://developer.echonest.com/docs/v4/artist.html#profile 156 | */ 157 | get: function(data) { 158 | if (data instanceof Object) { 159 | return query('artist/profile', data).then(function(data) { 160 | return new Artist(data.artist); 161 | }); 162 | } 163 | }, 164 | 165 | /* 166 | * Return a list of the top hottt artists. 167 | * 168 | * doc: http://developer.echonest.com/docs/v4/artist.html#top-hottt 169 | */ 170 | topHot: function(params) { 171 | var data = getParams(params); 172 | 173 | return artistsGet.call(this, 'top_hottt', data); 174 | }, 175 | 176 | /* 177 | * Suggest artists based upon partial names. 178 | * 179 | * doc: http://developer.echonest.com/docs/v4/artist.html#suggest-beta 180 | */ 181 | suggest: function(params) { 182 | var data = getParams(params); 183 | 184 | return artistsGet.call(this, 'suggest', data); 185 | }, 186 | 187 | /* 188 | * Extract artist names from text. 189 | * 190 | * doc: http://developer.echonest.com/docs/v4/artist.html#extract-beta 191 | */ 192 | extract: function(params) { 193 | var data = getParams(params); 194 | 195 | return artistsGet.call(this, 'extract', data); 196 | } 197 | }; 198 | 199 | 200 | // Songs class 201 | Songs = function() { 202 | return this; 203 | }; 204 | 205 | Songs.prototype = { 206 | 207 | /* 208 | * Search for songs given different query types. 209 | * 210 | * doc: http://developer.echonest.com/docs/v4/song.html#search 211 | */ 212 | search: function(params) { 213 | var data = getParams(params); 214 | 215 | return query('song/search', data).then(function(result) { 216 | return result.songs; 217 | }); 218 | }, 219 | 220 | /* 221 | * Get info about songs given a list of ids. 222 | * 223 | * doc: http://developer.echonest.com/docs/v4/song.html#profile 224 | */ 225 | get: function(data) { 226 | if (data instanceof Object) { 227 | return query('song/profile', data).then(function(result) { 228 | return result.songs[0]; 229 | }); 230 | } 231 | }, 232 | 233 | /* 234 | * Identifies a song given an Echoprint or Echo Nest Musical Fingerprint hash codes. 235 | * 236 | * doc: http://developer.echonest.com/docs/v4/song.html#identify 237 | */ 238 | identify: function(params) { 239 | var data = getParams(params); 240 | 241 | return query('song/identify', data).then(function(result) { 242 | return result.songs; 243 | }); 244 | } 245 | }; 246 | 247 | 248 | this.$get = ['$http', '$q', function($http, $q) { 249 | http = $http; 250 | q = $q; 251 | 252 | obj = { 253 | artists: new Artists(), 254 | songs: new Songs() 255 | }; 256 | 257 | return obj; 258 | }]; 259 | }); 260 | })(); 261 | -------------------------------------------------------------------------------- /bower_components/angular-echonest/test/artists.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('Artists', function() { 4 | var echonest, httpBackend; 5 | var apiUrl = 'http://developer.echonest.com/api/v4/'; 6 | var artistApiMethods = ['biographies', 'blogs', 'images', 'news', 'reviews', 'songs', 'familiarity', 'hotttnesss', 'similar', 'terms', 'twitter', 'urls']; 7 | 8 | var artistsApiResponse = { 9 | response: { 10 | artists: [ 11 | { 12 | id: 'AR212SC1187FB4A4F9', 13 | name: 'nirvana' 14 | }, 15 | { 16 | id: 'ARTSYYD1369F266E57', 17 | name: 'acdc' 18 | }, 19 | { 20 | id: 'AR6ZH2F1187FB4FB84', 21 | name: 'motorhead' 22 | } 23 | ], 24 | status: { 25 | code: 0, 26 | message: 'Success', 27 | version: '4.2' 28 | } 29 | } 30 | }; 31 | 32 | var artistApiResponse = { 33 | response: { 34 | artist: { 35 | id: 'AR212SC1187FB4A4F9', 36 | name: 'motorhead' 37 | }, 38 | status: { 39 | code: 0, 40 | message: 'Success', 41 | version: '4.2' 42 | } 43 | } 44 | }; 45 | 46 | var artistApiMethodsResponse = function(name) { 47 | var obj = {response: {}}; 48 | 49 | obj.response[name] = []; 50 | 51 | return obj; 52 | }; 53 | 54 | var getSingleArtist = function() { 55 | var result; 56 | 57 | echonest.artists.get({ 58 | name: 'motorhead' 59 | }).then(function(artist, status) { 60 | result = artist; 61 | }); 62 | 63 | httpBackend.flush(); 64 | 65 | return result; 66 | }; 67 | 68 | beforeEach(angular.mock.module('angular-echonest')); 69 | 70 | beforeEach(inject(function($injector) { 71 | echonest = $injector.get('Echonest'); 72 | httpBackend = $injector.get("$httpBackend"); 73 | 74 | httpBackend.when('JSONP', apiUrl + 'artist/profile?api_key=&callback=JSON_CALLBACK&format=jsonp&name=motorhead').respond(artistApiResponse); 75 | 76 | httpBackend.when('JSONP', apiUrl + 'artist/search?api_key=&callback=JSON_CALLBACK&format=jsonp&name=motorhead').respond(artistsApiResponse); 77 | httpBackend.when('JSONP', apiUrl + 'artist/top_hottt?api_key=&callback=JSON_CALLBACK&format=jsonp&results=3').respond(artistsApiResponse); 78 | httpBackend.when('JSONP', apiUrl + 'artist/suggest?api_key=&callback=JSON_CALLBACK&format=jsonp&name=motorhead').respond(artistsApiResponse); 79 | httpBackend.when('JSONP', apiUrl + 'artist/extract?api_key=&callback=JSON_CALLBACK&format=jsonp&text=abc+motorhead+abc').respond(artistsApiResponse); 80 | 81 | for (var i in artistApiMethods) { 82 | httpBackend.when('JSONP', apiUrl + 'artist/' + artistApiMethods[i] + '?api_key=&callback=JSON_CALLBACK&format=jsonp&id=AR212SC1187FB4A4F9').respond(artistApiMethodsResponse(artistApiMethods[i])); 83 | } 84 | })); 85 | 86 | // 87 | // Artists 88 | // 89 | it('get method should return artist object', function() { 90 | echonest.artists.get({ 91 | name: 'motorhead' 92 | }).then(function(artist) { 93 | expect(artist.constructor.name).toBe('Object'); 94 | expect(artist.id).toBe('AR212SC1187FB4A4F9'); 95 | expect(artist.name).toBe('motorhead'); 96 | }); 97 | 98 | httpBackend.flush(); 99 | }); 100 | 101 | it('search method should return array of artist objects', function() { 102 | echonest.artists.search({ 103 | name: 'motorhead' 104 | }).then(function(artists, status) { 105 | expect(artists.constructor.name).toBe('Array'); 106 | expect(artists[0].constructor.name).toBe('Object'); 107 | expect(artists[0].id).toBe('AR212SC1187FB4A4F9'); 108 | expect(artists[0].name).toBe('nirvana'); 109 | }); 110 | 111 | httpBackend.flush(); 112 | }); 113 | 114 | it('topHot method should return array of artist objects', function() { 115 | echonest.artists.topHot({ 116 | results: 3 117 | }).then(function(artists, status) { 118 | expect(artists.constructor.name).toBe('Array'); 119 | expect(artists[0].constructor.name).toBe('Object'); 120 | expect(artists[0].id).toBe('AR212SC1187FB4A4F9'); 121 | expect(artists[0].name).toBe('nirvana'); 122 | }); 123 | 124 | httpBackend.flush(); 125 | }); 126 | 127 | it('suggest method should return array of artist objects', function() { 128 | echonest.artists.suggest({ 129 | name: 'motorhead' 130 | }).then(function(artists, status) { 131 | expect(artists.constructor.name).toBe('Array'); 132 | expect(artists[0].constructor.name).toBe('Object'); 133 | expect(artists[0].id).toBe('AR212SC1187FB4A4F9'); 134 | expect(artists[0].name).toBe('nirvana'); 135 | }); 136 | 137 | httpBackend.flush(); 138 | }); 139 | 140 | it('extract method should return array of artist objects', function() { 141 | echonest.artists.extract({ 142 | text: 'abc motorhead abc' 143 | }).then(function(artists, status) { 144 | expect(artists.constructor.name).toBe('Array'); 145 | expect(artists[0].constructor.name).toBe('Object'); 146 | expect(artists[0].id).toBe('AR212SC1187FB4A4F9'); 147 | expect(artists[0].name).toBe('nirvana'); 148 | }); 149 | 150 | httpBackend.flush(); 151 | }); 152 | 153 | it('getBiographies method should insert biographies array into artist object', function() { 154 | var artist = getSingleArtist(); 155 | 156 | artist.getBiographies().then(function(artist) { 157 | expect(artist.biographies instanceof Array).toBe(true); 158 | }); 159 | 160 | httpBackend.flush(); 161 | }); 162 | 163 | it('getBlogs method should insert blogs array into artist object', function() { 164 | var artist = getSingleArtist(); 165 | 166 | artist.getBlogs().then(function(artist) { 167 | expect(artist.blogs instanceof Array).toBe(true); 168 | }); 169 | 170 | httpBackend.flush(); 171 | }); 172 | 173 | it('getImages method should insert images array into artist object', function() { 174 | var artist = getSingleArtist(); 175 | 176 | artist.getImages().then(function(artist) { 177 | expect(artist.images instanceof Array).toBe(true); 178 | }); 179 | 180 | httpBackend.flush(); 181 | }); 182 | 183 | it('getNews method should insert news array into artist object', function() { 184 | var artist = getSingleArtist(); 185 | 186 | artist.getNews().then(function(artist) { 187 | expect(artist.news instanceof Array).toBe(true); 188 | }); 189 | 190 | httpBackend.flush(); 191 | }); 192 | 193 | it('getReviews method should insert reviews array into artist object', function() { 194 | var artist = getSingleArtist(); 195 | 196 | artist.getReviews().then(function(artist) { 197 | expect(artist.reviews instanceof Array).toBe(true); 198 | }); 199 | 200 | httpBackend.flush(); 201 | }); 202 | 203 | it('getSongs method should insert songs array into artist object', function() { 204 | var artist = getSingleArtist(); 205 | 206 | artist.getSongs().then(function(artist) { 207 | expect(artist.songs instanceof Array).toBe(true); 208 | }); 209 | 210 | httpBackend.flush(); 211 | }); 212 | 213 | it('getFamiliarity method should insert familiarity array into artist object', function() { 214 | var artist = getSingleArtist(); 215 | 216 | artist.getFamiliarity().then(function(artist) { 217 | expect(artist.familiarity instanceof Array).toBe(true); 218 | }); 219 | 220 | httpBackend.flush(); 221 | }); 222 | 223 | it('getHotnes method should insert hotttnesss array into artist object', function() { 224 | var artist = getSingleArtist(); 225 | 226 | artist.getHotnes().then(function(artist) { 227 | expect(artist.hotttnesss instanceof Array).toBe(true); 228 | }); 229 | 230 | httpBackend.flush(); 231 | }); 232 | 233 | it('getSimilar method should insert similar array into artist object', function() { 234 | var artist = getSingleArtist(); 235 | 236 | artist.getSimilar().then(function(artist) { 237 | expect(artist.similar instanceof Array).toBe(true); 238 | }); 239 | 240 | httpBackend.flush(); 241 | }); 242 | 243 | it('getTerms method should insert terms array into artist object', function() { 244 | var artist = getSingleArtist(); 245 | 246 | artist.getTerms().then(function(artist) { 247 | expect(artist.terms instanceof Array).toBe(true); 248 | }); 249 | 250 | httpBackend.flush(); 251 | }); 252 | 253 | it('getTwitter method should insert twitter array into artist object', function() { 254 | var artist = getSingleArtist(); 255 | 256 | artist.getTwitter().then(function(artist) { 257 | expect(artist.twitter instanceof Array).toBe(true); 258 | }); 259 | 260 | httpBackend.flush(); 261 | }); 262 | 263 | it('getUrls method should insert urls array into artist object', function() { 264 | var artist = getSingleArtist(); 265 | 266 | artist.getUrls().then(function(artist) { 267 | expect(artist.urls instanceof Array).toBe(true); 268 | }); 269 | 270 | httpBackend.flush(); 271 | }); 272 | }); 273 | -------------------------------------------------------------------------------- /bower_components/ui-router/src/common.js: -------------------------------------------------------------------------------- 1 | /*jshint globalstrict:true*/ 2 | /*global angular:false*/ 3 | 'use strict'; 4 | 5 | var isDefined = angular.isDefined, 6 | isFunction = angular.isFunction, 7 | isString = angular.isString, 8 | isObject = angular.isObject, 9 | isArray = angular.isArray, 10 | forEach = angular.forEach, 11 | extend = angular.extend, 12 | copy = angular.copy; 13 | 14 | function inherit(parent, extra) { 15 | return extend(new (extend(function() {}, { prototype: parent }))(), extra); 16 | } 17 | 18 | function merge(dst) { 19 | forEach(arguments, function(obj) { 20 | if (obj !== dst) { 21 | forEach(obj, function(value, key) { 22 | if (!dst.hasOwnProperty(key)) dst[key] = value; 23 | }); 24 | } 25 | }); 26 | return dst; 27 | } 28 | 29 | /** 30 | * Finds the common ancestor path between two states. 31 | * 32 | * @param {Object} first The first state. 33 | * @param {Object} second The second state. 34 | * @return {Array} Returns an array of state names in descending order, not including the root. 35 | */ 36 | function ancestors(first, second) { 37 | var path = []; 38 | 39 | for (var n in first.path) { 40 | if (first.path[n] !== second.path[n]) break; 41 | path.push(first.path[n]); 42 | } 43 | return path; 44 | } 45 | 46 | /** 47 | * IE8-safe wrapper for `Object.keys()`. 48 | * 49 | * @param {Object} object A JavaScript object. 50 | * @return {Array} Returns the keys of the object as an array. 51 | */ 52 | function objectKeys(object) { 53 | if (Object.keys) { 54 | return Object.keys(object); 55 | } 56 | var result = []; 57 | 58 | angular.forEach(object, function(val, key) { 59 | result.push(key); 60 | }); 61 | return result; 62 | } 63 | 64 | /** 65 | * IE8-safe wrapper for `Array.prototype.indexOf()`. 66 | * 67 | * @param {Array} array A JavaScript array. 68 | * @param {*} value A value to search the array for. 69 | * @return {Number} Returns the array index value of `value`, or `-1` if not present. 70 | */ 71 | function indexOf(array, value) { 72 | if (Array.prototype.indexOf) { 73 | return array.indexOf(value, Number(arguments[2]) || 0); 74 | } 75 | var len = array.length >>> 0, from = Number(arguments[2]) || 0; 76 | from = (from < 0) ? Math.ceil(from) : Math.floor(from); 77 | 78 | if (from < 0) from += len; 79 | 80 | for (; from < len; from++) { 81 | if (from in array && array[from] === value) return from; 82 | } 83 | return -1; 84 | } 85 | 86 | /** 87 | * Merges a set of parameters with all parameters inherited between the common parents of the 88 | * current state and a given destination state. 89 | * 90 | * @param {Object} currentParams The value of the current state parameters ($stateParams). 91 | * @param {Object} newParams The set of parameters which will be composited with inherited params. 92 | * @param {Object} $current Internal definition of object representing the current state. 93 | * @param {Object} $to Internal definition of object representing state to transition to. 94 | */ 95 | function inheritParams(currentParams, newParams, $current, $to) { 96 | var parents = ancestors($current, $to), parentParams, inherited = {}, inheritList = []; 97 | 98 | for (var i in parents) { 99 | if (!parents[i].params) continue; 100 | parentParams = objectKeys(parents[i].params); 101 | if (!parentParams.length) continue; 102 | 103 | for (var j in parentParams) { 104 | if (indexOf(inheritList, parentParams[j]) >= 0) continue; 105 | inheritList.push(parentParams[j]); 106 | inherited[parentParams[j]] = currentParams[parentParams[j]]; 107 | } 108 | } 109 | return extend({}, inherited, newParams); 110 | } 111 | 112 | /** 113 | * Performs a non-strict comparison of the subset of two objects, defined by a list of keys. 114 | * 115 | * @param {Object} a The first object. 116 | * @param {Object} b The second object. 117 | * @param {Array} keys The list of keys within each object to compare. If the list is empty or not specified, 118 | * it defaults to the list of keys in `a`. 119 | * @return {Boolean} Returns `true` if the keys match, otherwise `false`. 120 | */ 121 | function equalForKeys(a, b, keys) { 122 | if (!keys) { 123 | keys = []; 124 | for (var n in a) keys.push(n); // Used instead of Object.keys() for IE8 compatibility 125 | } 126 | 127 | for (var i=0; i 274 | * 275 | * 276 | * 277 | * 278 | * 279 | * 280 | * 284 | * 285 | * 286 | * 287 | * 288 | * 289 | */ 290 | angular.module('ui.router', ['ui.router.state']); 291 | 292 | angular.module('ui.router.compat', ['ui.router']); 293 | -------------------------------------------------------------------------------- /bower_components/ui-router/README.md: -------------------------------------------------------------------------------- 1 | # AngularUI Router  [![Build Status](https://travis-ci.org/angular-ui/ui-router.svg?branch=master)](https://travis-ci.org/angular-ui/ui-router) 2 | 3 | #### The de-facto solution to flexible routing with nested views 4 | --- 5 | **[Download 0.2.11](http://angular-ui.github.io/ui-router/release/angular-ui-router.js)** (or **[Minified](http://angular-ui.github.io/ui-router/release/angular-ui-router.min.js)**) **|** 6 | **[Guide](https://github.com/angular-ui/ui-router/wiki) |** 7 | **[API](http://angular-ui.github.io/ui-router/site) |** 8 | **[Sample](http://angular-ui.github.com/ui-router/sample/) ([Src](https://github.com/angular-ui/ui-router/tree/gh-pages/sample)) |** 9 | **[FAQ](https://github.com/angular-ui/ui-router/wiki/Frequently-Asked-Questions) |** 10 | **[Resources](#resources) |** 11 | **[Report an Issue](https://github.com/angular-ui/ui-router/blob/master/CONTRIBUTING.md#report-an-issue) |** 12 | **[Contribute](https://github.com/angular-ui/ui-router/blob/master/CONTRIBUTING.md#contribute) |** 13 | **[Help!](http://stackoverflow.com/questions/ask?tags=angularjs,angular-ui-router) |** 14 | **[Discuss](https://groups.google.com/forum/#!categories/angular-ui/router)** 15 | 16 | --- 17 | 18 | AngularUI Router is a routing framework for [AngularJS](http://angularjs.org), which allows you to organize the 19 | parts of your interface into a [*state machine*](https://en.wikipedia.org/wiki/Finite-state_machine). Unlike the 20 | [`$route` service](http://docs.angularjs.org/api/ngRoute.$route) in the Angular ngRoute module, which is organized around URL 21 | routes, UI-Router is organized around [*states*](https://github.com/angular-ui/ui-router/wiki), 22 | which may optionally have routes, as well as other behavior, attached. 23 | 24 | States are bound to *named*, *nested* and *parallel views*, allowing you to powerfully manage your application's interface. 25 | 26 | Check out the sample app: http://angular-ui.github.io/ui-router/sample/ 27 | 28 | - 29 | **Note:** *UI-Router is under active development. As such, while this library is well-tested, the API may change. Consider using it in production applications only if you're comfortable following a changelog and updating your usage accordingly.* 30 | 31 | 32 | ## Get Started 33 | 34 | **(1)** Get UI-Router in one of the following ways: 35 | - clone & [build](CONTRIBUTING.md#developing) this repository 36 | - [download the release](http://angular-ui.github.io/ui-router/release/angular-ui-router.js) (or [minified](http://angular-ui.github.io/ui-router/release/angular-ui-router.min.js)) 37 | - via **[Bower](http://bower.io/)**: by running `$ bower install angular-ui-router` from your console 38 | - or via **[npm](https://www.npmjs.org/)**: by running `$ npm install angular-ui-router` from your console 39 | - or via **[Component](https://github.com/component/component)**: by running `$ component install angular-ui/ui-router` from your console 40 | 41 | **(2)** Include `angular-ui-router.js` (or `angular-ui-router.min.js`) in your `index.html`, after including Angular itself (For Component users: ignore this step) 42 | 43 | **(3)** Add `'ui.router'` to your main module's list of dependencies (For Component users: replace `'ui.router'` with `require('angular-ui-router')`) 44 | 45 | When you're done, your setup should look similar to the following: 46 | 47 | > 48 | ```html 49 | 50 | 51 | 52 | 53 | 54 | 59 | ... 60 | 61 | 62 | ... 63 | 64 | 65 | ``` 66 | 67 | ### [Nested States & Views](http://plnkr.co/edit/u18KQc?p=preview) 68 | 69 | The majority of UI-Router's power is in its ability to nest states & views. 70 | 71 | **(1)** First, follow the [setup](#get-started) instructions detailed above. 72 | 73 | **(2)** Then, add a [`ui-view` directive](https://github.com/angular-ui/ui-router/wiki/Quick-Reference#ui-view) to the `` of your app. 74 | 75 | > 76 | ```html 77 | 78 | 79 |
80 | 81 | State 1 82 | State 2 83 | 84 | ``` 85 | 86 | **(3)** You'll notice we also added some links with [`ui-sref` directives](https://github.com/angular-ui/ui-router/wiki/Quick-Reference#ui-sref). In addition to managing state transitions, this directive auto-generates the `href` attribute of the `` element it's attached to, if the corresponding state has a URL. Next we'll add some templates. These will plug into the `ui-view` within `index.html`. Notice that they have their own `ui-view` as well! That is the key to nesting states and views. 87 | 88 | > 89 | ```html 90 | 91 |

State 1

92 |
93 |
Show List 94 |
95 | ``` 96 | ```html 97 | 98 |

State 2

99 |
100 | Show List 101 |
102 | ``` 103 | 104 | **(4)** Next, we'll add some child templates. *These* will get plugged into the `ui-view` of their parent state templates. 105 | 106 | > 107 | ```html 108 | 109 |

List of State 1 Items

110 |
    111 |
  • {{ item }}
  • 112 |
113 | ``` 114 | 115 | > 116 | ```html 117 | 118 |

List of State 2 Things

119 |
    120 |
  • {{ thing }}
  • 121 |
122 | ``` 123 | 124 | **(5)** Finally, we'll wire it all up with `$stateProvider`. Set up your states in the module config, as in the following: 125 | 126 | 127 | > 128 | ```javascript 129 | myApp.config(function($stateProvider, $urlRouterProvider) { 130 | // 131 | // For any unmatched url, redirect to /state1 132 | $urlRouterProvider.otherwise("/state1"); 133 | // 134 | // Now set up the states 135 | $stateProvider 136 | .state('state1', { 137 | url: "/state1", 138 | templateUrl: "partials/state1.html" 139 | }) 140 | .state('state1.list', { 141 | url: "/list", 142 | templateUrl: "partials/state1.list.html", 143 | controller: function($scope) { 144 | $scope.items = ["A", "List", "Of", "Items"]; 145 | } 146 | }) 147 | .state('state2', { 148 | url: "/state2", 149 | templateUrl: "partials/state2.html" 150 | }) 151 | .state('state2.list', { 152 | url: "/list", 153 | templateUrl: "partials/state2.list.html", 154 | controller: function($scope) { 155 | $scope.things = ["A", "Set", "Of", "Things"]; 156 | } 157 | }); 158 | }); 159 | ``` 160 | 161 | **(6)** See this quick start example in action. 162 | >**[Go to Quick Start Plunker for Nested States & Views](http://plnkr.co/edit/u18KQc?p=preview)** 163 | 164 | **(7)** This only scratches the surface 165 | >**[Dive Deeper!](https://github.com/angular-ui/ui-router/wiki)** 166 | 167 | 168 | ### [Multiple & Named Views](http://plnkr.co/edit/SDOcGS?p=preview) 169 | 170 | Another great feature is the ability to have multiple `ui-view`s view per template. 171 | 172 | **Pro Tip:** *While multiple parallel views are a powerful feature, you'll often be able to manage your 173 | interfaces more effectively by nesting your views, and pairing those views with nested states.* 174 | 175 | **(1)** Follow the [setup](#get-started) instructions detailed above. 176 | 177 | **(2)** Add one or more `ui-view` to your app, give them names. 178 | > 179 | ```html 180 | 181 | 182 |
183 |
184 | 185 | Route 1 186 | Route 2 187 | 188 | ``` 189 | 190 | **(3)** Set up your states in the module config: 191 | > 192 | ```javascript 193 | myApp.config(function($stateProvider) { 194 | $stateProvider 195 | .state('index', { 196 | url: "", 197 | views: { 198 | "viewA": { template: "index.viewA" }, 199 | "viewB": { template: "index.viewB" } 200 | } 201 | }) 202 | .state('route1', { 203 | url: "/route1", 204 | views: { 205 | "viewA": { template: "route1.viewA" }, 206 | "viewB": { template: "route1.viewB" } 207 | } 208 | }) 209 | .state('route2', { 210 | url: "/route2", 211 | views: { 212 | "viewA": { template: "route2.viewA" }, 213 | "viewB": { template: "route2.viewB" } 214 | } 215 | }) 216 | }); 217 | ``` 218 | 219 | **(4)** See this quick start example in action. 220 | >**[Go to Quick Start Plunker for Multiple & Named Views](http://plnkr.co/edit/SDOcGS?p=preview)** 221 | 222 | 223 | ## Resources 224 | 225 | * [In-Depth Guide](https://github.com/angular-ui/ui-router/wiki) 226 | * [API Reference](http://angular-ui.github.io/ui-router/site) 227 | * [Sample App](http://angular-ui.github.com/ui-router/sample/) ([Source](https://github.com/angular-ui/ui-router/tree/gh-pages/sample)) 228 | * [FAQ](https://github.com/angular-ui/ui-router/wiki/Frequently-Asked-Questions) 229 | * [Slides comparing ngRoute to ui-router](http://slid.es/timkindberg/ui-router#/) 230 | * [UI-Router Extras / Addons](http://christopherthielen.github.io/ui-router-extras/#/home) (@christopherthielen) 231 | 232 | ### Videos 233 | 234 | * [Introduction Video](https://egghead.io/lessons/angularjs-introduction-ui-router) (egghead.io) 235 | * [Tim Kindberg on Angular UI-Router](https://www.youtube.com/watch?v=lBqiZSemrqg) 236 | * [Activating States](https://egghead.io/lessons/angularjs-ui-router-activating-states) (egghead.io) 237 | * [Learn Angular.js using UI-Router](http://youtu.be/QETUuZ27N0w) (LearnCode.academy) 238 | 239 | 240 | 241 | ## Reporting issues and Contributing 242 | 243 | Please read our [Contributor guidelines](CONTRIBUTING.md) before reporting an issue or creating a pull request. 244 | -------------------------------------------------------------------------------- /bower_components/ui-router/src/viewDirective.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @ngdoc directive 3 | * @name ui.router.state.directive:ui-view 4 | * 5 | * @requires ui.router.state.$state 6 | * @requires $compile 7 | * @requires $controller 8 | * @requires $injector 9 | * @requires ui.router.state.$uiViewScroll 10 | * @requires $document 11 | * 12 | * @restrict ECA 13 | * 14 | * @description 15 | * The ui-view directive tells $state where to place your templates. 16 | * 17 | * @param {string=} name A view name. The name should be unique amongst the other views in the 18 | * same state. You can have views of the same name that live in different states. 19 | * 20 | * @param {string=} autoscroll It allows you to set the scroll behavior of the browser window 21 | * when a view is populated. By default, $anchorScroll is overridden by ui-router's custom scroll 22 | * service, {@link ui.router.state.$uiViewScroll}. This custom service let's you 23 | * scroll ui-view elements into view when they are populated during a state activation. 24 | * 25 | * *Note: To revert back to old [`$anchorScroll`](http://docs.angularjs.org/api/ng.$anchorScroll) 26 | * functionality, call `$uiViewScrollProvider.useAnchorScroll()`.* 27 | * 28 | * @param {string=} onload Expression to evaluate whenever the view updates. 29 | * 30 | * @example 31 | * A view can be unnamed or named. 32 | *
 33 |  * 
 34 |  * 
35 | * 36 | * 37 | *
38 | *
39 | * 40 | * You can only have one unnamed view within any template (or root html). If you are only using a 41 | * single view and it is unnamed then you can populate it like so: 42 | *
 43 |  * 
44 | * $stateProvider.state("home", { 45 | * template: "

HELLO!

" 46 | * }) 47 | *
48 | * 49 | * The above is a convenient shortcut equivalent to specifying your view explicitly with the {@link ui.router.state.$stateProvider#views `views`} 50 | * config property, by name, in this case an empty name: 51 | *
 52 |  * $stateProvider.state("home", {
 53 |  *   views: {
 54 |  *     "": {
 55 |  *       template: "

HELLO!

" 56 | * } 57 | * } 58 | * }) 59 | *
60 | * 61 | * But typically you'll only use the views property if you name your view or have more than one view 62 | * in the same template. There's not really a compelling reason to name a view if its the only one, 63 | * but you could if you wanted, like so: 64 | *
 65 |  * 
66 | *
67 | *
 68 |  * $stateProvider.state("home", {
 69 |  *   views: {
 70 |  *     "main": {
 71 |  *       template: "

HELLO!

" 72 | * } 73 | * } 74 | * }) 75 | *
76 | * 77 | * Really though, you'll use views to set up multiple views: 78 | *
 79 |  * 
80 | *
81 | *
82 | *
83 | * 84 | *
 85 |  * $stateProvider.state("home", {
 86 |  *   views: {
 87 |  *     "": {
 88 |  *       template: "

HELLO!

" 89 | * }, 90 | * "chart": { 91 | * template: "" 92 | * }, 93 | * "data": { 94 | * template: "" 95 | * } 96 | * } 97 | * }) 98 | *
99 | * 100 | * Examples for `autoscroll`: 101 | * 102 | *
103 |  * 
105 |  * 
106 |  *
107 |  * 
109 |  * 
110 |  * 
111 |  * 
112 |  * 
113 | */ 114 | $ViewDirective.$inject = ['$state', '$injector', '$uiViewScroll', '$interpolate']; 115 | function $ViewDirective( $state, $injector, $uiViewScroll, $interpolate) { 116 | 117 | function getService() { 118 | return ($injector.has) ? function(service) { 119 | return $injector.has(service) ? $injector.get(service) : null; 120 | } : function(service) { 121 | try { 122 | return $injector.get(service); 123 | } catch (e) { 124 | return null; 125 | } 126 | }; 127 | } 128 | 129 | var service = getService(), 130 | $animator = service('$animator'), 131 | $animate = service('$animate'); 132 | 133 | // Returns a set of DOM manipulation functions based on which Angular version 134 | // it should use 135 | function getRenderer(attrs, scope) { 136 | var statics = function() { 137 | return { 138 | enter: function (element, target, cb) { target.after(element); cb(); }, 139 | leave: function (element, cb) { element.remove(); cb(); } 140 | }; 141 | }; 142 | 143 | if ($animate) { 144 | return { 145 | enter: function(element, target, cb) { 146 | var promise = $animate.enter(element, null, target, cb); 147 | if (promise && promise.then) promise.then(cb); 148 | }, 149 | leave: function(element, cb) { 150 | var promise = $animate.leave(element, cb); 151 | if (promise && promise.then) promise.then(cb); 152 | } 153 | }; 154 | } 155 | 156 | if ($animator) { 157 | var animate = $animator && $animator(scope, attrs); 158 | 159 | return { 160 | enter: function(element, target, cb) {animate.enter(element, null, target); cb(); }, 161 | leave: function(element, cb) { animate.leave(element); cb(); } 162 | }; 163 | } 164 | 165 | return statics(); 166 | } 167 | 168 | var directive = { 169 | restrict: 'ECA', 170 | terminal: true, 171 | priority: 400, 172 | transclude: 'element', 173 | compile: function (tElement, tAttrs, $transclude) { 174 | return function (scope, $element, attrs) { 175 | var previousEl, currentEl, currentScope, latestLocals, 176 | onloadExp = attrs.onload || '', 177 | autoScrollExp = attrs.autoscroll, 178 | renderer = getRenderer(attrs, scope); 179 | 180 | scope.$on('$stateChangeSuccess', function() { 181 | updateView(false); 182 | }); 183 | scope.$on('$viewContentLoading', function() { 184 | updateView(false); 185 | }); 186 | 187 | updateView(true); 188 | 189 | function cleanupLastView() { 190 | if (previousEl) { 191 | previousEl.remove(); 192 | previousEl = null; 193 | } 194 | 195 | if (currentScope) { 196 | currentScope.$destroy(); 197 | currentScope = null; 198 | } 199 | 200 | if (currentEl) { 201 | renderer.leave(currentEl, function() { 202 | previousEl = null; 203 | }); 204 | 205 | previousEl = currentEl; 206 | currentEl = null; 207 | } 208 | } 209 | 210 | function updateView(firstTime) { 211 | var newScope, 212 | name = getUiViewName(scope, attrs, $element, $interpolate), 213 | previousLocals = name && $state.$current && $state.$current.locals[name]; 214 | 215 | if (!firstTime && previousLocals === latestLocals) return; // nothing to do 216 | newScope = scope.$new(); 217 | latestLocals = $state.$current.locals[name]; 218 | 219 | var clone = $transclude(newScope, function(clone) { 220 | renderer.enter(clone, $element, function onUiViewEnter() { 221 | if(currentScope) { 222 | currentScope.$emit('$viewContentAnimationEnded'); 223 | } 224 | 225 | if (angular.isDefined(autoScrollExp) && !autoScrollExp || scope.$eval(autoScrollExp)) { 226 | $uiViewScroll(clone); 227 | } 228 | }); 229 | cleanupLastView(); 230 | }); 231 | 232 | currentEl = clone; 233 | currentScope = newScope; 234 | /** 235 | * @ngdoc event 236 | * @name ui.router.state.directive:ui-view#$viewContentLoaded 237 | * @eventOf ui.router.state.directive:ui-view 238 | * @eventType emits on ui-view directive scope 239 | * @description * 240 | * Fired once the view is **loaded**, *after* the DOM is rendered. 241 | * 242 | * @param {Object} event Event object. 243 | */ 244 | currentScope.$emit('$viewContentLoaded'); 245 | currentScope.$eval(onloadExp); 246 | } 247 | }; 248 | } 249 | }; 250 | 251 | return directive; 252 | } 253 | 254 | $ViewDirectiveFill.$inject = ['$compile', '$controller', '$state', '$interpolate']; 255 | function $ViewDirectiveFill ( $compile, $controller, $state, $interpolate) { 256 | return { 257 | restrict: 'ECA', 258 | priority: -400, 259 | compile: function (tElement) { 260 | var initial = tElement.html(); 261 | return function (scope, $element, attrs) { 262 | var current = $state.$current, 263 | name = getUiViewName(scope, attrs, $element, $interpolate), 264 | locals = current && current.locals[name]; 265 | 266 | if (! locals) { 267 | return; 268 | } 269 | 270 | $element.data('$uiView', { name: name, state: locals.$$state }); 271 | $element.html(locals.$template ? locals.$template : initial); 272 | 273 | var link = $compile($element.contents()); 274 | 275 | if (locals.$$controller) { 276 | locals.$scope = scope; 277 | var controller = $controller(locals.$$controller, locals); 278 | if (locals.$$controllerAs) { 279 | scope[locals.$$controllerAs] = controller; 280 | } 281 | $element.data('$ngControllerController', controller); 282 | $element.children().data('$ngControllerController', controller); 283 | } 284 | 285 | link(scope); 286 | }; 287 | } 288 | }; 289 | } 290 | 291 | /** 292 | * Shared ui-view code for both directives: 293 | * Given scope, element, and its attributes, return the view's name 294 | */ 295 | function getUiViewName(scope, attrs, element, $interpolate) { 296 | var name = $interpolate(attrs.uiView || attrs.name || '')(scope); 297 | var inherited = element.inheritedData('$uiView'); 298 | return name.indexOf('@') >= 0 ? name : (name + '@' + (inherited ? inherited.state.name : '')); 299 | } 300 | 301 | angular.module('ui.router.state').directive('uiView', $ViewDirective); 302 | angular.module('ui.router.state').directive('uiView', $ViewDirectiveFill); 303 | -------------------------------------------------------------------------------- /bower_components/ui-router/src/stateDirectives.js: -------------------------------------------------------------------------------- 1 | function parseStateRef(ref, current) { 2 | var preparsed = ref.match(/^\s*({[^}]*})\s*$/), parsed; 3 | if (preparsed) ref = current + '(' + preparsed[1] + ')'; 4 | parsed = ref.replace(/\n/g, " ").match(/^([^(]+?)\s*(\((.*)\))?$/); 5 | if (!parsed || parsed.length !== 4) throw new Error("Invalid state ref '" + ref + "'"); 6 | return { state: parsed[1], paramExpr: parsed[3] || null }; 7 | } 8 | 9 | function stateContext(el) { 10 | var stateData = el.parent().inheritedData('$uiView'); 11 | 12 | if (stateData && stateData.state && stateData.state.name) { 13 | return stateData.state; 14 | } 15 | } 16 | 17 | /** 18 | * @ngdoc directive 19 | * @name ui.router.state.directive:ui-sref 20 | * 21 | * @requires ui.router.state.$state 22 | * @requires $timeout 23 | * 24 | * @restrict A 25 | * 26 | * @description 27 | * A directive that binds a link (`` tag) to a state. If the state has an associated 28 | * URL, the directive will automatically generate & update the `href` attribute via 29 | * the {@link ui.router.state.$state#methods_href $state.href()} method. Clicking 30 | * the link will trigger a state transition with optional parameters. 31 | * 32 | * Also middle-clicking, right-clicking, and ctrl-clicking on the link will be 33 | * handled natively by the browser. 34 | * 35 | * You can also use relative state paths within ui-sref, just like the relative 36 | * paths passed to `$state.go()`. You just need to be aware that the path is relative 37 | * to the state that the link lives in, in other words the state that loaded the 38 | * template containing the link. 39 | * 40 | * You can specify options to pass to {@link ui.router.state.$state#go $state.go()} 41 | * using the `ui-sref-opts` attribute. Options are restricted to `location`, `inherit`, 42 | * and `reload`. 43 | * 44 | * @example 45 | * Here's an example of how you'd use ui-sref and how it would compile. If you have the 46 | * following template: 47 | *
 48 |  * Home | About | Next page
 49 |  * 
 50 |  * 
 55 |  * 
56 | * 57 | * Then the compiled html would be (assuming Html5Mode is off and current state is contacts): 58 | *
 59 |  * Home | About | Next page
 60 |  * 
 61 |  * 
    62 | *
  • 63 | * Joe 64 | *
  • 65 | *
  • 66 | * Alice 67 | *
  • 68 | *
  • 69 | * Bob 70 | *
  • 71 | *
72 | * 73 | * Home 74 | *
75 | * 76 | * @param {string} ui-sref 'stateName' can be any valid absolute or relative state 77 | * @param {Object} ui-sref-opts options to pass to {@link ui.router.state.$state#go $state.go()} 78 | */ 79 | $StateRefDirective.$inject = ['$state', '$timeout']; 80 | function $StateRefDirective($state, $timeout) { 81 | var allowedOptions = ['location', 'inherit', 'reload']; 82 | 83 | return { 84 | restrict: 'A', 85 | require: ['?^uiSrefActive', '?^uiSrefActiveEq'], 86 | link: function(scope, element, attrs, uiSrefActive) { 87 | var ref = parseStateRef(attrs.uiSref, $state.current.name); 88 | var params = null, url = null, base = stateContext(element) || $state.$current; 89 | var newHref = null, isAnchor = element.prop("tagName") === "A"; 90 | var isForm = element[0].nodeName === "FORM"; 91 | var attr = isForm ? "action" : "href", nav = true; 92 | 93 | var options = { relative: base, inherit: true }; 94 | var optionsOverride = scope.$eval(attrs.uiSrefOpts) || {}; 95 | 96 | angular.forEach(allowedOptions, function(option) { 97 | if (option in optionsOverride) { 98 | options[option] = optionsOverride[option]; 99 | } 100 | }); 101 | 102 | var update = function(newVal) { 103 | if (newVal) params = angular.copy(newVal); 104 | if (!nav) return; 105 | 106 | newHref = $state.href(ref.state, params, options); 107 | 108 | var activeDirective = uiSrefActive[1] || uiSrefActive[0]; 109 | if (activeDirective) { 110 | activeDirective.$$setStateInfo(ref.state, params); 111 | } 112 | if (newHref === null) { 113 | nav = false; 114 | return false; 115 | } 116 | attrs.$set(attr, newHref); 117 | }; 118 | 119 | if (ref.paramExpr) { 120 | scope.$watch(ref.paramExpr, function(newVal, oldVal) { 121 | if (newVal !== params) update(newVal); 122 | }, true); 123 | params = angular.copy(scope.$eval(ref.paramExpr)); 124 | } 125 | update(); 126 | 127 | if (isForm) return; 128 | 129 | element.bind("click", function(e) { 130 | var button = e.which || e.button; 131 | if ( !(button > 1 || e.ctrlKey || e.metaKey || e.shiftKey || element.attr('target')) ) { 132 | // HACK: This is to allow ng-clicks to be processed before the transition is initiated: 133 | var transition = $timeout(function() { 134 | $state.go(ref.state, params, options); 135 | }); 136 | e.preventDefault(); 137 | 138 | // if the state has no URL, ignore one preventDefault from the directive. 139 | var ignorePreventDefaultCount = isAnchor && !newHref ? 1: 0; 140 | e.preventDefault = function() { 141 | if (ignorePreventDefaultCount-- <= 0) 142 | $timeout.cancel(transition); 143 | }; 144 | } 145 | }); 146 | } 147 | }; 148 | } 149 | 150 | /** 151 | * @ngdoc directive 152 | * @name ui.router.state.directive:ui-sref-active 153 | * 154 | * @requires ui.router.state.$state 155 | * @requires ui.router.state.$stateParams 156 | * @requires $interpolate 157 | * 158 | * @restrict A 159 | * 160 | * @description 161 | * A directive working alongside ui-sref to add classes to an element when the 162 | * related ui-sref directive's state is active, and removing them when it is inactive. 163 | * The primary use-case is to simplify the special appearance of navigation menus 164 | * relying on `ui-sref`, by having the "active" state's menu button appear different, 165 | * distinguishing it from the inactive menu items. 166 | * 167 | * ui-sref-active can live on the same element as ui-sref or on a parent element. The first 168 | * ui-sref-active found at the same level or above the ui-sref will be used. 169 | * 170 | * Will activate when the ui-sref's target state or any child state is active. If you 171 | * need to activate only when the ui-sref target state is active and *not* any of 172 | * it's children, then you will use 173 | * {@link ui.router.state.directive:ui-sref-active-eq ui-sref-active-eq} 174 | * 175 | * @example 176 | * Given the following template: 177 | *
178 |  * 
183 |  * 
184 | * 185 | * 186 | * When the app state is "app.user" (or any children states), and contains the state parameter "user" with value "bilbobaggins", 187 | * the resulting HTML will appear as (note the 'active' class): 188 | *
189 |  * 
194 |  * 
195 | * 196 | * The class name is interpolated **once** during the directives link time (any further changes to the 197 | * interpolated value are ignored). 198 | * 199 | * Multiple classes may be specified in a space-separated format: 200 | *
201 |  * 
    202 | *
  • 203 | * link 204 | *
  • 205 | *
206 | *
207 | */ 208 | 209 | /** 210 | * @ngdoc directive 211 | * @name ui.router.state.directive:ui-sref-active-eq 212 | * 213 | * @requires ui.router.state.$state 214 | * @requires ui.router.state.$stateParams 215 | * @requires $interpolate 216 | * 217 | * @restrict A 218 | * 219 | * @description 220 | * The same as {@link ui.router.state.directive:ui-sref-active ui-sref-active} but will only activate 221 | * when the exact target state used in the `ui-sref` is active; no child states. 222 | * 223 | */ 224 | $StateRefActiveDirective.$inject = ['$state', '$stateParams', '$interpolate']; 225 | function $StateRefActiveDirective($state, $stateParams, $interpolate) { 226 | return { 227 | restrict: "A", 228 | controller: ['$scope', '$element', '$attrs', function ($scope, $element, $attrs) { 229 | var state, params, activeClass; 230 | 231 | // There probably isn't much point in $observing this 232 | // uiSrefActive and uiSrefActiveEq share the same directive object with some 233 | // slight difference in logic routing 234 | activeClass = $interpolate($attrs.uiSrefActiveEq || $attrs.uiSrefActive || '', false)($scope); 235 | 236 | // Allow uiSref to communicate with uiSrefActive[Equals] 237 | this.$$setStateInfo = function (newState, newParams) { 238 | state = $state.get(newState, stateContext($element)); 239 | params = newParams; 240 | update(); 241 | }; 242 | 243 | $scope.$on('$stateChangeSuccess', update); 244 | 245 | // Update route state 246 | function update() { 247 | if (isMatch()) { 248 | $element.addClass(activeClass); 249 | } else { 250 | $element.removeClass(activeClass); 251 | } 252 | } 253 | 254 | function isMatch() { 255 | if (typeof $attrs.uiSrefActiveEq !== 'undefined') { 256 | return state && $state.is(state.name, params); 257 | } else { 258 | return state && $state.includes(state.name, params); 259 | } 260 | } 261 | }] 262 | }; 263 | } 264 | 265 | angular.module('ui.router.state') 266 | .directive('uiSref', $StateRefDirective) 267 | .directive('uiSrefActive', $StateRefActiveDirective) 268 | .directive('uiSrefActiveEq', $StateRefActiveDirective); 269 | -------------------------------------------------------------------------------- /bower_components/ui-router/src/resolve.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @ngdoc object 3 | * @name ui.router.util.$resolve 4 | * 5 | * @requires $q 6 | * @requires $injector 7 | * 8 | * @description 9 | * Manages resolution of (acyclic) graphs of promises. 10 | */ 11 | $Resolve.$inject = ['$q', '$injector']; 12 | function $Resolve( $q, $injector) { 13 | 14 | var VISIT_IN_PROGRESS = 1, 15 | VISIT_DONE = 2, 16 | NOTHING = {}, 17 | NO_DEPENDENCIES = [], 18 | NO_LOCALS = NOTHING, 19 | NO_PARENT = extend($q.when(NOTHING), { $$promises: NOTHING, $$values: NOTHING }); 20 | 21 | 22 | /** 23 | * @ngdoc function 24 | * @name ui.router.util.$resolve#study 25 | * @methodOf ui.router.util.$resolve 26 | * 27 | * @description 28 | * Studies a set of invocables that are likely to be used multiple times. 29 | *
 30 |    * $resolve.study(invocables)(locals, parent, self)
 31 |    * 
32 | * is equivalent to 33 | *
 34 |    * $resolve.resolve(invocables, locals, parent, self)
 35 |    * 
36 | * but the former is more efficient (in fact `resolve` just calls `study` 37 | * internally). 38 | * 39 | * @param {object} invocables Invocable objects 40 | * @return {function} a function to pass in locals, parent and self 41 | */ 42 | this.study = function (invocables) { 43 | if (!isObject(invocables)) throw new Error("'invocables' must be an object"); 44 | var invocableKeys = objectKeys(invocables || {}); 45 | 46 | // Perform a topological sort of invocables to build an ordered plan 47 | var plan = [], cycle = [], visited = {}; 48 | function visit(value, key) { 49 | if (visited[key] === VISIT_DONE) return; 50 | 51 | cycle.push(key); 52 | if (visited[key] === VISIT_IN_PROGRESS) { 53 | cycle.splice(0, indexOf(cycle, key)); 54 | throw new Error("Cyclic dependency: " + cycle.join(" -> ")); 55 | } 56 | visited[key] = VISIT_IN_PROGRESS; 57 | 58 | if (isString(value)) { 59 | plan.push(key, [ function() { return $injector.get(value); }], NO_DEPENDENCIES); 60 | } else { 61 | var params = $injector.annotate(value); 62 | forEach(params, function (param) { 63 | if (param !== key && invocables.hasOwnProperty(param)) visit(invocables[param], param); 64 | }); 65 | plan.push(key, value, params); 66 | } 67 | 68 | cycle.pop(); 69 | visited[key] = VISIT_DONE; 70 | } 71 | forEach(invocables, visit); 72 | invocables = cycle = visited = null; // plan is all that's required 73 | 74 | function isResolve(value) { 75 | return isObject(value) && value.then && value.$$promises; 76 | } 77 | 78 | return function (locals, parent, self) { 79 | if (isResolve(locals) && self === undefined) { 80 | self = parent; parent = locals; locals = null; 81 | } 82 | if (!locals) locals = NO_LOCALS; 83 | else if (!isObject(locals)) { 84 | throw new Error("'locals' must be an object"); 85 | } 86 | if (!parent) parent = NO_PARENT; 87 | else if (!isResolve(parent)) { 88 | throw new Error("'parent' must be a promise returned by $resolve.resolve()"); 89 | } 90 | 91 | // To complete the overall resolution, we have to wait for the parent 92 | // promise and for the promise for each invokable in our plan. 93 | var resolution = $q.defer(), 94 | result = resolution.promise, 95 | promises = result.$$promises = {}, 96 | values = extend({}, locals), 97 | wait = 1 + plan.length/3, 98 | merged = false; 99 | 100 | function done() { 101 | // Merge parent values we haven't got yet and publish our own $$values 102 | if (!--wait) { 103 | if (!merged) merge(values, parent.$$values); 104 | result.$$values = values; 105 | result.$$promises = result.$$promises || true; // keep for isResolve() 106 | delete result.$$inheritedValues; 107 | resolution.resolve(values); 108 | } 109 | } 110 | 111 | function fail(reason) { 112 | result.$$failure = reason; 113 | resolution.reject(reason); 114 | } 115 | 116 | // Short-circuit if parent has already failed 117 | if (isDefined(parent.$$failure)) { 118 | fail(parent.$$failure); 119 | return result; 120 | } 121 | 122 | if (parent.$$inheritedValues) { 123 | merge(values, omit(parent.$$inheritedValues, invocableKeys)); 124 | } 125 | 126 | // Merge parent values if the parent has already resolved, or merge 127 | // parent promises and wait if the parent resolve is still in progress. 128 | extend(promises, parent.$$promises); 129 | if (parent.$$values) { 130 | merged = merge(values, omit(parent.$$values, invocableKeys)); 131 | result.$$inheritedValues = omit(parent.$$values, invocableKeys); 132 | done(); 133 | } else { 134 | if (parent.$$inheritedValues) { 135 | result.$$inheritedValues = omit(parent.$$inheritedValues, invocableKeys); 136 | } 137 | parent.then(done, fail); 138 | } 139 | 140 | // Process each invocable in the plan, but ignore any where a local of the same name exists. 141 | for (var i=0, ii=plan.length; i 45 | * var app = angular.module('app', ['ui.router.router']); 46 | * 47 | * app.config(function ($urlRouterProvider) { 48 | * // Here's an example of how you might allow case insensitive urls 49 | * $urlRouterProvider.rule(function ($injector, $location) { 50 | * var path = $location.path(), 51 | * normalized = path.toLowerCase(); 52 | * 53 | * if (path !== normalized) { 54 | * return normalized; 55 | * } 56 | * }); 57 | * }); 58 | * 59 | * 60 | * @param {object} rule Handler function that takes `$injector` and `$location` 61 | * services as arguments. You can use them to return a valid path as a string. 62 | * 63 | * @return {object} `$urlRouterProvider` - `$urlRouterProvider` instance 64 | */ 65 | this.rule = function (rule) { 66 | if (!isFunction(rule)) throw new Error("'rule' must be a function"); 67 | rules.push(rule); 68 | return this; 69 | }; 70 | 71 | /** 72 | * @ngdoc object 73 | * @name ui.router.router.$urlRouterProvider#otherwise 74 | * @methodOf ui.router.router.$urlRouterProvider 75 | * 76 | * @description 77 | * Defines a path that is used when an invalid route is requested. 78 | * 79 | * @example 80 | *
 81 |    * var app = angular.module('app', ['ui.router.router']);
 82 |    *
 83 |    * app.config(function ($urlRouterProvider) {
 84 |    *   // if the path doesn't match any of the urls you configured
 85 |    *   // otherwise will take care of routing the user to the
 86 |    *   // specified url
 87 |    *   $urlRouterProvider.otherwise('/index');
 88 |    *
 89 |    *   // Example of using function rule as param
 90 |    *   $urlRouterProvider.otherwise(function ($injector, $location) {
 91 |    *     return '/a/valid/url';
 92 |    *   });
 93 |    * });
 94 |    * 
95 | * 96 | * @param {string|object} rule The url path you want to redirect to or a function 97 | * rule that returns the url path. The function version is passed two params: 98 | * `$injector` and `$location` services, and must return a url string. 99 | * 100 | * @return {object} `$urlRouterProvider` - `$urlRouterProvider` instance 101 | */ 102 | this.otherwise = function (rule) { 103 | if (isString(rule)) { 104 | var redirect = rule; 105 | rule = function () { return redirect; }; 106 | } 107 | else if (!isFunction(rule)) throw new Error("'rule' must be a function"); 108 | otherwise = rule; 109 | return this; 110 | }; 111 | 112 | 113 | function handleIfMatch($injector, handler, match) { 114 | if (!match) return false; 115 | var result = $injector.invoke(handler, handler, { $match: match }); 116 | return isDefined(result) ? result : true; 117 | } 118 | 119 | /** 120 | * @ngdoc function 121 | * @name ui.router.router.$urlRouterProvider#when 122 | * @methodOf ui.router.router.$urlRouterProvider 123 | * 124 | * @description 125 | * Registers a handler for a given url matching. if handle is a string, it is 126 | * treated as a redirect, and is interpolated according to the syntax of match 127 | * (i.e. like `String.replace()` for `RegExp`, or like a `UrlMatcher` pattern otherwise). 128 | * 129 | * If the handler is a function, it is injectable. It gets invoked if `$location` 130 | * matches. You have the option of inject the match object as `$match`. 131 | * 132 | * The handler can return 133 | * 134 | * - **falsy** to indicate that the rule didn't match after all, then `$urlRouter` 135 | * will continue trying to find another one that matches. 136 | * - **string** which is treated as a redirect and passed to `$location.url()` 137 | * - **void** or any **truthy** value tells `$urlRouter` that the url was handled. 138 | * 139 | * @example 140 | *
141 |    * var app = angular.module('app', ['ui.router.router']);
142 |    *
143 |    * app.config(function ($urlRouterProvider) {
144 |    *   $urlRouterProvider.when($state.url, function ($match, $stateParams) {
145 |    *     if ($state.$current.navigable !== state ||
146 |    *         !equalForKeys($match, $stateParams) {
147 |    *      $state.transitionTo(state, $match, false);
148 |    *     }
149 |    *   });
150 |    * });
151 |    * 
152 | * 153 | * @param {string|object} what The incoming path that you want to redirect. 154 | * @param {string|object} handler The path you want to redirect your user to. 155 | */ 156 | this.when = function (what, handler) { 157 | var redirect, handlerIsString = isString(handler); 158 | if (isString(what)) what = $urlMatcherFactory.compile(what); 159 | 160 | if (!handlerIsString && !isFunction(handler) && !isArray(handler)) 161 | throw new Error("invalid 'handler' in when()"); 162 | 163 | var strategies = { 164 | matcher: function (what, handler) { 165 | if (handlerIsString) { 166 | redirect = $urlMatcherFactory.compile(handler); 167 | handler = ['$match', function ($match) { return redirect.format($match); }]; 168 | } 169 | return extend(function ($injector, $location) { 170 | return handleIfMatch($injector, handler, what.exec($location.path(), $location.search())); 171 | }, { 172 | prefix: isString(what.prefix) ? what.prefix : '' 173 | }); 174 | }, 175 | regex: function (what, handler) { 176 | if (what.global || what.sticky) throw new Error("when() RegExp must not be global or sticky"); 177 | 178 | if (handlerIsString) { 179 | redirect = handler; 180 | handler = ['$match', function ($match) { return interpolate(redirect, $match); }]; 181 | } 182 | return extend(function ($injector, $location) { 183 | return handleIfMatch($injector, handler, what.exec($location.path())); 184 | }, { 185 | prefix: regExpPrefix(what) 186 | }); 187 | } 188 | }; 189 | 190 | var check = { matcher: $urlMatcherFactory.isMatcher(what), regex: what instanceof RegExp }; 191 | 192 | for (var n in check) { 193 | if (check[n]) return this.rule(strategies[n](what, handler)); 194 | } 195 | 196 | throw new Error("invalid 'what' in when()"); 197 | }; 198 | 199 | /** 200 | * @ngdoc function 201 | * @name ui.router.router.$urlRouterProvider#deferIntercept 202 | * @methodOf ui.router.router.$urlRouterProvider 203 | * 204 | * @description 205 | * Disables (or enables) deferring location change interception. 206 | * 207 | * If you wish to customize the behavior of syncing the URL (for example, if you wish to 208 | * defer a transition but maintain the current URL), call this method at configuration time. 209 | * Then, at run time, call `$urlRouter.listen()` after you have configured your own 210 | * `$locationChangeSuccess` event handler. 211 | * 212 | * @example 213 | *
214 |    * var app = angular.module('app', ['ui.router.router']);
215 |    *
216 |    * app.config(function ($urlRouterProvider) {
217 |    *
218 |    *   // Prevent $urlRouter from automatically intercepting URL changes;
219 |    *   // this allows you to configure custom behavior in between
220 |    *   // location changes and route synchronization:
221 |    *   $urlRouterProvider.deferIntercept();
222 |    *
223 |    * }).run(function ($rootScope, $urlRouter, UserService) {
224 |    *
225 |    *   $rootScope.$on('$locationChangeSuccess', function(e) {
226 |    *     // UserService is an example service for managing user state
227 |    *     if (UserService.isLoggedIn()) return;
228 |    *
229 |    *     // Prevent $urlRouter's default handler from firing
230 |    *     e.preventDefault();
231 |    *
232 |    *     UserService.handleLogin().then(function() {
233 |    *       // Once the user has logged in, sync the current URL
234 |    *       // to the router:
235 |    *       $urlRouter.sync();
236 |    *     });
237 |    *   });
238 |    *
239 |    *   // Configures $urlRouter's listener *after* your custom listener
240 |    *   $urlRouter.listen();
241 |    * });
242 |    * 
243 | * 244 | * @param {boolean} defer Indicates whether to defer location change interception. Passing 245 | no parameter is equivalent to `true`. 246 | */ 247 | this.deferIntercept = function (defer) { 248 | if (defer === undefined) defer = true; 249 | interceptDeferred = defer; 250 | }; 251 | 252 | /** 253 | * @ngdoc object 254 | * @name ui.router.router.$urlRouter 255 | * 256 | * @requires $location 257 | * @requires $rootScope 258 | * @requires $injector 259 | * @requires $browser 260 | * 261 | * @description 262 | * 263 | */ 264 | this.$get = $get; 265 | $get.$inject = ['$location', '$rootScope', '$injector', '$browser']; 266 | function $get( $location, $rootScope, $injector, $browser) { 267 | 268 | var baseHref = $browser.baseHref(), location = $location.url(), lastPushedUrl; 269 | 270 | function appendBasePath(url, isHtml5, absolute) { 271 | if (baseHref === '/') return url; 272 | if (isHtml5) return baseHref.slice(0, -1) + url; 273 | if (absolute) return baseHref.slice(1) + url; 274 | return url; 275 | } 276 | 277 | // TODO: Optimize groups of rules with non-empty prefix into some sort of decision tree 278 | function update(evt) { 279 | if (evt && evt.defaultPrevented) return; 280 | var ignoreUpdate = lastPushedUrl && $location.url() === lastPushedUrl; 281 | lastPushedUrl = undefined; 282 | if (ignoreUpdate) return true; 283 | 284 | function check(rule) { 285 | var handled = rule($injector, $location); 286 | 287 | if (!handled) return false; 288 | if (isString(handled)) $location.replace().url(handled); 289 | return true; 290 | } 291 | var n = rules.length, i; 292 | 293 | for (i = 0; i < n; i++) { 294 | if (check(rules[i])) return; 295 | } 296 | // always check otherwise last to allow dynamic updates to the set of rules 297 | if (otherwise) check(otherwise); 298 | } 299 | 300 | function listen() { 301 | listener = listener || $rootScope.$on('$locationChangeSuccess', update); 302 | return listener; 303 | } 304 | 305 | if (!interceptDeferred) listen(); 306 | 307 | return { 308 | /** 309 | * @ngdoc function 310 | * @name ui.router.router.$urlRouter#sync 311 | * @methodOf ui.router.router.$urlRouter 312 | * 313 | * @description 314 | * Triggers an update; the same update that happens when the address bar url changes, aka `$locationChangeSuccess`. 315 | * This method is useful when you need to use `preventDefault()` on the `$locationChangeSuccess` event, 316 | * perform some custom logic (route protection, auth, config, redirection, etc) and then finally proceed 317 | * with the transition by calling `$urlRouter.sync()`. 318 | * 319 | * @example 320 | *
321 |        * angular.module('app', ['ui.router'])
322 |        *   .run(function($rootScope, $urlRouter) {
323 |        *     $rootScope.$on('$locationChangeSuccess', function(evt) {
324 |        *       // Halt state change from even starting
325 |        *       evt.preventDefault();
326 |        *       // Perform custom logic
327 |        *       var meetsRequirement = ...
328 |        *       // Continue with the update and state transition if logic allows
329 |        *       if (meetsRequirement) $urlRouter.sync();
330 |        *     });
331 |        * });
332 |        * 
333 | */ 334 | sync: function() { 335 | update(); 336 | }, 337 | 338 | listen: function() { 339 | return listen(); 340 | }, 341 | 342 | update: function(read) { 343 | if (read) { 344 | location = $location.url(); 345 | return; 346 | } 347 | if ($location.url() === location) return; 348 | 349 | $location.url(location); 350 | $location.replace(); 351 | }, 352 | 353 | push: function(urlMatcher, params, options) { 354 | $location.url(urlMatcher.format(params || {})); 355 | lastPushedUrl = options && options.$$avoidResync ? $location.url() : undefined; 356 | if (options && options.replace) $location.replace(); 357 | }, 358 | 359 | /** 360 | * @ngdoc function 361 | * @name ui.router.router.$urlRouter#href 362 | * @methodOf ui.router.router.$urlRouter 363 | * 364 | * @description 365 | * A URL generation method that returns the compiled URL for a given 366 | * {@link ui.router.util.type:UrlMatcher `UrlMatcher`}, populated with the provided parameters. 367 | * 368 | * @example 369 | *
370 |        * $bob = $urlRouter.href(new UrlMatcher("/about/:person"), {
371 |        *   person: "bob"
372 |        * });
373 |        * // $bob == "/about/bob";
374 |        * 
375 | * 376 | * @param {UrlMatcher} urlMatcher The `UrlMatcher` object which is used as the template of the URL to generate. 377 | * @param {object=} params An object of parameter values to fill the matcher's required parameters. 378 | * @param {object=} options Options object. The options are: 379 | * 380 | * - **`absolute`** - {boolean=false}, If true will generate an absolute url, e.g. "http://www.example.com/fullurl". 381 | * 382 | * @returns {string} Returns the fully compiled URL, or `null` if `params` fail validation against `urlMatcher` 383 | */ 384 | href: function(urlMatcher, params, options) { 385 | if (!urlMatcher.validates(params)) return null; 386 | 387 | var isHtml5 = $locationProvider.html5Mode(); 388 | if (angular.isObject(isHtml5)) { 389 | isHtml5 = isHtml5.enabled; 390 | } 391 | 392 | var url = urlMatcher.format(params); 393 | options = options || {}; 394 | 395 | if (!isHtml5 && url !== null) { 396 | url = "#" + $locationProvider.hashPrefix() + url; 397 | } 398 | url = appendBasePath(url, isHtml5, options.absolute); 399 | 400 | if (!options.absolute || !url) { 401 | return url; 402 | } 403 | 404 | var slash = (!isHtml5 && url ? '/' : ''), port = $location.port(); 405 | port = (port === 80 || port === 443 ? '' : ':' + port); 406 | 407 | return [$location.protocol(), '://', $location.host(), port, slash, url].join(''); 408 | } 409 | }; 410 | } 411 | } 412 | 413 | angular.module('ui.router.router').provider('$urlRouter', $UrlRouterProvider); 414 | -------------------------------------------------------------------------------- /bower_components/ui-router/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | ### 0.2.13 (2014-11-20) 3 | 4 | This release primarily fixes issues reported against 0.2.12 5 | 6 | #### Bug Fixes 7 | 8 | * **$state:** fix $state.includes/.is to apply param types before comparisions fix(uiSref): ma ([19715d15](https://github.com/angular-ui/ui-router/commit/19715d15e3cbfff724519e9febedd05b49c75baa), closes [#1513](https://github.com/angular-ui/ui-router/issues/1513)) 9 | * Avoid re-synchronizing from url after .transitionTo ([b267ecd3](https://github.com/angular-ui/ui-router/commit/b267ecd348e5c415233573ef95ebdbd051875f52), closes [#1573](https://github.com/angular-ui/ui-router/issues/1573)) 10 | * **$urlMatcherFactory:** 11 | * Built-in date type uses local time zone ([d726bedc](https://github.com/angular-ui/ui-router/commit/d726bedcbb5f70a5660addf43fd52ec730790293)) 12 | * make date type fn check .is before running ([aa94ce3b](https://github.com/angular-ui/ui-router/commit/aa94ce3b86632ad05301530a2213099da73a3dc0), closes [#1564](https://github.com/angular-ui/ui-router/issues/1564)) 13 | * early binding of array handler bypasses type resolution ([ada4bc27](https://github.com/angular-ui/ui-router/commit/ada4bc27df5eff3ba3ab0de94a09bd91b0f7a28c)) 14 | * add 'any' Type for non-encoding non-url params ([3bfd75ab](https://github.com/angular-ui/ui-router/commit/3bfd75ab445ee2f1dd55275465059ed116b10b27), closes [#1562](https://github.com/angular-ui/ui-router/issues/1562)) 15 | * fix encoding slashes in params ([0c983a08](https://github.com/angular-ui/ui-router/commit/0c983a08e2947f999683571477debd73038e95cf), closes [#1119](https://github.com/angular-ui/ui-router/issues/1119)) 16 | * fix mixed path/query params ordering problem ([a479fbd0](https://github.com/angular-ui/ui-router/commit/a479fbd0b8eb393a94320973e5b9a62d83912ee2), closes [#1543](https://github.com/angular-ui/ui-router/issues/1543)) 17 | * **ArrayType:** 18 | * specify empty array mapping corner case ([74aa6091](https://github.com/angular-ui/ui-router/commit/74aa60917e996b0b4e27bbb4eb88c3c03832021d), closes [#1511](https://github.com/angular-ui/ui-router/issues/1511)) 19 | * fix .equals for array types ([5e6783b7](https://github.com/angular-ui/ui-router/commit/5e6783b77af9a90ddff154f990b43dbb17eeda6e), closes [#1538](https://github.com/angular-ui/ui-router/issues/1538)) 20 | * **Param:** fix default value shorthand declaration ([831d812a](https://github.com/angular-ui/ui-router/commit/831d812a524524c71f0ee1c9afaf0487a5a66230), closes [#1554](https://github.com/angular-ui/ui-router/issues/1554)) 21 | * **common:** fixed the _.filter clone to not create sparse arrays ([750f5cf5](https://github.com/angular-ui/ui-router/commit/750f5cf5fd91f9ada96f39e50d39aceb2caf22b6), closes [#1563](https://github.com/angular-ui/ui-router/issues/1563)) 22 | * **ie8:** fix calls to indexOf and filter ([dcb31b84](https://github.com/angular-ui/ui-router/commit/dcb31b843391b3e61dee4de13f368c109541813e), closes [#1556](https://github.com/angular-ui/ui-router/issues/1556)) 23 | 24 | 25 | #### Features 26 | 27 | * add json parameter Type ([027f1fcf](https://github.com/angular-ui/ui-router/commit/027f1fcf9c0916cea651e88981345da6f9ff214a)) 28 | 29 | 30 | 31 | ### 0.2.12 (2014-11-13) 32 | 33 | #### Bug Fixes 34 | 35 | * **$resolve:** use resolve fn result, not parent resolved value of same name ([67f5e00c](https://github.com/angular-ui/ui-router/commit/67f5e00cc9aa006ce3fe6cde9dff261c28eab70a), closes [#1317], [#1353]) 36 | * **$state:** 37 | * populate default params in .transitionTo. ([3f60fbe6](https://github.com/angular-ui/ui-router/commit/3f60fbe6d65ebeca8d97952c05aa1d269f1b7ba1), closes [#1396]) 38 | * reload() now reinvokes controllers ([73443420](https://github.com/angular-ui/ui-router/commit/7344342018847902594dc1fc62d30a5c30f01763), closes [#582]) 39 | * do not emit $viewContentLoading if notify: false ([74255feb](https://github.com/angular-ui/ui-router/commit/74255febdf48ae082a02ca1e735165f2c369a463), closes [#1387](https://github.com/angular-ui/ui-router/issues/1387)) 40 | * register states at config-time ([4533fe36](https://github.com/angular-ui/ui-router/commit/4533fe36e0ab2f0143edd854a4145deaa013915a)) 41 | * handle parent.name when parent is obj ([4533fe36](https://github.com/angular-ui/ui-router/commit/4533fe36e0ab2f0143edd854a4145deaa013915a)) 42 | * **$urlMatcherFactory:** 43 | * register types at config ([4533fe36](https://github.com/angular-ui/ui-router/commit/4533fe36e0ab2f0143edd854a4145deaa013915a), closes [#1476]) 44 | * made path params default value "" for backwards compat ([8f998e71](https://github.com/angular-ui/ui-router/commit/8f998e71e43a0b31293331c981f5db0f0097b8ba)) 45 | * Pre-replace certain param values for better mapping ([6374a3e2](https://github.com/angular-ui/ui-router/commit/6374a3e29ab932014a7c77d2e1ab884cc841a2e3)) 46 | * fixed ParamSet.$$keys() ordering ([9136fecb](https://github.com/angular-ui/ui-router/commit/9136fecbc2bfd4fda748a9914f0225a46c933860)) 47 | * empty string policy now respected in Param.value() ([db12c85c](https://github.com/angular-ui/ui-router/commit/db12c85c16f2d105415f9bbbdeb11863f64728e0)) 48 | * "string" type now encodes/decodes slashes ([3045e415](https://github.com/angular-ui/ui-router/commit/3045e41577a8b8b8afc6039f42adddf5f3c061ec), closes [#1119]) 49 | * allow arrays in both path and query params ([fdd2f2c1](https://github.com/angular-ui/ui-router/commit/fdd2f2c191c4a67c874fdb9ec9a34f8dde9ad180), closes [#1073], [#1045], [#1486], [#1394]) 50 | * typed params in search ([8d4cab69](https://github.com/angular-ui/ui-router/commit/8d4cab69dd67058e1a716892cc37b7d80a57037f), closes [#1488](https://github.com/angular-ui/ui-router/issues/1488)) 51 | * no longer generate unroutable urls ([cb9fd9d8](https://github.com/angular-ui/ui-router/commit/cb9fd9d8943cb26c7223f6990db29c82ae8740f8), closes [#1487](https://github.com/angular-ui/ui-router/issues/1487)) 52 | * handle optional parameter followed by required parameter in url format. ([efc72106](https://github.com/angular-ui/ui-router/commit/efc72106ddcc4774b48ea176a505ef9e95193b41)) 53 | * default to parameter string coersion. ([13a468a7](https://github.com/angular-ui/ui-router/commit/13a468a7d54c2fb0751b94c0c1841d580b71e6dc), closes [#1414](https://github.com/angular-ui/ui-router/issues/1414)) 54 | * concat respects strictMode/caseInsensitive ([dd72e103](https://github.com/angular-ui/ui-router/commit/dd72e103edb342d9cf802816fe127e1bbd68fd5f), closes [#1395]) 55 | * **ui-sref:** 56 | * Allow sref state options to take a scope object ([b5f7b596](https://github.com/angular-ui/ui-router/commit/b5f7b59692ce4933e2d63eb5df3f50a4ba68ccc0)) 57 | * replace raw href modification with attrs. ([08c96782](https://github.com/angular-ui/ui-router/commit/08c96782faf881b0c7ab00afc233ee6729548fa0)) 58 | * nagivate to state when url is "" fix($state.href): generate href for state with ([656b5aab](https://github.com/angular-ui/ui-router/commit/656b5aab906e5749db9b5a080c6a83b95f50fd91), closes [#1363](https://github.com/angular-ui/ui-router/issues/1363)) 59 | * Check that state is defined in isMatch() ([92aebc75](https://github.com/angular-ui/ui-router/commit/92aebc7520f88babdc6e266536086e07263514c3), closes [#1314](https://github.com/angular-ui/ui-router/issues/1314), [#1332](https://github.com/angular-ui/ui-router/issues/1332)) 60 | * **uiView:** 61 | * allow inteprolated ui-view names ([81f6a19a](https://github.com/angular-ui/ui-router/commit/81f6a19a432dac9198fd33243855bfd3b4fea8c0), closes [#1324](https://github.com/angular-ui/ui-router/issues/1324)) 62 | * Made anim work with angular 1.3 ([c3bb7ad9](https://github.com/angular-ui/ui-router/commit/c3bb7ad903da1e1f3c91019cfd255be8489ff4ef), closes [#1367](https://github.com/angular-ui/ui-router/issues/1367), [#1345](https://github.com/angular-ui/ui-router/issues/1345)) 63 | * **urlRouter:** html5Mode accepts an object from angular v1.3.0-rc.3 ([7fea1e9d](https://github.com/angular-ui/ui-router/commit/7fea1e9d0d8c6e09cc6c895ecb93d4221e9adf48)) 64 | * **stateFilters:** mark state filters as stateful. ([a00b353e](https://github.com/angular-ui/ui-router/commit/a00b353e3036f64a81245c4e7898646ba218f833), closes [#1479]) 65 | * **ui-router:** re-add IE8 compatibility for map/filter/keys ([8ce69d9f](https://github.com/angular-ui/ui-router/commit/8ce69d9f7c886888ab53eca7e53536f36b428aae), closes [#1518], [#1383]) 66 | * **package:** point 'main' to a valid filename ([ac903350](https://github.com/angular-ui/ui-router/commit/ac9033501debb63364539d91fbf3a0cba4579f8e)) 67 | * **travis:** make CI build faster ([0531de05](https://github.com/angular-ui/ui-router/commit/0531de052e414a8d839fbb4e7635e923e94865b3)) 68 | 69 | 70 | #### Features 71 | 72 | ##### Default and Typed params 73 | 74 | This release includes a lot of bug fixes around default/optional and typed parameters. As such, 0.2.12 is the first release where we recommend those features be used. 75 | 76 | * **$state:** 77 | * add state params validation ([b1379e6a](https://github.com/angular-ui/ui-router/commit/b1379e6a4d38f7ed7436e05873932d7c279af578), closes [#1433](https://github.com/angular-ui/ui-router/issues/1433)) 78 | * is/includes/get work on relative stateOrName ([232e94b3](https://github.com/angular-ui/ui-router/commit/232e94b3c2ca2c764bb9510046e4b61690c87852)) 79 | * .reload() returns state transition promise ([639e0565](https://github.com/angular-ui/ui-router/commit/639e0565dece9d5544cc93b3eee6e11c99bd7373)) 80 | * **$templateFactory:** request templateURL as text/html ([ccd60769](https://github.com/angular-ui/ui-router/commit/ccd6076904a4b801d77b47f6e2de4c06ce9962f8), closes [#1287]) 81 | * **$urlMatcherFactory:** Made a Params and ParamSet class ([0cc1e6cc](https://github.com/angular-ui/ui-router/commit/0cc1e6cc461a4640618e2bb594566551c54834e2)) 82 | 83 | 84 | 85 | 86 | ### 0.2.11 (2014-08-26) 87 | 88 | 89 | #### Bug Fixes 90 | 91 | * **$resolve:** Resolves only inherit from immediate parent fixes #702 ([df34e20c](https://github.com/angular-ui/ui-router/commit/df34e20c576299e7a3c8bd4ebc68d42341c0ace9)) 92 | * **$state:** 93 | * change $state.href default options.inherit to true ([deea695f](https://github.com/angular-ui/ui-router/commit/deea695f5cacc55de351ab985144fd233c02a769)) 94 | * sanity-check state lookups ([456fd5ae](https://github.com/angular-ui/ui-router/commit/456fd5aec9ea507518927bfabd62b4afad4cf714), closes [#980](https://github.com/angular-ui/ui-router/issues/980)) 95 | * didn't comply to inherit parameter ([09836781](https://github.com/angular-ui/ui-router/commit/09836781f126c1c485b06551eb9cfd4fa0f45c35)) 96 | * allow view content loading broadcast ([7b78edee](https://github.com/angular-ui/ui-router/commit/7b78edeeb52a74abf4d3f00f79534033d5a08d1a)) 97 | * **$urlMatcherFactory:** 98 | * detect injected functions ([91f75ae6](https://github.com/angular-ui/ui-router/commit/91f75ae66c4d129f6f69e53bd547594e9661f5d5)) 99 | * syntax ([1ebed370](https://github.com/angular-ui/ui-router/commit/1ebed37069bae8614d41541d56521f5c45f703f3)) 100 | * **UrlMatcher:** 101 | * query param function defaults ([f9c20530](https://github.com/angular-ui/ui-router/commit/f9c205304f10d8a4ebe7efe9025e642016479a51)) 102 | * don't decode default values ([63607bdb](https://github.com/angular-ui/ui-router/commit/63607bdbbcb432d3fb37856a1cb3da0cd496804e)) 103 | * **travis:** update Node version to fix build ([d6b95ef2](https://github.com/angular-ui/ui-router/commit/d6b95ef23d9dacb4eba08897f5190a0bcddb3a48)) 104 | * **uiSref:** 105 | * Generate an href for states with a blank url. closes #1293 ([691745b1](https://github.com/angular-ui/ui-router/commit/691745b12fa05d3700dd28f0c8d25f8a105074ad)) 106 | * should inherit params by default ([b973dad1](https://github.com/angular-ui/ui-router/commit/b973dad155ad09a7975e1476bd096f7b2c758eeb)) 107 | * cancel transition if preventDefault() has been called ([2e6d9167](https://github.com/angular-ui/ui-router/commit/2e6d9167d3afbfbca6427e53e012f94fb5fb8022)) 108 | * **uiView:** Fixed infinite loop when is called .go() from a controller. ([e13988b8](https://github.com/angular-ui/ui-router/commit/e13988b8cd6231d75c78876ee9d012cc87f4a8d9), closes [#1194](https://github.com/angular-ui/ui-router/issues/1194)) 109 | * **docs:** 110 | * Fixed link to milestones ([6c0ae500](https://github.com/angular-ui/ui-router/commit/6c0ae500cc238ea9fc95adcc15415c55fc9e1f33)) 111 | * fix bug in decorator example ([4bd00af5](https://github.com/angular-ui/ui-router/commit/4bd00af50b8b88a49d1545a76290731cb8e0feb1)) 112 | * Removed an incorrect semi-colon ([af97cef8](https://github.com/angular-ui/ui-router/commit/af97cef8b967f2e32177e539ef41450dca131a7d)) 113 | * Explain return value of rule as function ([5e887890](https://github.com/angular-ui/ui-router/commit/5e8878900a6ffe59a81aed531a3925e34a297377)) 114 | 115 | 116 | #### Features 117 | 118 | * **$state:** 119 | * allow parameters to pass unharmed ([8939d057](https://github.com/angular-ui/ui-router/commit/8939d0572ab1316e458ef016317ecff53131a822)) 120 | * **BREAKING CHANGE**: state parameters are no longer automatically coerced to strings, and unspecified parameter values are now set to undefined rather than null. 121 | * allow prevent syncUrl on failure ([753060b9](https://github.com/angular-ui/ui-router/commit/753060b910d5d2da600a6fa0757976e401c33172)) 122 | * **typescript:** Add typescript definitions for component builds ([521ceb3f](https://github.com/angular-ui/ui-router/commit/521ceb3fd7850646422f411921e21ce5e7d82e0f)) 123 | * **uiSref:** extend syntax for ui-sref ([71cad3d6](https://github.com/angular-ui/ui-router/commit/71cad3d636508b5a9fe004775ad1f1adc0c80c3e)) 124 | * **uiSrefActive:** 125 | * Also activate for child states. ([bf163ad6](https://github.com/angular-ui/ui-router/commit/bf163ad6ce176ce28792696c8302d7cdf5c05a01), closes [#818](https://github.com/angular-ui/ui-router/issues/818)) 126 | * **BREAKING CHANGE** Since ui-sref-active now activates even when child states are active you may need to swap out your ui-sref-active with ui-sref-active-eq, thought typically we think devs want the auto inheritance. 127 | 128 | * uiSrefActiveEq: new directive with old ui-sref-active behavior 129 | * **$urlRouter:** 130 | * defer URL change interception ([c72d8ce1](https://github.com/angular-ui/ui-router/commit/c72d8ce11916d0ac22c81b409c9e61d7048554d7)) 131 | * force URLs to have valid params ([d48505cd](https://github.com/angular-ui/ui-router/commit/d48505cd328d83e39d5706e085ba319715f999a6)) 132 | * abstract $location handling ([08b4636b](https://github.com/angular-ui/ui-router/commit/08b4636b294611f08db35f00641eb5211686fb50)) 133 | * **$urlMatcherFactory:** 134 | * fail on bad parameters ([d8f124c1](https://github.com/angular-ui/ui-router/commit/d8f124c10d00c7e5dde88c602d966db261aea221)) 135 | * date type support ([b7f074ff](https://github.com/angular-ui/ui-router/commit/b7f074ff65ca150a3cdbda4d5ad6cb17107300eb)) 136 | * implement type support ([450b1f0e](https://github.com/angular-ui/ui-router/commit/450b1f0e8e03c738174ff967f688b9a6373290f4)) 137 | * **UrlMatcher:** 138 | * handle query string arrays ([9cf764ef](https://github.com/angular-ui/ui-router/commit/9cf764efab45fa9309368688d535ddf6e96d6449), closes [#373](https://github.com/angular-ui/ui-router/issues/373)) 139 | * injectable functions as defaults ([00966ecd](https://github.com/angular-ui/ui-router/commit/00966ecd91fb745846039160cab707bfca8b3bec)) 140 | * default values & type decoding for query params ([a472b301](https://github.com/angular-ui/ui-router/commit/a472b301389fbe84d1c1fa9f24852b492a569d11)) 141 | * allow shorthand definitions ([5b724304](https://github.com/angular-ui/ui-router/commit/5b7243049793505e44b6608ea09878c37c95b1f5)) 142 | * validates whole interface ([32b27db1](https://github.com/angular-ui/ui-router/commit/32b27db173722e9194ef1d5c0ea7d93f25a98d11)) 143 | * implement non-strict matching ([a3e21366](https://github.com/angular-ui/ui-router/commit/a3e21366bee0475c9795a1ec76f70eec41c5b4e3)) 144 | * add per-param config support ([07b3029f](https://github.com/angular-ui/ui-router/commit/07b3029f4d409cf955780113df92e36401b47580)) 145 | * **BREAKING CHANGE**: the `params` option in state configurations must now be an object keyed by parameter name. 146 | 147 | ### 0.2.10 (2014-03-12) 148 | 149 | 150 | #### Bug Fixes 151 | 152 | * **$state:** use $browser.baseHref() when generating urls with .href() ([cbcc8488](https://github.com/angular-ui/ui-router/commit/cbcc84887d6b6d35258adabb97c714cd9c1e272d)) 153 | * **bower.json:** JS files should not be ignored ([ccdab193](https://github.com/angular-ui/ui-router/commit/ccdab193315f304eb3be5f5b97c47a926c79263e)) 154 | * **dev:** karma:background task is missing, can't run grunt:dev. ([d9f7b898](https://github.com/angular-ui/ui-router/commit/d9f7b898e8e3abb8c846b0faa16a382913d7b22b)) 155 | * **sample:** Contacts menu button not staying active when navigating to detail states. Need t ([2fcb8443](https://github.com/angular-ui/ui-router/commit/2fcb84437cb43ade12682a92b764f13cac77dfe7)) 156 | * **uiSref:** support mock-clicks/events with no data ([717d3ff7](https://github.com/angular-ui/ui-router/commit/717d3ff7d0ba72d239892dee562b401cdf90e418)) 157 | * **uiView:** 158 | * Do NOT autoscroll when autoscroll attr is missing ([affe5bd7](https://github.com/angular-ui/ui-router/commit/affe5bd785cdc3f02b7a9f64a52e3900386ec3a0), closes [#807](https://github.com/angular-ui/ui-router/issues/807)) 159 | * Refactoring uiView directive to copy ngView logic ([548fab6a](https://github.com/angular-ui/ui-router/commit/548fab6ab9debc9904c5865c8bc68b4fc3271dd0), closes [#857](https://github.com/angular-ui/ui-router/issues/857), [#552](https://github.com/angular-ui/ui-router/issues/552)) 160 | 161 | 162 | #### Features 163 | 164 | * **$state:** includes() allows glob patterns for state matching. ([2d5f6b37](https://github.com/angular-ui/ui-router/commit/2d5f6b37191a3135f4a6d9e8f344c54edcdc065b)) 165 | * **UrlMatcher:** Add support for case insensitive url matching ([642d5247](https://github.com/angular-ui/ui-router/commit/642d524799f604811e680331002feec7199a1fb5)) 166 | * **uiSref:** add support for transition options ([2ed7a728](https://github.com/angular-ui/ui-router/commit/2ed7a728cee6854b38501fbc1df6139d3de5b28a)) 167 | * **uiView:** add controllerAs config with function ([1ee7334a](https://github.com/angular-ui/ui-router/commit/1ee7334a73efeccc9b95340e315cdfd59944762d)) 168 | 169 | 170 | ### 0.2.9 (2014-01-17) 171 | 172 | 173 | This release is identical to 0.2.8. 0.2.8 was re-tagged in git to fix a problem with bower. 174 | 175 | 176 | ### 0.2.8 (2014-01-16) 177 | 178 | 179 | #### Bug Fixes 180 | 181 | * **$state:** allow null to be passed as 'params' param ([094dc30e](https://github.com/angular-ui/ui-router/commit/094dc30e883e1bd14e50a475553bafeaade3b178)) 182 | * **$state.go:** param inheritance shouldn't inherit from siblings ([aea872e0](https://github.com/angular-ui/ui-router/commit/aea872e0b983cb433436ce5875df10c838fccedb)) 183 | * **bower.json:** fixes bower.json ([eed3cc4d](https://github.com/angular-ui/ui-router/commit/eed3cc4d4dfef1d3ef84b9fd063127538ebf59d3)) 184 | * **uiSrefActive:** annotate controller injection ([85921422](https://github.com/angular-ui/ui-router/commit/85921422ff7fb0effed358136426d616cce3d583), closes [#671](https://github.com/angular-ui/ui-router/issues/671)) 185 | * **uiView:** 186 | * autoscroll tests pass on 1.2.4 & 1.1.5 ([86eacac0](https://github.com/angular-ui/ui-router/commit/86eacac09ca5e9000bd3b9c7ba6e2cc95d883a3a)) 187 | * don't animate initial load ([83b6634d](https://github.com/angular-ui/ui-router/commit/83b6634d27942ca74766b2b1244a7fc52c5643d9)) 188 | * test pass against 1.0.8 and 1.2.4 ([a402415a](https://github.com/angular-ui/ui-router/commit/a402415a2a28b360c43b9fe8f4f54c540f6c33de)) 189 | * it should autoscroll when expr is missing. ([8bb9e27a](https://github.com/angular-ui/ui-router/commit/8bb9e27a2986725f45daf44c4c9f846385095aff)) 190 | 191 | 192 | #### Features 193 | 194 | * **uiSref:** add target attribute behaviour ([c12bf9a5](https://github.com/angular-ui/ui-router/commit/c12bf9a520d30d70294e3d82de7661900f8e394e)) 195 | * **uiView:** 196 | * merge autoscroll expression test. ([b89e0f87](https://github.com/angular-ui/ui-router/commit/b89e0f871d5cc35c10925ede986c10684d5c9252)) 197 | * cache and test autoscroll expression ([ee262282](https://github.com/angular-ui/ui-router/commit/ee2622828c2ce83807f006a459ac4e11406d9258)) 198 | -------------------------------------------------------------------------------- /bower_components/ui-router/release/angular-ui-router.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * State-based routing for AngularJS 3 | * @version v0.2.13 4 | * @link http://angular-ui.github.com/ 5 | * @license MIT License, http://www.opensource.org/licenses/MIT 6 | */ 7 | "undefined"!=typeof module&&"undefined"!=typeof exports&&module.exports===exports&&(module.exports="ui.router"),function(a,b,c){"use strict";function d(a,b){return M(new(M(function(){},{prototype:a})),b)}function e(a){return L(arguments,function(b){b!==a&&L(b,function(b,c){a.hasOwnProperty(c)||(a[c]=b)})}),a}function f(a,b){var c=[];for(var d in a.path){if(a.path[d]!==b.path[d])break;c.push(a.path[d])}return c}function g(a){if(Object.keys)return Object.keys(a);var c=[];return b.forEach(a,function(a,b){c.push(b)}),c}function h(a,b){if(Array.prototype.indexOf)return a.indexOf(b,Number(arguments[2])||0);var c=a.length>>>0,d=Number(arguments[2])||0;for(d=0>d?Math.ceil(d):Math.floor(d),0>d&&(d+=c);c>d;d++)if(d in a&&a[d]===b)return d;return-1}function i(a,b,c,d){var e,i=f(c,d),j={},k=[];for(var l in i)if(i[l].params&&(e=g(i[l].params),e.length))for(var m in e)h(k,e[m])>=0||(k.push(e[m]),j[e[m]]=a[e[m]]);return M({},j,b)}function j(a,b,c){if(!c){c=[];for(var d in a)c.push(d)}for(var e=0;e "));if(s[c]=d,I(a))q.push(c,[function(){return b.get(a)}],j);else{var e=b.annotate(a);L(e,function(a){a!==c&&i.hasOwnProperty(a)&&n(i[a],a)}),q.push(c,a,e)}r.pop(),s[c]=f}}function o(a){return J(a)&&a.then&&a.$$promises}if(!J(i))throw new Error("'invocables' must be an object");var p=g(i||{}),q=[],r=[],s={};return L(i,n),i=r=s=null,function(d,f,g){function h(){--u||(v||e(t,f.$$values),r.$$values=t,r.$$promises=r.$$promises||!0,delete r.$$inheritedValues,n.resolve(t))}function i(a){r.$$failure=a,n.reject(a)}function j(c,e,f){function j(a){l.reject(a),i(a)}function k(){if(!G(r.$$failure))try{l.resolve(b.invoke(e,g,t)),l.promise.then(function(a){t[c]=a,h()},j)}catch(a){j(a)}}var l=a.defer(),m=0;L(f,function(a){s.hasOwnProperty(a)&&!d.hasOwnProperty(a)&&(m++,s[a].then(function(b){t[a]=b,--m||k()},j))}),m||k(),s[c]=l.promise}if(o(d)&&g===c&&(g=f,f=d,d=null),d){if(!J(d))throw new Error("'locals' must be an object")}else d=k;if(f){if(!o(f))throw new Error("'parent' must be a promise returned by $resolve.resolve()")}else f=m;var n=a.defer(),r=n.promise,s=r.$$promises={},t=M({},d),u=1+q.length/3,v=!1;if(G(f.$$failure))return i(f.$$failure),r;f.$$inheritedValues&&e(t,l(f.$$inheritedValues,p)),M(s,f.$$promises),f.$$values?(v=e(t,l(f.$$values,p)),r.$$inheritedValues=l(f.$$values,p),h()):(f.$$inheritedValues&&(r.$$inheritedValues=l(f.$$inheritedValues,p)),f.then(h,i));for(var w=0,x=q.length;x>w;w+=3)d.hasOwnProperty(q[w])?h():j(q[w],q[w+1],q[w+2]);return r}},this.resolve=function(a,b,c,d){return this.study(a)(b,c,d)}}function p(a,b,c){this.fromConfig=function(a,b,c){return G(a.template)?this.fromString(a.template,b):G(a.templateUrl)?this.fromUrl(a.templateUrl,b):G(a.templateProvider)?this.fromProvider(a.templateProvider,b,c):null},this.fromString=function(a,b){return H(a)?a(b):a},this.fromUrl=function(c,d){return H(c)&&(c=c(d)),null==c?null:a.get(c,{cache:b,headers:{Accept:"text/html"}}).then(function(a){return a.data})},this.fromProvider=function(a,b,d){return c.invoke(a,null,d||{params:b})}}function q(a,b,e){function f(b,c,d,e){if(q.push(b),o[b])return o[b];if(!/^\w+(-+\w+)*(?:\[\])?$/.test(b))throw new Error("Invalid parameter name '"+b+"' in pattern '"+a+"'");if(p[b])throw new Error("Duplicate parameter name '"+b+"' in pattern '"+a+"'");return p[b]=new O.Param(b,c,d,e),p[b]}function g(a,b,c){var d=["",""],e=a.replace(/[\\\[\]\^$*+?.()|{}]/g,"\\$&");if(!b)return e;switch(c){case!1:d=["(",")"];break;case!0:d=["?(",")?"];break;default:d=["("+c+"|",")?"]}return e+d[0]+b+d[1]}function h(c,e){var f,g,h,i,j;return f=c[2]||c[3],j=b.params[f],h=a.substring(m,c.index),g=e?c[4]:c[4]||("*"==c[1]?".*":null),i=O.type(g||"string")||d(O.type("string"),{pattern:new RegExp(g)}),{id:f,regexp:g,segment:h,type:i,cfg:j}}b=M({params:{}},J(b)?b:{});var i,j=/([:*])([\w\[\]]+)|\{([\w\[\]]+)(?:\:((?:[^{}\\]+|\\.|\{(?:[^{}\\]+|\\.)*\})+))?\}/g,k=/([:]?)([\w\[\]-]+)|\{([\w\[\]-]+)(?:\:((?:[^{}\\]+|\\.|\{(?:[^{}\\]+|\\.)*\})+))?\}/g,l="^",m=0,n=this.segments=[],o=e?e.params:{},p=this.params=e?e.params.$$new():new O.ParamSet,q=[];this.source=a;for(var r,s,t;(i=j.exec(a))&&(r=h(i,!1),!(r.segment.indexOf("?")>=0));)s=f(r.id,r.type,r.cfg,"path"),l+=g(r.segment,s.type.pattern.source,s.squash),n.push(r.segment),m=j.lastIndex;t=a.substring(m);var u=t.indexOf("?");if(u>=0){var v=this.sourceSearch=t.substring(u);if(t=t.substring(0,u),this.sourcePath=a.substring(0,m+u),v.length>0)for(m=0;i=k.exec(v);)r=h(i,!0),s=f(r.id,r.type,r.cfg,"search"),m=j.lastIndex}else this.sourcePath=a,this.sourceSearch="";l+=g(t)+(b.strict===!1?"/?":"")+"$",n.push(t),this.regexp=new RegExp(l,b.caseInsensitive?"i":c),this.prefix=n[0],this.$$paramNames=q}function r(a){M(this,a)}function s(){function a(a){return null!=a?a.toString().replace(/\//g,"%2F"):a}function e(a){return null!=a?a.toString().replace(/%2F/g,"/"):a}function f(a){return this.pattern.test(a)}function i(){return{strict:t,caseInsensitive:p}}function j(a){return H(a)||K(a)&&H(a[a.length-1])}function k(){for(;x.length;){var a=x.shift();if(a.pattern)throw new Error("You cannot override a type's .pattern at runtime.");b.extend(v[a.name],o.invoke(a.def))}}function l(a){M(this,a||{})}O=this;var o,p=!1,t=!0,u=!1,v={},w=!0,x=[],y={string:{encode:a,decode:e,is:f,pattern:/[^/]*/},"int":{encode:a,decode:function(a){return parseInt(a,10)},is:function(a){return G(a)&&this.decode(a.toString())===a},pattern:/\d+/},bool:{encode:function(a){return a?1:0},decode:function(a){return 0!==parseInt(a,10)},is:function(a){return a===!0||a===!1},pattern:/0|1/},date:{encode:function(a){return this.is(a)?[a.getFullYear(),("0"+(a.getMonth()+1)).slice(-2),("0"+a.getDate()).slice(-2)].join("-"):c},decode:function(a){if(this.is(a))return a;var b=this.capture.exec(a);return b?new Date(b[1],b[2]-1,b[3]):c},is:function(a){return a instanceof Date&&!isNaN(a.valueOf())},equals:function(a,b){return this.is(a)&&this.is(b)&&a.toISOString()===b.toISOString()},pattern:/[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[1-2][0-9]|3[0-1])/,capture:/([0-9]{4})-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])/},json:{encode:b.toJson,decode:b.fromJson,is:b.isObject,equals:b.equals,pattern:/[^/]*/},any:{encode:b.identity,decode:b.identity,is:b.identity,equals:b.equals,pattern:/.*/}};s.$$getDefaultValue=function(a){if(!j(a.value))return a.value;if(!o)throw new Error("Injectable functions cannot be called at configuration time");return o.invoke(a.value)},this.caseInsensitive=function(a){return G(a)&&(p=a),p},this.strictMode=function(a){return G(a)&&(t=a),t},this.defaultSquashPolicy=function(a){if(!G(a))return u;if(a!==!0&&a!==!1&&!I(a))throw new Error("Invalid squash policy: "+a+". Valid policies: false, true, arbitrary-string");return u=a,a},this.compile=function(a,b){return new q(a,M(i(),b))},this.isMatcher=function(a){if(!J(a))return!1;var b=!0;return L(q.prototype,function(c,d){H(c)&&(b=b&&G(a[d])&&H(a[d]))}),b},this.type=function(a,b,c){if(!G(b))return v[a];if(v.hasOwnProperty(a))throw new Error("A type named '"+a+"' has already been defined.");return v[a]=new r(M({name:a},b)),c&&(x.push({name:a,def:c}),w||k()),this},L(y,function(a,b){v[b]=new r(M({name:b},a))}),v=d(v,{}),this.$get=["$injector",function(a){return o=a,w=!1,k(),L(y,function(a,b){v[b]||(v[b]=new r(a))}),this}],this.Param=function(a,b,d,e){function f(a){var b=J(a)?g(a):[],c=-1===h(b,"value")&&-1===h(b,"type")&&-1===h(b,"squash")&&-1===h(b,"array");return c&&(a={value:a}),a.$$fn=j(a.value)?a.value:function(){return a.value},a}function i(b,c,d){if(b.type&&c)throw new Error("Param '"+a+"' has two type configurations.");return c?c:b.type?b.type instanceof r?b.type:new r(b.type):"config"===d?v.any:v.string}function k(){var b={array:"search"===e?"auto":!1},c=a.match(/\[\]$/)?{array:!0}:{};return M(b,c,d).array}function l(a,b){var c=a.squash;if(!b||c===!1)return!1;if(!G(c)||null==c)return u;if(c===!0||I(c))return c;throw new Error("Invalid squash policy: '"+c+"'. Valid policies: false, true, or arbitrary string")}function p(a,b,d,e){var f,g,i=[{from:"",to:d||b?c:""},{from:null,to:d||b?c:""}];return f=K(a.replace)?a.replace:[],I(e)&&f.push({from:e,to:c}),g=n(f,function(a){return a.from}),m(i,function(a){return-1===h(g,a.from)}).concat(f)}function q(){if(!o)throw new Error("Injectable functions cannot be called at configuration time");return o.invoke(d.$$fn)}function s(a){function b(a){return function(b){return b.from===a}}function c(a){var c=n(m(w.replace,b(a)),function(a){return a.to});return c.length?c[0]:a}return a=c(a),G(a)?w.type.decode(a):q()}function t(){return"{Param:"+a+" "+b+" squash: '"+z+"' optional: "+y+"}"}var w=this;d=f(d),b=i(d,b,e);var x=k();b=x?b.$asArray(x,"search"===e):b,"string"!==b.name||x||"path"!==e||d.value!==c||(d.value="");var y=d.value!==c,z=l(d,y),A=p(d,x,y,z);M(this,{id:a,type:b,location:e,array:x,squash:z,replace:A,isOptional:y,value:s,dynamic:c,config:d,toString:t})},l.prototype={$$new:function(){return d(this,M(new l,{$$parent:this}))},$$keys:function(){for(var a=[],b=[],c=this,d=g(l.prototype);c;)b.push(c),c=c.$$parent;return b.reverse(),L(b,function(b){L(g(b),function(b){-1===h(a,b)&&-1===h(d,b)&&a.push(b)})}),a},$$values:function(a){var b={},c=this;return L(c.$$keys(),function(d){b[d]=c[d].value(a&&a[d])}),b},$$equals:function(a,b){var c=!0,d=this;return L(d.$$keys(),function(e){var f=a&&a[e],g=b&&b[e];d[e].type.equals(f,g)||(c=!1)}),c},$$validates:function(a){var b,c,d,e=!0,f=this;return L(this.$$keys(),function(g){d=f[g],c=a[g],b=!c&&d.isOptional,e=e&&(b||!!d.type.is(c))}),e},$$parent:c},this.ParamSet=l}function t(a,d){function e(a){var b=/^\^((?:\\[^a-zA-Z0-9]|[^\\\[\]\^$*+?.()|{}]+)*)/.exec(a.source);return null!=b?b[1].replace(/\\(.)/g,"$1"):""}function f(a,b){return a.replace(/\$(\$|\d{1,2})/,function(a,c){return b["$"===c?0:Number(c)]})}function g(a,b,c){if(!c)return!1;var d=a.invoke(b,b,{$match:c});return G(d)?d:!0}function h(d,e,f,g){function h(a,b,c){return"/"===p?a:b?p.slice(0,-1)+a:c?p.slice(1)+a:a}function m(a){function b(a){var b=a(f,d);return b?(I(b)&&d.replace().url(b),!0):!1}if(!a||!a.defaultPrevented){var e=o&&d.url()===o;if(o=c,e)return!0;var g,h=j.length;for(g=0;h>g;g++)if(b(j[g]))return;k&&b(k)}}function n(){return i=i||e.$on("$locationChangeSuccess",m)}var o,p=g.baseHref(),q=d.url();return l||n(),{sync:function(){m()},listen:function(){return n()},update:function(a){return a?void(q=d.url()):void(d.url()!==q&&(d.url(q),d.replace()))},push:function(a,b,e){d.url(a.format(b||{})),o=e&&e.$$avoidResync?d.url():c,e&&e.replace&&d.replace()},href:function(c,e,f){if(!c.validates(e))return null;var g=a.html5Mode();b.isObject(g)&&(g=g.enabled);var i=c.format(e);if(f=f||{},g||null===i||(i="#"+a.hashPrefix()+i),i=h(i,g,f.absolute),!f.absolute||!i)return i;var j=!g&&i?"/":"",k=d.port();return k=80===k||443===k?"":":"+k,[d.protocol(),"://",d.host(),k,j,i].join("")}}}var i,j=[],k=null,l=!1;this.rule=function(a){if(!H(a))throw new Error("'rule' must be a function");return j.push(a),this},this.otherwise=function(a){if(I(a)){var b=a;a=function(){return b}}else if(!H(a))throw new Error("'rule' must be a function");return k=a,this},this.when=function(a,b){var c,h=I(b);if(I(a)&&(a=d.compile(a)),!h&&!H(b)&&!K(b))throw new Error("invalid 'handler' in when()");var i={matcher:function(a,b){return h&&(c=d.compile(b),b=["$match",function(a){return c.format(a)}]),M(function(c,d){return g(c,b,a.exec(d.path(),d.search()))},{prefix:I(a.prefix)?a.prefix:""})},regex:function(a,b){if(a.global||a.sticky)throw new Error("when() RegExp must not be global or sticky");return h&&(c=b,b=["$match",function(a){return f(c,a)}]),M(function(c,d){return g(c,b,a.exec(d.path()))},{prefix:e(a)})}},j={matcher:d.isMatcher(a),regex:a instanceof RegExp};for(var k in j)if(j[k])return this.rule(i[k](a,b));throw new Error("invalid 'what' in when()")},this.deferIntercept=function(a){a===c&&(a=!0),l=a},this.$get=h,h.$inject=["$location","$rootScope","$injector","$browser"]}function u(a,e){function f(a){return 0===a.indexOf(".")||0===a.indexOf("^")}function l(a,b){if(!a)return c;var d=I(a),e=d?a:a.name,g=f(e);if(g){if(!b)throw new Error("No reference point given for path '"+e+"'");b=l(b);for(var h=e.split("."),i=0,j=h.length,k=b;j>i;i++)if(""!==h[i]||0!==i){if("^"!==h[i])break;if(!k.parent)throw new Error("Path '"+e+"' not valid for state '"+b.name+"'");k=k.parent}else k=b;h=h.slice(i).join("."),e=k.name+(k.name&&h?".":"")+h}var m=y[e];return!m||!d&&(d||m!==a&&m.self!==a)?c:m}function m(a,b){z[a]||(z[a]=[]),z[a].push(b)}function o(a){for(var b=z[a]||[];b.length;)p(b.shift())}function p(b){b=d(b,{self:b,resolve:b.resolve||{},toString:function(){return this.name}});var c=b.name;if(!I(c)||c.indexOf("@")>=0)throw new Error("State must have a valid name");if(y.hasOwnProperty(c))throw new Error("State '"+c+"'' is already defined");var e=-1!==c.indexOf(".")?c.substring(0,c.lastIndexOf(".")):I(b.parent)?b.parent:J(b.parent)&&I(b.parent.name)?b.parent.name:"";if(e&&!y[e])return m(e,b.self);for(var f in B)H(B[f])&&(b[f]=B[f](b,B.$delegates[f]));return y[c]=b,!b[A]&&b.url&&a.when(b.url,["$match","$stateParams",function(a,c){x.$current.navigable==b&&j(a,c)||x.transitionTo(b,a,{inherit:!0,location:!1})}]),o(c),b}function q(a){return a.indexOf("*")>-1}function r(a){var b=a.split("."),c=x.$current.name.split(".");if("**"===b[0]&&(c=c.slice(h(c,b[1])),c.unshift("**")),"**"===b[b.length-1]&&(c.splice(h(c,b[b.length-2])+1,Number.MAX_VALUE),c.push("**")),b.length!=c.length)return!1;for(var d=0,e=b.length;e>d;d++)"*"===b[d]&&(c[d]="*");return c.join("")===b.join("")}function s(a,b){return I(a)&&!G(b)?B[a]:H(b)&&I(a)?(B[a]&&!B.$delegates[a]&&(B.$delegates[a]=B[a]),B[a]=b,this):this}function t(a,b){return J(a)?b=a:b.name=a,p(b),this}function u(a,e,f,h,m,o,p){function s(b,c,d,f){var g=a.$broadcast("$stateNotFound",b,c,d);if(g.defaultPrevented)return p.update(),B;if(!g.retry)return null;if(f.$retry)return p.update(),C;var h=x.transition=e.when(g.retry);return h.then(function(){return h!==x.transition?u:(b.options.$retry=!0,x.transitionTo(b.to,b.toParams,b.options))},function(){return B}),p.update(),h}function t(a,c,d,g,i,j){var l=d?c:k(a.params.$$keys(),c),n={$stateParams:l};i.resolve=m.resolve(a.resolve,n,i.resolve,a);var o=[i.resolve.then(function(a){i.globals=a})];return g&&o.push(g),L(a.views,function(c,d){var e=c.resolve&&c.resolve!==a.resolve?c.resolve:{};e.$template=[function(){return f.load(d,{view:c,locals:n,params:l,notify:j.notify})||""}],o.push(m.resolve(e,n,i.resolve,a).then(function(f){if(H(c.controllerProvider)||K(c.controllerProvider)){var g=b.extend({},e,n);f.$$controller=h.invoke(c.controllerProvider,null,g)}else f.$$controller=c.controller;f.$$state=a,f.$$controllerAs=c.controllerAs,i[d]=f}))}),e.all(o).then(function(){return i})}var u=e.reject(new Error("transition superseded")),z=e.reject(new Error("transition prevented")),B=e.reject(new Error("transition aborted")),C=e.reject(new Error("transition failed"));return w.locals={resolve:null,globals:{$stateParams:{}}},x={params:{},current:w.self,$current:w,transition:null},x.reload=function(){return x.transitionTo(x.current,o,{reload:!0,inherit:!1,notify:!0})},x.go=function(a,b,c){return x.transitionTo(a,b,M({inherit:!0,relative:x.$current},c))},x.transitionTo=function(b,c,f){c=c||{},f=M({location:!0,inherit:!1,relative:null,notify:!0,reload:!1,$retry:!1},f||{});var g,j=x.$current,m=x.params,n=j.path,q=l(b,f.relative);if(!G(q)){var r={to:b,toParams:c,options:f},y=s(r,j.self,m,f);if(y)return y;if(b=r.to,c=r.toParams,f=r.options,q=l(b,f.relative),!G(q)){if(!f.relative)throw new Error("No such state '"+b+"'");throw new Error("Could not resolve '"+b+"' from state '"+f.relative+"'")}}if(q[A])throw new Error("Cannot transition to abstract state '"+b+"'");if(f.inherit&&(c=i(o,c||{},x.$current,q)),!q.params.$$validates(c))return C;c=q.params.$$values(c),b=q;var B=b.path,D=0,E=B[D],F=w.locals,H=[];if(!f.reload)for(;E&&E===n[D]&&E.ownParams.$$equals(c,m);)F=H[D]=E.locals,D++,E=B[D];if(v(b,j,F,f))return b.self.reloadOnSearch!==!1&&p.update(),x.transition=null,e.when(x.current);if(c=k(b.params.$$keys(),c||{}),f.notify&&a.$broadcast("$stateChangeStart",b.self,c,j.self,m).defaultPrevented)return p.update(),z;for(var I=e.when(F),J=D;J=D;d--)g=n[d],g.self.onExit&&h.invoke(g.self.onExit,g.self,g.locals.globals),g.locals=null;for(d=D;d=0?e:e+"@"+(f?f.state.name:"")}function A(a,b){var c,d=a.match(/^\s*({[^}]*})\s*$/);if(d&&(a=b+"("+d[1]+")"),c=a.replace(/\n/g," ").match(/^([^(]+?)\s*(\((.*)\))?$/),!c||4!==c.length)throw new Error("Invalid state ref '"+a+"'");return{state:c[1],paramExpr:c[3]||null}}function B(a){var b=a.parent().inheritedData("$uiView");return b&&b.state&&b.state.name?b.state:void 0}function C(a,c){var d=["location","inherit","reload"];return{restrict:"A",require:["?^uiSrefActive","?^uiSrefActiveEq"],link:function(e,f,g,h){var i=A(g.uiSref,a.current.name),j=null,k=B(f)||a.$current,l=null,m="A"===f.prop("tagName"),n="FORM"===f[0].nodeName,o=n?"action":"href",p=!0,q={relative:k,inherit:!0},r=e.$eval(g.uiSrefOpts)||{};b.forEach(d,function(a){a in r&&(q[a]=r[a])});var s=function(c){if(c&&(j=b.copy(c)),p){l=a.href(i.state,j,q);var d=h[1]||h[0];return d&&d.$$setStateInfo(i.state,j),null===l?(p=!1,!1):void g.$set(o,l)}};i.paramExpr&&(e.$watch(i.paramExpr,function(a){a!==j&&s(a)},!0),j=b.copy(e.$eval(i.paramExpr))),s(),n||f.bind("click",function(b){var d=b.which||b.button;if(!(d>1||b.ctrlKey||b.metaKey||b.shiftKey||f.attr("target"))){var e=c(function(){a.go(i.state,j,q)});b.preventDefault();var g=m&&!l?1:0;b.preventDefault=function(){g--<=0&&c.cancel(e)}}})}}}function D(a,b,c){return{restrict:"A",controller:["$scope","$element","$attrs",function(b,d,e){function f(){g()?d.addClass(j):d.removeClass(j)}function g(){return"undefined"!=typeof e.uiSrefActiveEq?h&&a.is(h.name,i):h&&a.includes(h.name,i)}var h,i,j;j=c(e.uiSrefActiveEq||e.uiSrefActive||"",!1)(b),this.$$setStateInfo=function(b,c){h=a.get(b,B(d)),i=c,f()},b.$on("$stateChangeSuccess",f)}]}}function E(a){var b=function(b){return a.is(b)};return b.$stateful=!0,b}function F(a){var b=function(b){return a.includes(b)};return b.$stateful=!0,b}var G=b.isDefined,H=b.isFunction,I=b.isString,J=b.isObject,K=b.isArray,L=b.forEach,M=b.extend,N=b.copy;b.module("ui.router.util",["ng"]),b.module("ui.router.router",["ui.router.util"]),b.module("ui.router.state",["ui.router.router","ui.router.util"]),b.module("ui.router",["ui.router.state"]),b.module("ui.router.compat",["ui.router"]),o.$inject=["$q","$injector"],b.module("ui.router.util").service("$resolve",o),p.$inject=["$http","$templateCache","$injector"],b.module("ui.router.util").service("$templateFactory",p);var O;q.prototype.concat=function(a,b){var c={caseInsensitive:O.caseInsensitive(),strict:O.strictMode(),squash:O.defaultSquashPolicy()};return new q(this.sourcePath+a+this.sourceSearch,M(c,b),this)},q.prototype.toString=function(){return this.source},q.prototype.exec=function(a,b){function c(a){function b(a){return a.split("").reverse().join("")}function c(a){return a.replace(/\\-/,"-")}var d=b(a).split(/-(?!\\)/),e=n(d,b);return n(e,c).reverse()}var d=this.regexp.exec(a);if(!d)return null;b=b||{};var e,f,g,h=this.parameters(),i=h.length,j=this.segments.length-1,k={};if(j!==d.length-1)throw new Error("Unbalanced capture group in route '"+this.source+"'");for(e=0;j>e;e++){g=h[e];var l=this.params[g],m=d[e+1];for(f=0;fe;e++)g=h[e],k[g]=this.params[g].value(b[g]);return k},q.prototype.parameters=function(a){return G(a)?this.params[a]||null:this.$$paramNames},q.prototype.validates=function(a){return this.params.$$validates(a)},q.prototype.format=function(a){function b(a){return encodeURIComponent(a).replace(/-/g,function(a){return"%5C%"+a.charCodeAt(0).toString(16).toUpperCase()})}a=a||{};var c=this.segments,d=this.parameters(),e=this.params;if(!this.validates(a))return null;var f,g=!1,h=c.length-1,i=d.length,j=c[0];for(f=0;i>f;f++){var k=h>f,l=d[f],m=e[l],o=m.value(a[l]),p=m.isOptional&&m.type.equals(m.value(),o),q=p?m.squash:!1,r=m.type.encode(o);if(k){var s=c[f+1];if(q===!1)null!=r&&(j+=K(r)?n(r,b).join("-"):encodeURIComponent(r)),j+=s;else if(q===!0){var t=j.match(/\/$/)?/\/?(.*)/:/(.*)/;j+=s.match(t)[1]}else I(q)&&(j+=q+s)}else{if(null==r||p&&q!==!1)continue;K(r)||(r=[r]),r=n(r,encodeURIComponent).join("&"+l+"="),j+=(g?"&":"?")+(l+"="+r),g=!0}}return j},r.prototype.is=function(){return!0},r.prototype.encode=function(a){return a},r.prototype.decode=function(a){return a},r.prototype.equals=function(a,b){return a==b},r.prototype.$subPattern=function(){var a=this.pattern.toString();return a.substr(1,a.length-2)},r.prototype.pattern=/.*/,r.prototype.toString=function(){return"{Type:"+this.name+"}"},r.prototype.$asArray=function(a,b){function d(a,b){function d(a,b){return function(){return a[b].apply(a,arguments)}}function e(a){return K(a)?a:G(a)?[a]:[]}function f(a){switch(a.length){case 0:return c;case 1:return"auto"===b?a[0]:a;default:return a}}function g(a){return!a}function h(a,b){return function(c){c=e(c);var d=n(c,a);return b===!0?0===m(d,g).length:f(d)}}function i(a){return function(b,c){var d=e(b),f=e(c);if(d.length!==f.length)return!1;for(var g=0;g