├── .dockerignore ├── .editorconfig ├── .gitignore ├── CHANGELOG.md ├── Dockerfile ├── LICENSE ├── README.md ├── data ├── barData.json └── bazData.json ├── e2e-spec.js ├── favicon.ico ├── index.html ├── karma-test-shim.js ├── karma.conf.js ├── package.json ├── protractor.config.js ├── src ├── app.component.ts ├── app.states.ts ├── bar │ ├── bar.module.ts │ ├── bar.states.ts │ ├── barDetail.component.ts │ ├── barFooter.component.ts │ └── barList.component.ts ├── baz │ ├── baz.module.ts │ ├── baz.states.ts │ ├── bazDetail.component.ts │ ├── bazFooter.component.ts │ └── bazList.component.ts ├── bootstrap.ts ├── foo │ ├── foo.component.ts │ ├── foo.module.ts │ ├── foo.states.ts │ ├── fooFooter.component.ts │ ├── nest1.component.ts │ └── nest2.component.ts ├── router.config.ts └── shared.module.ts ├── styles.css ├── systemjs.config.js ├── tsconfig.json ├── tslint.json └── wallaby.js /.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | end_of_line = lf 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | 12 | 13 | [*.md] 14 | max_line_length = 0 15 | trim_trailing_whitespace = false 16 | 17 | # Indentation override 18 | #[lib/**.js] 19 | #[{package.json,.travis.yml}] 20 | #[**/**.js] 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | typings/** 3 | node_modules 4 | jspm_packages 5 | link-checker-results.txt 6 | **/*npm-debug.log.* 7 | *.js 8 | *.js.map 9 | _test-output 10 | _temp 11 | 12 | !**/*e2e-spec.js 13 | !karma*.js 14 | !protractor*.js 15 | !systemjs.config.js 16 | !typings/typings.d.ts 17 | !wallaby.js 18 | 19 | *.ipr 20 | *.iml 21 | *.iws 22 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | # 0.2.1 (2016-05-03) 3 | * Angular 2 RC01 version 4 | 5 | 6 | # 0.2.0 (2016-05-02) 7 | * Angular 2 RC0 version 8 | 9 | 10 | # 0.1.17 (2016-04-29) 11 | * update packages 12 | * Angular 2 beta 17 13 | * RxJS 5.0.0-beta.6 14 | * a2-in-memory-web-api 0.1.17 15 | 16 | 17 | # 0.1.16 (2016-04-26) 18 | * update packages 19 | * Angular 2 beta 16 20 | * a2-in-memory-web-api 0.1.6 21 | * protractor 3.3.0 22 | * typings 0.8.1 23 | * zone.js 0.6.12 24 | 25 | * added favicon.ico 26 | 27 | * testing 28 | - updated wallaby.js and karma.conf.js 29 | - updated app.component.spec.ts 30 | 31 | 32 | 33 | # 0.1.15 (2016-04-13) 34 | * Add testing support 35 | * npm scripts 36 | * karma/jasmine 37 | * protractor 38 | 39 | * update packages 40 | * Angular 2 beta 15 41 | * lite-server 2.2.0 42 | * systemjs 0.19.26 43 | * typescript 1.8.10 44 | * typings 0.7.12 45 | 46 | * add run packages 47 | * a2-in-memory-web-api 48 | 49 | * add testing dev-dependency packages 50 | * canonical-path: 0.0.2, 51 | * http-server: ^0.9.0, 52 | * jasmine-core: ~2.4.1, 53 | * karma: ^0.13.22, 54 | * karma-chrome-launcher: ^0.2.3, 55 | * karma-cli: ^0.1.2, 56 | * karma-htmlfile-reporter: ^0.2.2, 57 | * karma-jasmine: ^0.3.8, 58 | * protractor: ^3.2.2, 59 | * rimraf: ^2.5.2 60 | 61 | 62 | # 0.1.14 (2016-04-07) 63 | * update packages 64 | * Angular 2 beta 14 65 | * lite-server 2.2.0 66 | * typings 0.7.12 67 | 68 | 69 | # 0.1.13 (2016-03-31) 70 | * update packages 71 | * Angular 2 beta 13 72 | 73 | 74 | # 0.1.12 (2016-03-23) 75 | * update packages 76 | * Angular 2 beta 12 77 | * zones 0.6.6 78 | * remove es6-promise because no longer needed. 79 | 80 | 81 | # 0.1.11 (2016-03-18) 82 | * update packages 83 | * Angular 2 beta 11 84 | * zones 0.6.4 85 | * typescript 1.8.9 86 | * typings 0.7.9 87 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # To build and run with Docker: 2 | # 3 | # $ docker build -t ng2-quickstart . 4 | # $ docker run -it --rm -p 3000:3000 -p 3001:3001 ng2-quickstart 5 | # 6 | FROM node:latest 7 | 8 | RUN mkdir -p /quickstart /home/nodejs && \ 9 | groupadd -r nodejs && \ 10 | useradd -r -g nodejs -d /home/nodejs -s /sbin/nologin nodejs && \ 11 | chown -R nodejs:nodejs /home/nodejs 12 | 13 | WORKDIR /quickstart 14 | COPY package.json typings.json /quickstart/ 15 | RUN npm install --unsafe-perm=true 16 | 17 | COPY . /quickstart 18 | RUN chown -R nodejs:nodejs /quickstart 19 | USER nodejs 20 | 21 | CMD npm start 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2014-2016 Google, Inc. 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Deprecated in favor of Angular-CLI starter: https://github.com/ui-router/quickstart-angular 2 | 3 | 4 | 5 | # UI-Router for Angular 2 QuickStart Source 6 | 7 | ### Start development 8 | 9 | Install the npm packages described in the `package.json` and verify that it works: 10 | 11 | ```bash 12 | git clone https://github.com/ui-router/quickstart-ng2.git 13 | cd quickstart-ng2 14 | npm install 15 | npm run tsc 16 | npm start 17 | ``` 18 | 19 | ### UI-Router for NG2 quickstart highlights: 20 | 21 | - We're using npm and systemjs. We added a dependency on latest `ui-router-ng2` in [package.json](https://github.com/ui-router/quickstart-ng2/blob/1.0.2/package.json#L19) 22 | - Import UI-Router classes [directly from `"ui-router-ng2"`](https://github.com/ui-router/quickstart-ng2/blob/1.0.2/app/app.component.ts#L2) 23 | - Either [bootstrap a `UIView` component](https://github.com/ui-router/quickstart-ng2/blob/1.0.2/app/_bootstrap/bootstrap.ts#L14), or add a `` viewport to your root component. 24 | - [Create application states](https://github.com/ui-router/quickstart-ng2/blob/1.0.2/app/app.states.ts#L16-L20) (as defined by Ng2StateDeclaration]]) which will fill in the `ui-view` viewports with component. 25 | - Create a `UIRouterConfig` and apply any router config in the `UIRouterConfig.configure()` function. 26 | - Bootstrap a `@UIRouterModule`. Provide UI-Router using [the `provideUIRouter` helper](https://github.com/ui-router/quickstart-ng2/blob/c69c19d30fbeb25e99a2d5c3b3fb72866513ab03/src/app.module.ts#L34). 27 | 28 | #### Foo module 29 | 30 | - Simple nested views 31 | - Update browser hash value 32 | 33 | #### Bar module 34 | 35 | - Resolve data from server (bar list) 36 | - Query parameter 37 | - Nested view (bar detail renders inside bar list) 38 | 39 | #### Baz module 40 | 41 | - This module is lazy loaded using a "Future State" with a [`lazyLoad` function](https://ui-router.github.io/docs/latest/interfaces/state.statedeclaration.html#lazyload) 42 | - Resolve data from server (baz list) 43 | - Path parameter 44 | - View targeting (baz detail replaces the baz list) 45 | 46 | --- 47 | 48 | You're ready to write your application. 49 | 50 | Remember the npm scripts in `package.json`: 51 | 52 | * `npm start` - runs the compiler and a server at the same time, both in "watch mode". 53 | * `npm run tsc` - runs the TypeScript compiler once. 54 | * `npm run tsc:w` - runs the TypeScript compiler in watch mode; the process keeps running, awaiting changes to TypeScript files and re-compiling when it sees them. 55 | * `npm run lite` - runs the [lite-server](https://www.npmjs.com/package/lite-server), a light-weight, static file server, written and maintained by 56 | [John Papa](https://github.com/johnpapa) and 57 | [Christopher Martin](https://github.com/cgmartin) 58 | with excellent support for Angular apps that use routing. 59 | * `npm run typings` - runs the typings tool. 60 | * `npm run postinstall` - called by *npm* automatically *after* it successfully completes package installation. This script installs the TypeScript definition files this app requires. 61 | 62 | (This repo is forked from https://github.com/angular/quickstart) 63 | 64 | -------------------------------------------------------------------------------- /data/barData.json: -------------------------------------------------------------------------------- 1 | [ 2 | { "id": 1, "name": "thing", "description": "This is a foo thing" }, 3 | { "id": 2, "name": "fighters", "description": "Foo Fighters" }, 4 | { "id": 3, "name": "manchu", "description": "Foo manchu" }, 5 | { "id": 4, "name": "bar", "description": "FUBAR" }, 6 | { "id": 5, "name": "d", "description": "Yummy food" } 7 | ] -------------------------------------------------------------------------------- /data/bazData.json: -------------------------------------------------------------------------------- 1 | [ 2 | { "id": 1, "name": "buzz", "description": "Buzz buzz buzz" }, 3 | { "id": 2, "name": "bazy", "description": "Bazy as a bee" }, 4 | { "id": 3, "name": "bee", "description": "Bee excellent to each other" }, 5 | { "id": 4, "name": "zzzzz", "description": "Get plenty of sleep" } 6 | ] 7 | -------------------------------------------------------------------------------- /e2e-spec.js: -------------------------------------------------------------------------------- 1 | 2 | describe('QuickStart E2E Tests', function () { 3 | 4 | var expectedMsg = 'My First Angular 2 App'; 5 | 6 | 7 | beforeEach(function () { 8 | browser.get(''); 9 | }); 10 | 11 | it('should display: ' + expectedMsg, function () { 12 | expect(element(by.css('h1')).getText()).toEqual(expectedMsg); 13 | }); 14 | 15 | }); 16 | -------------------------------------------------------------------------------- /favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ui-router/quickstart-ng2/8d3f8c417033480fa1de69252f713206e8cf8640/favicon.ico -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | UI-Router Angular 2 QuickStart 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 21 | 22 | 23 | 24 | Loading... 25 | 26 | 27 | -------------------------------------------------------------------------------- /karma-test-shim.js: -------------------------------------------------------------------------------- 1 | /*global jasmine, __karma__, window*/ 2 | (function () { 3 | 4 | // Error.stackTraceLimit = Infinity; 5 | 6 | jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000; 7 | 8 | // Cancel Karma's synchronous start, 9 | // we call `__karma__.start()` later, once all the specs are loaded. 10 | __karma__.loaded = function () { }; 11 | 12 | // SET THE RUNTIME APPLICATION ROOT HERE 13 | var appRoot ='app'; // no trailing slash! 14 | 15 | // RegExp for client application base path within karma (which always starts 'base\') 16 | var karmaBase = '^\/base\/'; // RegEx string for base of karma folders 17 | var appPackage = 'base/' + appRoot; //e.g., base/app 18 | var appRootRe = new RegExp(karmaBase + appRoot + '\/'); 19 | var onlyAppFilesRe = new RegExp(karmaBase + appRoot + '\/(?!.*\.spec\.js$)([a-z0-9-_\.\/]+)\.js$'); 20 | 21 | var moduleNames = []; 22 | 23 | // Configure systemjs packages to use the .js extension for imports from the app folder 24 | var packages = {}; 25 | packages[appPackage] = { 26 | defaultExtension: false, 27 | format: 'register', 28 | map: Object.keys(window.__karma__.files) 29 | .filter(onlyAppFiles) 30 | // Create local module name mapping to karma file path for app files 31 | // with karma's fingerprint in query string, e.g.: 32 | // './hero.service': '/base/app/hero.service.js?f4523daf879cfb7310ef6242682ccf10b2041b3e' 33 | .reduce(function (pathsMapping, appPath) { 34 | var moduleName = appPath.replace(appRootRe, './').replace(/\.js$/, ''); 35 | pathsMapping[moduleName] = appPath + '?' + window.__karma__.files[appPath]; 36 | return pathsMapping; 37 | }, {}) 38 | } 39 | 40 | System.config({ packages: packages }); 41 | 42 | // Configure Angular for the browser and 43 | // with test versions of the platform providers 44 | Promise.all([ 45 | System.import('angular2/testing'), 46 | System.import('angular2/platform/testing/browser') 47 | ]) 48 | .then(function (results) { 49 | var testing = results[0]; 50 | var browser = results[1]; 51 | testing.setBaseTestProviders( 52 | browser.TEST_BROWSER_PLATFORM_PROVIDERS, 53 | browser.TEST_BROWSER_APPLICATION_PROVIDERS); 54 | 55 | // Load all spec files 56 | // (e.g. 'base/app/hero.service.spec.js') 57 | return Promise.all( 58 | Object.keys(window.__karma__.files) 59 | .filter(onlySpecFiles) 60 | .map(function (moduleName) { 61 | moduleNames.push(moduleName); 62 | return System.import(moduleName); 63 | })); 64 | }) 65 | 66 | .then(success, fail); 67 | 68 | ////// Helpers ////// 69 | 70 | function onlyAppFiles(filePath) { 71 | return onlyAppFilesRe.test(filePath); 72 | } 73 | 74 | function onlySpecFiles(filePath) { 75 | return /\.spec\.js$/.test(filePath); 76 | } 77 | 78 | function success () { 79 | console.log( 80 | 'Spec files loaded:\n ' + 81 | moduleNames.join('\n ') + 82 | '\nStarting Jasmine testrunner'); 83 | __karma__.start(); 84 | } 85 | 86 | function fail(error) { 87 | __karma__.error(error.stack || error); 88 | } 89 | 90 | })(); 91 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | module.exports = function(config) { 2 | 3 | var appBase = 'app/'; // transpiled app JS files 4 | var appAssets ='/base/app/'; // component assets fetched by Angular's compiler 5 | 6 | config.set({ 7 | basePath: '', 8 | frameworks: ['jasmine'], 9 | plugins: [ 10 | require('karma-jasmine'), 11 | require('karma-chrome-launcher'), 12 | require('karma-htmlfile-reporter') 13 | ], 14 | 15 | customLaunchers: { 16 | // From the CLI. Not used here but interesting 17 | // chrome setup for travis CI using chromium 18 | Chrome_travis_ci: { 19 | base: 'Chrome', 20 | flags: ['--no-sandbox'] 21 | } 22 | }, 23 | files: [ 24 | // System.js for module loading 25 | 'node_modules/systemjs/dist/system-polyfills.js', 26 | 'node_modules/systemjs/dist/system.src.js', 27 | 28 | // Polyfills 29 | 'node_modules/es6-shim/es6-shim.js', 30 | 'node_modules/angular2/bundles/angular2-polyfills.js', 31 | 32 | // Zone.js dependencies 33 | // Note - do not include zone.js itself or long-stack-trace-zone.js` here as 34 | // they are included already in angular2-polyfills 35 | 'node_modules/zone.js/dist/jasmine-patch.js', 36 | 'node_modules/zone.js/dist/async-test.js', 37 | 'node_modules/zone.js/dist/fake-async-test.js', 38 | 39 | // RxJs 40 | 'node_modules/rxjs/bundles/Rx.js', 41 | 42 | // Angular 2 itself and the testing library 43 | 'node_modules/angular2/bundles/angular2.js', 44 | 'node_modules/angular2/bundles/router.dev.js', 45 | 'node_modules/angular2/bundles/http.dev.js', 46 | 'node_modules/angular2/bundles/testing.dev.js', 47 | 48 | 'karma-test-shim.js', 49 | 50 | // transpiled application & spec code paths loaded via module imports 51 | {pattern: appBase + '**/*.js', included: false, watched: true}, 52 | 53 | // asset (HTML & CSS) paths loaded via Angular's component compiler 54 | // (these paths need to be rewritten, see proxies section) 55 | {pattern: appBase + '**/*.html', included: false, watched: true}, 56 | {pattern: appBase + '**/*.css', included: false, watched: true}, 57 | 58 | // paths for debugging with source maps in dev tools 59 | {pattern: appBase + '**/*.ts', included: false, watched: false}, 60 | {pattern: appBase + '**/*.js.map', included: false, watched: false} 61 | ], 62 | 63 | // proxied base paths for loading assets 64 | proxies: { 65 | // required for component assets fetched by Angular's compiler 66 | "/app/": appAssets 67 | }, 68 | 69 | exclude: [], 70 | preprocessors: {}, 71 | reporters: ['progress', 'html'], 72 | 73 | // HtmlReporter configuration 74 | htmlReporter: { 75 | // Open this file to see results in browser 76 | outputFile: '_test-output/tests.html', 77 | 78 | // Optional 79 | pageTitle: 'Unit Tests', 80 | subPageTitle: __dirname 81 | }, 82 | 83 | port: 9876, 84 | colors: true, 85 | logLevel: config.LOG_INFO, 86 | autoWatch: true, 87 | browsers: ['Chrome'], 88 | singleRun: false 89 | }) 90 | } 91 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ui-router-ng2-quickstart", 3 | "version": "1.0.5", 4 | "scripts": { 5 | "start": "npm run tsc && npm run watch", 6 | "tsc": "tsc", 7 | "tsc:w": "tsc -w", 8 | "serve": "lite-server", 9 | "watch": "run-p tsc:w serve" 10 | }, 11 | "license": "MIT", 12 | "repository": { 13 | "type": "git", 14 | "url": "https://github.com/ui-router/quickstart-ng2.git" 15 | }, 16 | "dependencies": { 17 | "@angular/common": "^4.0.0", 18 | "@angular/compiler": "^4.0.0", 19 | "@angular/core": "^4.0.0", 20 | "@angular/http": "^4.0.0", 21 | "@angular/platform-browser": "^4.0.0", 22 | "@angular/platform-browser-dynamic": "^4.0.0", 23 | "@angular/router": "^4.0.0", 24 | "@uirouter/angular": "^1.0.0-beta.6", 25 | "@uirouter/visualizer": "^4.0.0", 26 | "core-js": "^2.4.0", 27 | "es6-shim": "^0.35.0", 28 | "reflect-metadata": "^0.1.3", 29 | "rxjs": "^5.0.0-beta.12", 30 | "systemjs": "0.19.27", 31 | "zone.js": "^0.6.21" 32 | }, 33 | "devDependencies": { 34 | "@types/chai": "^3.4.34", 35 | "lite-server": "^2.1.0", 36 | "npm-run-all": "^3.1.1", 37 | "shx": "^0.1.4", 38 | "typescript": "^2.0.0" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /protractor.config.js: -------------------------------------------------------------------------------- 1 | // FIRST TIME ONLY- run: 2 | // ./node_modules/.bin/webdriver-manager update 3 | // 4 | // Try: `npm run webdriver:update` 5 | // 6 | // AND THEN EVERYTIME ... 7 | // 1. Compile with `tsc` 8 | // 2. Make sure the test server (e.g., http-server: localhost:8080) is running. 9 | // 3. ./node_modules/.bin/protractor protractor.config.js 10 | // 11 | // To do all steps, try: `npm run e2e` 12 | 13 | var fs = require('fs'); 14 | var path = require('canonical-path'); 15 | var _ = require('lodash'); 16 | 17 | 18 | exports.config = { 19 | directConnect: true, 20 | 21 | // Capabilities to be passed to the webdriver instance. 22 | capabilities: { 23 | 'browserName': 'chrome' 24 | }, 25 | 26 | // Framework to use. Jasmine is recommended. 27 | framework: 'jasmine', 28 | 29 | // Spec patterns are relative to this config file 30 | specs: ['**/*e2e-spec.js' ], 31 | 32 | 33 | // For angular2 tests 34 | useAllAngular2AppRoots: true, 35 | 36 | // Base URL for application server 37 | baseUrl: 'http://localhost:8080', 38 | 39 | // doesn't seem to work. 40 | // resultJsonOutputFile: "foo.json", 41 | 42 | onPrepare: function() { 43 | //// SpecReporter 44 | //var SpecReporter = require('jasmine-spec-reporter'); 45 | //jasmine.getEnv().addReporter(new SpecReporter({displayStacktrace: 'none'})); 46 | //// jasmine.getEnv().addReporter(new SpecReporter({displayStacktrace: 'all'})); 47 | 48 | // debugging 49 | // console.log('browser.params:' + JSON.stringify(browser.params)); 50 | jasmine.getEnv().addReporter(new Reporter( browser.params )) ; 51 | 52 | global.sendKeys = sendKeys; 53 | 54 | // Allow changing bootstrap mode to NG1 for upgrade tests 55 | global.setProtractorToNg1Mode = function() { 56 | browser.useAllAngular2AppRoots = false; 57 | browser.rootEl = 'body'; 58 | }; 59 | }, 60 | 61 | jasmineNodeOpts: { 62 | // defaultTimeoutInterval: 60000, 63 | defaultTimeoutInterval: 10000, 64 | showTiming: true, 65 | print: function() {} 66 | } 67 | }; 68 | 69 | // Hack - because of bug with protractor send keys 70 | function sendKeys(element, str) { 71 | return str.split('').reduce(function (promise, char) { 72 | return promise.then(function () { 73 | return element.sendKeys(char); 74 | }); 75 | }, element.getAttribute('value')); 76 | // better to create a resolved promise here but ... don't know how with protractor; 77 | } 78 | 79 | // Custom reporter 80 | function Reporter(options) { 81 | var _defaultOutputFile = path.resolve(process.cwd(), './_test-output', 'protractor-results.txt'); 82 | options.outputFile = options.outputFile || _defaultOutputFile; 83 | 84 | initOutputFile(options.outputFile); 85 | options.appDir = options.appDir || './'; 86 | var _root = { appDir: options.appDir, suites: [] }; 87 | log('AppDir: ' + options.appDir, +1); 88 | var _currentSuite; 89 | 90 | this.suiteStarted = function(suite) { 91 | _currentSuite = { description: suite.description, status: null, specs: [] }; 92 | _root.suites.push(_currentSuite); 93 | log('Suite: ' + suite.description, +1); 94 | }; 95 | 96 | this.suiteDone = function(suite) { 97 | var statuses = _currentSuite.specs.map(function(spec) { 98 | return spec.status; 99 | }); 100 | statuses = _.uniq(statuses); 101 | var status = statuses.indexOf('failed') >= 0 ? 'failed' : statuses.join(', '); 102 | _currentSuite.status = status; 103 | log('Suite ' + _currentSuite.status + ': ' + suite.description, -1); 104 | }; 105 | 106 | this.specStarted = function(spec) { 107 | 108 | }; 109 | 110 | this.specDone = function(spec) { 111 | var currentSpec = { 112 | description: spec.description, 113 | status: spec.status 114 | }; 115 | if (spec.failedExpectations.length > 0) { 116 | currentSpec.failedExpectations = spec.failedExpectations; 117 | } 118 | 119 | _currentSuite.specs.push(currentSpec); 120 | log(spec.status + ' - ' + spec.description); 121 | }; 122 | 123 | this.jasmineDone = function() { 124 | outputFile = options.outputFile; 125 | //// Alternate approach - just stringify the _root - not as pretty 126 | //// but might be more useful for automation. 127 | // var output = JSON.stringify(_root, null, 2); 128 | var output = formatOutput(_root); 129 | fs.appendFileSync(outputFile, output); 130 | }; 131 | 132 | function initOutputFile(outputFile) { 133 | var header = "Protractor results for: " + (new Date()).toLocaleString() + "\n\n"; 134 | fs.writeFileSync(outputFile, header); 135 | } 136 | 137 | // for output file output 138 | function formatOutput(output) { 139 | var indent = ' '; 140 | var pad = ' '; 141 | var results = []; 142 | results.push('AppDir:' + output.appDir); 143 | output.suites.forEach(function(suite) { 144 | results.push(pad + 'Suite: ' + suite.description + ' -- ' + suite.status); 145 | pad+=indent; 146 | suite.specs.forEach(function(spec) { 147 | results.push(pad + spec.status + ' - ' + spec.description); 148 | if (spec.failedExpectations) { 149 | pad+=indent; 150 | spec.failedExpectations.forEach(function (fe) { 151 | results.push(pad + 'message: ' + fe.message); 152 | }); 153 | pad=pad.substr(2); 154 | } 155 | }); 156 | pad = pad.substr(2); 157 | results.push(''); 158 | }); 159 | results.push(''); 160 | return results.join('\n'); 161 | } 162 | 163 | // for console output 164 | var _pad; 165 | function log(str, indent) { 166 | _pad = _pad || ''; 167 | if (indent == -1) { 168 | _pad = _pad.substr(2); 169 | } 170 | console.log(_pad + str); 171 | if (indent == 1) { 172 | _pad = _pad + ' '; 173 | } 174 | } 175 | 176 | } 177 | -------------------------------------------------------------------------------- /src/app.component.ts: -------------------------------------------------------------------------------- 1 | import {Component} from '@angular/core'; 2 | 3 | /** 4 | * The top level application component. 5 | * 6 | * This component renders three uiSref "links" and has a viewport for a child to fill in. 7 | */ 8 | 9 | let template = ` 10 | 11 |

My First UI-Router Angular 2 App

12 | 13 | Foo 14 | Bar 15 | Baz 16 | 17 | 18 | 19 | 20 | `; 21 | 22 | @Component({ 23 | selector: 'my-app', 24 | template: template 25 | }) 26 | export class AppComponent { } 27 | -------------------------------------------------------------------------------- /src/app.states.ts: -------------------------------------------------------------------------------- 1 | import {AppComponent} from "./app.component"; 2 | import {Ng2StateDeclaration, loadNgModule} from "@uirouter/angular"; 3 | 4 | /** The top level state(s) */ 5 | export let MAIN_STATES: Ng2StateDeclaration[] = [ 6 | // The top-level app state. 7 | // This state fills the root (defined in index.html) with the AppComponent 8 | { name: 'app', component: AppComponent }, 9 | 10 | // This is the Future State for lazy loading the BazModule 11 | { name: 'app.baz.**', url: '/baz', lazyLoad: loadNgModule('src/baz/baz.module') } 12 | ]; 13 | -------------------------------------------------------------------------------- /src/bar/bar.module.ts: -------------------------------------------------------------------------------- 1 | import {UIRouterModule} from "@uirouter/angular"; 2 | import {SharedModule} from "../shared.module"; 3 | import {BAR_STATES} from "./bar.states"; 4 | import {NgModule} from "@angular/core"; 5 | import {BarListComponent} from "./barList.component"; 6 | import {BarDetailsComponent} from "./barDetail.component"; 7 | import {BarFooterComponent} from "./barFooter.component"; 8 | 9 | /** The Bar NgModule */ 10 | @NgModule({ 11 | imports: [ 12 | SharedModule, 13 | UIRouterModule.forChild({ states: BAR_STATES }) 14 | ], 15 | declarations: [ 16 | BarListComponent, 17 | BarDetailsComponent, 18 | BarFooterComponent, 19 | ] 20 | }) 21 | export class BarModule { } 22 | 23 | -------------------------------------------------------------------------------- /src/bar/bar.states.ts: -------------------------------------------------------------------------------- 1 | import {Http} from "@angular/http"; 2 | import {BarListComponent} from "./barList.component"; 3 | import {BarDetailsComponent} from "./barDetail.component"; 4 | import {BarFooterComponent} from "./barFooter.component"; 5 | import {Ng2StateDeclaration, Transition} from "@uirouter/angular"; 6 | /** 7 | * This file defines the states for the `bar` module. 8 | * The states are exported as an array and imported in the BarModule. 9 | */ 10 | export let BAR_STATES: Ng2StateDeclaration[] = [ 11 | // A state for the 'app.bar' submodule. 12 | // - Fills in the unnamed ($default) from `app` state with `BarListComponent` 13 | // - Fills in the footer from `app` state with `BarFooterComponent` 14 | // - Fetches barList data using a resolve, then the component displays the data 15 | { 16 | name: 'app.bar', 17 | url: '/bar', 18 | views: { 19 | $default: { component: BarListComponent }, 20 | footer: { component: BarFooterComponent } 21 | }, 22 | resolve: [ 23 | // Inject 'http' and fetch all the bar data 24 | { 25 | token: 'barList', 26 | deps: [Http], 27 | resolveFn: (http: Http) => 28 | http.get('/data/barData.json').map(res => res.json()).toPromise() 29 | } 30 | ] 31 | }, 32 | 33 | // A child state of app.bar 34 | // - This state fills the unnnamed (in `BarListComponent` from `app.foo` state) with `BarDetailsComponent` 35 | // - Has a parameter :barId which appears in the URL 36 | // - Resolves barDetail, then the component displays the data 37 | { 38 | name: 'app.bar.details', url: '/?barId', component: BarDetailsComponent, 39 | resolve: [ 40 | // Inject the barList (from the parent) and find the correct 41 | { 42 | token: 'barDetail', 43 | deps: ['barList', Transition], 44 | resolveFn: (barList, trans) => 45 | barList.find(item => item.id == trans.params().barId) 46 | } 47 | ] 48 | }, 49 | ]; 50 | 51 | 52 | -------------------------------------------------------------------------------- /src/bar/barDetail.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, Input} from '@angular/core'; 2 | 3 | /** 4 | * This component injects "barDetail" (resolve data) into the matching @Input and renders the detail */ 5 | let template = ` 6 |
Bar Details
7 | 8 |
9 |
10 |
11 | `; 12 | 13 | @Component({ 14 | selector: 'bar-detail', 15 | template: template 16 | }) 17 | export class BarDetailsComponent { 18 | // `barDetail` resolve data is provided to this @Input 19 | @Input('barDetail') bar; 20 | } 21 | -------------------------------------------------------------------------------- /src/bar/barFooter.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, Input} from '@angular/core'; 2 | 3 | /** 4 | * This component is shown in the footer when any bar state is active. 5 | * It receives the `barList` resolve data and displays the count of bar objects loaded. 6 | */ 7 | @Component({ 8 | selector: 'bar-footer', 9 | styles: ['h4 { border-top: 2px solid black; margin-top: 1em; }'], 10 | template: `

Bar Module Active - {{ barList.length }} bars

` 11 | }) 12 | export class BarFooterComponent { 13 | @Input() barList; 14 | } 15 | -------------------------------------------------------------------------------- /src/bar/barList.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, Inject} from '@angular/core'; 2 | 3 | /** 4 | * This component has "barList" (resolve data) injected into the constructor. 5 | * 6 | * It creates a list of uiSref (links) to the bar details and highlights the active uiSref 7 | * It provides a viewport for a child state to fill in 8 | */ 9 | 10 | let template = ` 11 |

Bar Component

12 | 13 | 18 | 19 | 20 | `; 21 | 22 | @Component({ 23 | selector: 'bar', 24 | template: template 25 | }) 26 | export class BarListComponent { 27 | // resolve data injected by name 'barList' into 'bars' property 28 | constructor(@Inject("barList") public bars) { } 29 | } 30 | -------------------------------------------------------------------------------- /src/baz/baz.module.ts: -------------------------------------------------------------------------------- 1 | import {UIRouterModule} from "@uirouter/angular"; 2 | import {SharedModule} from "../shared.module"; 3 | import {BAZ_STATES} from "./baz.states"; 4 | import {NgModule} from "@angular/core"; 5 | import {BazListComponent} from "./bazList.component"; 6 | import {BazDetailsComponent} from "./bazDetail.component"; 7 | import {BazFooterComponent} from "./bazFooter.component"; 8 | 9 | /** The Baz NgModule. */ 10 | @NgModule({ 11 | imports: [ 12 | SharedModule, 13 | UIRouterModule.forChild({ states: BAZ_STATES }) 14 | ], 15 | declarations: [ 16 | BazListComponent, 17 | BazDetailsComponent, 18 | BazFooterComponent, 19 | ] 20 | }) 21 | export default class BazModule { } 22 | -------------------------------------------------------------------------------- /src/baz/baz.states.ts: -------------------------------------------------------------------------------- 1 | import {Http} from "@angular/http"; 2 | import {BazListComponent} from "./bazList.component"; 3 | import {BazDetailsComponent} from "./bazDetail.component"; 4 | import {BazFooterComponent} from "./bazFooter.component"; 5 | import {Ng2StateDeclaration, Transition} from "@uirouter/angular"; 6 | /** 7 | * This file defines the states for the `baz` module. 8 | * The states are exported as an array and imported in the BazModule. 9 | */ 10 | export let BAZ_STATES: Ng2StateDeclaration[] = [ 11 | 12 | // A state for the 'app.baz' submodule. 13 | // - Fills in the unnamed ($default) from `app` state with `BazListComponent` 14 | // - Fills in the footer from `app` state with `BazFooterComponent` 15 | // - Fetches bazList data using a resolve, then the component displays the data 16 | { 17 | name: 'app.baz', 18 | url: '/baz', 19 | views: { 20 | $default: { component: BazListComponent }, 21 | footer: { component: BazFooterComponent } 22 | }, 23 | resolve: [ 24 | // Inject 'Http' and fetch all the baz data 25 | { 26 | token: 'bazList', 27 | deps: [Http], 28 | resolveFn: (http: Http) => 29 | http.get('/data/bazData.json').map(res => res.json()).toPromise() 30 | } 31 | ] 32 | }, 33 | 34 | // A child state of app.baz 35 | // - This state fills the unnamed ($default) (in the `AppComponent` from `app` state) with 36 | // `BazDetailsComponent`. This effectively replaces the baz list view with a baz detail view. 37 | // - Has a path parameter :bazId which appears in the URL 38 | // - Resolves bazDetail, then the component displays the data 39 | { 40 | name: 'app.baz.details', 41 | url: '/:bazId', 42 | views: { 43 | '$default@app': { component: BazDetailsComponent } 44 | }, 45 | resolve: [ 46 | // Inject the bazList (from the parent) and find the correct 47 | { 48 | token: 'bazDetail', 49 | deps: ['bazList', Transition], 50 | resolveFn: (bazList, trans) => 51 | bazList.find(item => item.id == trans.params().bazId) 52 | } 53 | ] 54 | }, 55 | ]; 56 | 57 | 58 | -------------------------------------------------------------------------------- /src/baz/bazDetail.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, Input} from '@angular/core'; 2 | 3 | /** 4 | * This component receives `bazDetail` resolve data into the `bazDetail` input, then renders the detail 5 | * It has a link back to the parent state, which is `app.baz` 6 | */ 7 | let template = ` 8 |
Baz Details
9 | Back to list
10 | 11 |
12 |
13 |
14 | `; 15 | 16 | @Component({ 17 | selector: 'baz-detail', 18 | template: template, 19 | // `bazDetail` resolve data is provided to the `bazDetail` input 20 | inputs: ["bazDetail"], 21 | }) 22 | export class BazDetailsComponent { 23 | bazDetail; 24 | } 25 | -------------------------------------------------------------------------------- /src/baz/bazFooter.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, Input} from '@angular/core'; 2 | 3 | /** 4 | * This component is shown in the footer when any baz state is active. 5 | * It receives the `bazList` resolve data and displays the count of baz objects loaded. 6 | */ 7 | @Component({ 8 | selector: 'baz-footer', 9 | styles: ['h4 { border-top: 2px solid black; margin-top: 1em; }'], 10 | template: `

Baz Module Active - {{ bazList.length }} bazs

` 11 | }) 12 | export class BazFooterComponent { 13 | @Input() bazList; 14 | } 15 | -------------------------------------------------------------------------------- /src/baz/bazList.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, Inject} from '@angular/core'; 2 | 3 | /** 4 | * This component injects "bazList" (resolve data) 5 | * 6 | * It creates a list of uiSref (links) to the baz details 7 | * 8 | * It does not have a nested viewport because the nested app.baz.details state 9 | * replaces this component with the BazDetailsComponent, using view targeting. 10 | */ 11 | 12 | let template = ` 13 |

Baz Component

14 | 15 | 19 | `; 20 | 21 | @Component({ 22 | selector: 'baz', 23 | template: template 24 | }) 25 | export class BazListComponent { 26 | // resolve data injected by name 'bazList' into 'bazs' property 27 | constructor(@Inject("bazList") public bazs) { 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/bootstrap.ts: -------------------------------------------------------------------------------- 1 | import 'rxjs/add/operator/toPromise'; 2 | import 'rxjs/add/operator/map'; 3 | 4 | import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; 5 | import {trace, Category, UIRouterModule, UIView} from "@uirouter/angular"; 6 | import {NgModule, NgModuleFactoryLoader, SystemJsNgModuleLoader} from "@angular/core"; 7 | import {BrowserModule} from "@angular/platform-browser"; 8 | 9 | import {MAIN_STATES} from "./app.states"; 10 | import {AppComponent} from "./app.component"; 11 | import {FooModule} from "./foo/foo.module"; 12 | import {BarModule} from "./bar/bar.module"; 13 | import {routerConfig} from "./router.config"; 14 | 15 | // Enables tracing (check the console) of: 16 | // - TRANSITION transition start, redirect, success, error, ignored 17 | // - VIEWCONFIG ui-view component creation/destruction and viewconfig de/activation 18 | trace.enable(Category.TRANSITION, Category.VIEWCONFIG); 19 | 20 | @NgModule({ 21 | imports: [ 22 | BrowserModule, 23 | UIRouterModule.forRoot({ 24 | states: MAIN_STATES, 25 | otherwise: { state: 'app', params: {} }, 26 | useHash: true, 27 | config: routerConfig, 28 | }), 29 | FooModule, 30 | BarModule, 31 | // BazModule will be lazy loaded 32 | ], 33 | declarations: [ AppComponent ], 34 | providers: [ 35 | // Provide a NgModule lazy loading strategy 36 | { provide: NgModuleFactoryLoader, useClass: SystemJsNgModuleLoader }, 37 | ], 38 | bootstrap: [UIView], 39 | }) 40 | class RootModule {} 41 | 42 | platformBrowserDynamic().bootstrapModule(RootModule); 43 | -------------------------------------------------------------------------------- /src/foo/foo.component.ts: -------------------------------------------------------------------------------- 1 | import {Component} from '@angular/core'; 2 | 3 | /** 4 | * This is a simple component which provides two uiSref (links) to two nested states 5 | * and a viewport for the child states to fill in 6 | */ 7 | let template = ` 8 |

Foo Component

9 | 10 | Nested state 1 11 | Nested state 2 12 | 13 | 14 | `; 15 | 16 | @Component({ 17 | selector: 'foo', 18 | template: template 19 | }) 20 | export class FooComponent { } 21 | -------------------------------------------------------------------------------- /src/foo/foo.module.ts: -------------------------------------------------------------------------------- 1 | import {UIRouterModule} from "@uirouter/angular"; 2 | import {FOO_STATES} from "./foo.states"; 3 | import {SharedModule} from "../shared.module"; 4 | import {NgModule} from "@angular/core"; 5 | import {FooComponent} from "./foo.component"; 6 | import {FooFooterComponent} from "./fooFooter.component"; 7 | import {Nest1Component} from "./nest1.component"; 8 | import {Nest2Component} from "./nest2.component"; 9 | 10 | /** The Foo NgModule */ 11 | @NgModule({ 12 | imports: [ 13 | UIRouterModule.forChild({ states: FOO_STATES }), 14 | SharedModule, 15 | ], 16 | declarations: [ 17 | FooComponent, 18 | FooFooterComponent, 19 | Nest1Component, 20 | Nest2Component, 21 | ] 22 | }) 23 | export class FooModule { } 24 | -------------------------------------------------------------------------------- /src/foo/foo.states.ts: -------------------------------------------------------------------------------- 1 | import {FooComponent} from "./foo.component"; 2 | import {Nest1Component} from "./nest1.component"; 3 | import {Nest2Component} from "./nest2.component"; 4 | import {Ng2StateDeclaration} from "@uirouter/angular"; 5 | import {FooFooterComponent} from "./fooFooter.component"; 6 | /** 7 | * This file defines the states for the `foo` module. 8 | * The states are exported as an array and imported in the FooModule. 9 | */ 10 | export let FOO_STATES: Ng2StateDeclaration[] = [ 11 | // A state for the 'app.foo' submodule, 12 | // It fills the unnamed ($default) (in the AppComponent from the `app` state) with `FooComponent` 13 | { 14 | name: 'app.foo', 15 | url: '/foo', 16 | views: { 17 | $default: {component: FooComponent}, 18 | footer: {component: FooFooterComponent} 19 | } 20 | }, 21 | 22 | // A child state of app.foo; it fills the in app.foo with Nest1Component 23 | { 24 | name: 'app.foo.nest1', 25 | url: '/nest1', 26 | component: Nest1Component 27 | }, 28 | 29 | // A child state of app.foo; it fills the in app.foo with Nest2Component 30 | { 31 | name: 'app.foo.nest2', 32 | url: '/nest2', 33 | component: Nest2Component 34 | } 35 | ]; 36 | 37 | -------------------------------------------------------------------------------- /src/foo/fooFooter.component.ts: -------------------------------------------------------------------------------- 1 | import {Component} from '@angular/core'; 2 | 3 | /** 4 | * This component is shown in the footer when any foo state is active. 5 | */ 6 | @Component({ 7 | styles: ['h4 { border-top: 1px solid black; margin-top: 2em; }'], 8 | selector: 'foo-footer', 9 | template: `

Foo Module Active

` 10 | }) 11 | export class FooFooterComponent { } 12 | -------------------------------------------------------------------------------- /src/foo/nest1.component.ts: -------------------------------------------------------------------------------- 1 | import {Component} from '@angular/core'; 2 | 3 | /** 4 | * This is a simple component used as the component for the app.foo.nest1 state 5 | * to demonstrate grandchildren states 6 | */ 7 | let template = `
Nest 1 component
`; 8 | 9 | @Component({ 10 | selector: 'nest1', 11 | template: template 12 | }) 13 | export class Nest1Component { } 14 | -------------------------------------------------------------------------------- /src/foo/nest2.component.ts: -------------------------------------------------------------------------------- 1 | import {Component} from '@angular/core'; 2 | 3 | /** 4 | * This component demonstrates use of the '#' state parameter, which updates the url hash. 5 | * The '#' parameter is implicitly available. 6 | * 7 | * Note: the parameter value is cleared when clicking a top-level nav link, "Foo", "Bar", "Baz" 8 | * using `{ inherit: false }` 9 | */ 10 | let template = ` 11 |
Nest 2 component
12 | 13 | anchor asdf
14 | anchor fhqwhgads 15 | `; 16 | 17 | @Component({ 18 | selector: 'nest1', 19 | template: template 20 | }) 21 | export class Nest2Component { } 22 | -------------------------------------------------------------------------------- /src/router.config.ts: -------------------------------------------------------------------------------- 1 | import {UIRouter} from "@uirouter/angular"; 2 | import {Injectable} from "@angular/core"; 3 | declare var SystemJS; 4 | 5 | /** 6 | * This function configures the router 7 | */ 8 | export function routerConfig(uiRouter: UIRouter) { 9 | // Show the ui-router visualizer 10 | let vis = window['ui-router-visualizer']; 11 | vis.visualizer(uiRouter); 12 | } 13 | -------------------------------------------------------------------------------- /src/shared.module.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from "@angular/core"; 2 | import {HttpModule} from "@angular/http"; 3 | import {CommonModule} from "@angular/common"; 4 | 5 | /** MyCommon Module: Re-exports BrowserModule and HttpModule */ 6 | @NgModule({ 7 | exports: [CommonModule, HttpModule], 8 | }) 9 | export class SharedModule { } 10 | -------------------------------------------------------------------------------- /styles.css: -------------------------------------------------------------------------------- 1 | /* Master Styles */ 2 | h1 { 3 | color: #369; 4 | font-family: Arial, Helvetica, sans-serif; 5 | font-size: 250%; 6 | } 7 | h2, h3 { 8 | color: #444; 9 | font-family: Arial, Helvetica, sans-serif; 10 | font-weight: lighter; 11 | } 12 | body { 13 | margin: 2em; 14 | } 15 | body, input[text], button { 16 | color: #888; 17 | font-family: Cambria, Georgia; 18 | } 19 | a { 20 | cursor: pointer; 21 | cursor: hand; 22 | color: #0000bc; 23 | text-decoration: none; 24 | } 25 | .active { 26 | font-weight: bolder; 27 | } 28 | button { 29 | font-family: Arial; 30 | background-color: #eee; 31 | border: none; 32 | padding: 5px 10px; 33 | border-radius: 4px; 34 | cursor: pointer; 35 | cursor: hand; 36 | } 37 | button:hover { 38 | background-color: #cfd8dc; 39 | } 40 | button:disabled { 41 | background-color: #eee; 42 | color: #aaa; 43 | cursor: auto; 44 | } 45 | 46 | /* Navigation link styles */ 47 | nav a { 48 | padding: 5px 10px; 49 | text-decoration: none; 50 | margin-top: 10px; 51 | display: inline-block; 52 | background-color: #eee; 53 | border-radius: 4px; 54 | } 55 | nav a:visited, a:link { 56 | color: #607D8B; 57 | } 58 | nav a:hover { 59 | color: #039be5; 60 | background-color: #CFD8DC; 61 | } 62 | nav a.router-link-active { 63 | color: #039be5; 64 | } 65 | 66 | /* items class */ 67 | .items { 68 | margin: 0 0 2em 0; 69 | list-style-type: none; 70 | padding: 0; 71 | width: 24em; 72 | } 73 | .items li { 74 | cursor: pointer; 75 | position: relative; 76 | left: 0; 77 | background-color: #EEE; 78 | margin: .5em; 79 | padding: .3em 0; 80 | height: 1.6em; 81 | border-radius: 4px; 82 | } 83 | .items li:hover { 84 | color: #607D8B; 85 | background-color: #DDD; 86 | left: .1em; 87 | } 88 | .items li.selected:hover { 89 | background-color: #BBD8DC; 90 | color: white; 91 | } 92 | .items .text { 93 | position: relative; 94 | top: -3px; 95 | } 96 | .items { 97 | margin: 0 0 2em 0; 98 | list-style-type: none; 99 | padding: 0; 100 | width: 24em; 101 | } 102 | .items li { 103 | cursor: pointer; 104 | position: relative; 105 | left: 0; 106 | background-color: #EEE; 107 | margin: .5em; 108 | padding: .3em 0; 109 | height: 1.6em; 110 | border-radius: 4px; 111 | } 112 | .items li:hover { 113 | color: #607D8B; 114 | background-color: #DDD; 115 | left: .1em; 116 | } 117 | .items li.selected { 118 | background-color: #CFD8DC; 119 | color: white; 120 | } 121 | 122 | .items li.selected:hover { 123 | background-color: #BBD8DC; 124 | } 125 | .items .text { 126 | position: relative; 127 | top: -3px; 128 | } 129 | .items .badge { 130 | display: inline-block; 131 | font-size: small; 132 | color: white; 133 | padding: 0.8em 0.7em 0 0.7em; 134 | background-color: #607D8B; 135 | line-height: 1em; 136 | position: relative; 137 | left: -1px; 138 | top: -4px; 139 | height: 1.8em; 140 | margin-right: .8em; 141 | border-radius: 4px 0 0 4px; 142 | } 143 | 144 | /* everywhere else */ 145 | * { 146 | font-family: Arial, Helvetica, sans-serif; 147 | } 148 | -------------------------------------------------------------------------------- /systemjs.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * System configuration for Angular 2 samples 3 | * Adjust as necessary for your application needs. 4 | * Override at the last minute with global.filterSystemConfig (as plunkers do) 5 | */ 6 | (function(global) { 7 | 8 | // map tells the System loader where to look for things 9 | var map = { 10 | 'quickstart': 'src', 11 | '@uirouter/angular': 'node_modules/@uirouter/angular/_bundles/ui-router-ng2.js', 12 | '@uirouter/core': 'node_modules/@uirouter/core/lib', 13 | 'rxjs': 'node_modules/rxjs', 14 | 'angular2-in-memory-web-api': 'node_modules/angular2-in-memory-web-api', 15 | '@angular': 'node_modules/@angular' 16 | }; 17 | 18 | // packages tells the System loader how to load when no filename and/or no extension 19 | var packages = { 20 | 'quickstart': { main: 'bootstrap.js', defaultExtension: 'js' }, 21 | 'rxjs': { defaultExtension: 'js' }, 22 | 'angular2-in-memory-web-api': { defaultExtension: 'js' }, 23 | '@uirouter/core': { main: 'index.js', defaultExtension: 'js' }, 24 | }; 25 | 26 | var ngPackageNames = [ 27 | 'common', 28 | 'compiler', 29 | 'core', 30 | 'forms', 31 | 'http', 32 | 'platform-browser', 33 | 'platform-browser-dynamic', 34 | 'router', 35 | 'router-deprecated', 36 | 'testing', 37 | 'upgrade' 38 | ]; 39 | 40 | // Individual files (~300 requests): 41 | function packIndex(pkgName) { 42 | packages['@angular/'+pkgName] = { main: 'index.js', defaultExtension: 'js' }; 43 | } 44 | // Bundled (~40 requests): 45 | function packUmd(pkgName) { 46 | packages['@angular/'+pkgName] = { main: 'bundles/' + pkgName + '.umd.js', defaultExtension: 'js' }; 47 | } 48 | // Most environments should use UMD; some (Karma) need the individual index files 49 | var setPackageConfig = System.packageWithIndex ? packIndex : packUmd; 50 | // Add package entries for angular packages 51 | ngPackageNames.forEach(setPackageConfig); 52 | 53 | 54 | var config = { 55 | transpiler: false, 56 | meta: { "ui-router-ng2": { format: "cjs" } }, 57 | map: map, 58 | packages: packages 59 | }; 60 | 61 | System.config(config); 62 | 63 | })(this); 64 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "commonjs", 5 | "moduleResolution": "node", 6 | "sourceMap": true, 7 | "emitDecoratorMetadata": true, 8 | "experimentalDecorators": true, 9 | "removeComments": false, 10 | "suppressImplicitAnyIndexErrors": true, 11 | "noImplicitAny": false, 12 | "lib": [ "es6", "dom" ] 13 | }, 14 | "include": ["src/bootstrap.ts", "src/baz/baz.module.ts"] 15 | } 16 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "class-name": true, 4 | "comment-format": [ 5 | true, 6 | "check-space" 7 | ], 8 | "curly": true, 9 | "eofline": true, 10 | "forin": true, 11 | "indent": [ 12 | true, 13 | "spaces" 14 | ], 15 | "label-position": true, 16 | "label-undefined": true, 17 | "max-line-length": [ 18 | true, 19 | 140 20 | ], 21 | "member-access": false, 22 | "member-ordering": [ 23 | true, 24 | "static-before-instance", 25 | "variables-before-functions" 26 | ], 27 | "no-arg": true, 28 | "no-bitwise": true, 29 | "no-console": [ 30 | true, 31 | "debug", 32 | "info", 33 | "time", 34 | "timeEnd", 35 | "trace" 36 | ], 37 | "no-construct": true, 38 | "no-debugger": true, 39 | "no-duplicate-key": true, 40 | "no-duplicate-variable": true, 41 | "no-empty": false, 42 | "no-eval": true, 43 | "no-inferrable-types": true, 44 | "no-shadowed-variable": true, 45 | "no-string-literal": false, 46 | "no-switch-case-fall-through": true, 47 | "no-trailing-whitespace": true, 48 | "no-unused-expression": true, 49 | "no-unused-variable": true, 50 | "no-unreachable": true, 51 | "no-use-before-declare": true, 52 | "no-var-keyword": true, 53 | "object-literal-sort-keys": false, 54 | "one-line": [ 55 | true, 56 | "check-open-brace", 57 | "check-catch", 58 | "check-else", 59 | "check-whitespace" 60 | ], 61 | "quotemark": [ 62 | true, 63 | "single" 64 | ], 65 | "radix": true, 66 | "semicolon": [ 67 | "always" 68 | ], 69 | "triple-equals": [ 70 | true, 71 | "allow-null-check" 72 | ], 73 | "typedef-whitespace": [ 74 | true, 75 | { 76 | "call-signature": "nospace", 77 | "index-signature": "nospace", 78 | "parameter": "nospace", 79 | "property-declaration": "nospace", 80 | "variable-declaration": "nospace" 81 | } 82 | ], 83 | "variable-name": false, 84 | "whitespace": [ 85 | true, 86 | "check-branch", 87 | "check-decl", 88 | "check-operator", 89 | "check-separator", 90 | "check-type" 91 | ] 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /wallaby.js: -------------------------------------------------------------------------------- 1 | // Configuration for the Wallaby Visual Studio Code testing extension 2 | // https://marketplace.visualstudio.com/items?itemName=WallabyJs.wallaby-vscode 3 | // Note: Wallaby is not open source and costs money 4 | module.exports = function () { 5 | 6 | return { 7 | files: [ 8 | // System.js for module loading 9 | {pattern: 'node_modules/systemjs/dist/system-polyfills.js', instrument: false}, 10 | {pattern: 'node_modules/systemjs/dist/system.js', instrument: false}, 11 | 12 | // Polyfills 13 | {pattern: 'node_modules/es6-shim/es6-shim.js', instrument: false}, 14 | {pattern: 'node_modules/angular2/bundles/angular2-polyfills.js', instrument: false}, 15 | 16 | // Zone.js dependencies 17 | // Note - do not include zone.js itself or long-stack-trace-zone.js` here as 18 | // they are included already in angular2-polyfills 19 | {pattern: 'node_modules/zone.js/dist/jasmine-patch.js', instrument: false}, 20 | {pattern: 'node_modules/zone.js/dist/async-test.js', instrument: false}, 21 | {pattern: 'node_modules/zone.js/dist/fake-async-test.js', instrument: false}, 22 | 23 | // Rx.js, Angular 2 itself, and the testing library not here because loaded by systemjs 24 | 25 | {pattern: 'app/**/*+(ts|html|css)', load: false}, 26 | {pattern: 'app/**/*.spec.ts', ignore: true} 27 | ], 28 | 29 | tests: [ 30 | {pattern: 'app/**/*.spec.ts', load: false} 31 | ], 32 | 33 | middleware: function (app, express) { 34 | app.use('/node_modules', express.static(require('path').join(__dirname, 'node_modules'))); 35 | }, 36 | 37 | testFramework: 'jasmine', 38 | 39 | bootstrap: function (wallaby) { 40 | wallaby.delayStart(); 41 | 42 | System.config({ 43 | defaultJSExtensions: true, 44 | packages: { 45 | app: { 46 | meta: { 47 | '*': { 48 | scriptLoad: true 49 | } 50 | } 51 | } 52 | }, 53 | paths: { 54 | 'npm:*': 'node_modules/*' 55 | }, 56 | map: { 57 | 'angular2': 'npm:angular2', 58 | 'rxjs': 'npm:rxjs' 59 | } 60 | }); 61 | 62 | // Configure Angular for the browser and 63 | // with test versions of the platform providers 64 | Promise.all([ 65 | System.import('angular2/testing'), 66 | System.import('angular2/platform/testing/browser') 67 | ]) 68 | .then(function (results) { 69 | var testing = results[0]; 70 | var browser = results[1]; 71 | testing.setBaseTestProviders( 72 | browser.TEST_BROWSER_PLATFORM_PROVIDERS, 73 | browser.TEST_BROWSER_APPLICATION_PROVIDERS); 74 | 75 | // Load all spec files 76 | return Promise.all(wallaby.tests.map(function (specFile) { 77 | return System.import(specFile); 78 | })); 79 | }) 80 | .then(function () { 81 | wallaby.start(); 82 | }) 83 | .catch(function (e) { 84 | setTimeout(function () { 85 | throw e; 86 | }, 0); 87 | }); 88 | }, 89 | 90 | debug: true 91 | }; 92 | }; 93 | --------------------------------------------------------------------------------